1、访问java(私有)变量
逆向步骤:
1)最后通过调用env->Get{type}Field(jobject, fieldId)
得到该变量的值。其中{type} 是变量的类型;如果变量是静态 static 的,则调用的方法是GetStatic{type}Field(jclass, fieldId)
,注意 static 的话, 是使用 jclass 作为参数;
2)调用env->GetFieldID(jclazz, fieldName, signature)
得到该实例域(变量)的 id,即 jfieldID;如果变量是静态 static 的,则调用的方法为 GetStaticFieldID
3)通过env->GetObjectClass(jobject)
获取Java 对象的 class 类,返回一个 jclass;
public class JniPractise {
static {
System.loadLibrary("ndksample");
}
// 用public也可以
private int num = 10;
public native int nativeNum();
}
jint jin_nativeNum(JNIEnv *env, jobject obj) {
jclass jclazz = env->GetObjectClass(obj);
jfieldID jfieldId = env->GetFieldID(jclazz, "num", "I");
int num = env->GetIntField(obj, jfieldId);
++num;
return num;
}
2、访问java静态变量
public static String hello= "hello ";
public static native void nativeHello(String str);
注意:jclass代替了jobject;使用GetStaticFieldID而不是GetFieldID;jsting不能像String一样直接拼接字符串,而是转成const char *,再用strcat()函数拼接2个char *。
void jni_nativeHello(JNIEnv *env, jclass jclazz, jstring param) {
jfieldID jfieldId = env->GetStaticFieldID(jclazz, "hello", "Ljava/lang/String;");
jstring hello = (jstring) env->GetStaticObjectField(jclazz, jfieldId);
char *char_hello = const_cast<char *>(env->GetStringUTFChars(hello, JNI_FALSE));
const char *char_param = env->GetStringUTFChars(param, JNI_FALSE);
strcat(char_hello, char_param);
jstring newString = env->NewStringUTF(char_hello);
env->SetStaticObjectField(jclazz, jfieldId, newString);
}
3、调用java(私有)方法
逆向步骤:
1)通过 JNI 函数env->Call{type}Method(jobject, jmethod, param...)
实现调用 Java的方法;若调用的是 static 方法,则使用CallStatic{type}Method(jclass, jmethod, param...)
,使用的是 jclass
2)通过env->GetMethodID(jclass, methodName, sign)
获取到 Java 对象的方法 Id,即 jmethodID,当获取的方法是 static 的时,使用GetStaticMethodID
;
3)通过env->GetObjectClass(jobject)
获取Java 对象的 class 类,返回一个 jclass;
// 用private也行
public void setNum(int num) {
this.num = num;
}
public native void accessPublicMethod();
cpp代码:
void jni_accessPublicMethod(JNIEnv *env, jobject obj) {
jclass jclazz = env->GetObjectClass(obj);
jmethodID jmethodId = env->GetMethodID(jclazz,"setNum","(I)V");
env->CallVoidMethod(obj,jmethodId,13456);
}
4、调用java静态方法
public static String getUUID(){
return UUID.randomUUID().toString();
}
public static native String accessPublicStaticMethod();
cpp代码;
jstring jni_accessPublicStaticMethod(JNIEnv *env, jclass jclazz) {
jmethodID jmethodId = env->GetStaticMethodID(jclazz, "getUUID", "()Ljava/lang/String;");
return (jstring) env->CallStaticObjectMethod(jclazz, jmethodId);
}
5、调用父类的方法
public class Parent {
public int age(){
return 50;
}
}
public class JniPractise extends Parent{
@Override
public int age() {
return 18;
}
public native int accessSuperMethod();
}
cpp代码:
jint jni_accessSuperMethod(JNIEnv *env, jobject obj) {
jclass jclazz = env->FindClass("com/dawn/ndksample/Parent");
if (!jclazz) {
return -1;
}
jmethodID jmethodId = env->GetMethodID(jclazz, "age", "()I");
return env->CallNonvirtualIntMethod(obj, jclazz, jmethodId);
}
注意两点不同的地方,
- 获取的是父类的方法,所以不能通过GetObjectClass获取,需要通过反射 FindClass 获取;
- 调用父类的方法是 CallNonvirtual{type}Method 函数。Nonvirtual是非虚拟函数
6、jni创建java对象
public class Student {
public Student(String name) {
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class JniPractise {
public native Student createStudent();
}
jobject jni_createStudent(JNIEnv *env, jobject obj) {
jclass jclazz = env->FindClass("com/dawn/ndksample/Student");
if(jclazz == NULL) {
return env->NewStringUTF("cannot find class");
}
jmethodID jmethodId = env->GetMethodID(jclazz,"<init>","(Ljava/lang/String;)V");
jstring str = env->NewStringUTF("Tony Ya");
return env->NewObject(jclazz,jmethodId,str);
}
注意3个点:
- Student只能通过findClass()获取;
- 构造方法的方法名是<init>,返回值是V,而不是java中定义的Student。
- 动态注册时,方式映射表的第二个参数,即方法签名中的返回值类型是:Lcom/dawn/ndksample/Student;
7、jni动态注册
static const JNINativeMethod nativeMethod[] = {
{"nativeNum", "()I", (void *) jni_nativeNum},
{"nativeHello", "(Ljava/lang/String;)V", (void *) jni_nativeHello},
{"accessPublicMethod", "()V", (void *) jni_accessPublicMethod},
{"accessPublicStaticMethod", "()Ljava/lang/String;", (void *) jni_accessPublicStaticMethod},
{"accessSuperMethod", "()I", (void *) jni_accessSuperMethod},
{"createStudent", "()Lcom/dawn/ndksample/Student;", (void *) jni_createStudent}
};
static int registNativeMethod(JNIEnv *env) {
int result = -1;
jclass class_text = env->FindClass("com/dawn/ndksample/JniPractise");
if (env->RegisterNatives(class_text, nativeMethod,
sizeof(nativeMethod) / sizeof(nativeMethod[0])) == JNI_OK) {
result = 0;
}
return result;
}
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
int result = -1;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_1) == JNI_OK) {
if (registNativeMethod(env) == JNI_OK) {
result = JNI_VERSION_1_6;
}
return result;
}
}
8、调试代码
private void test(){
JniPractise jniPractise = new JniPractise();
int result =jniPractise.nativeNum();
Log.d("@@","nativeNum :"+result);
}
private void test2(){
JniPractise.nativeHello("word");
Log.d("@@","nativeHello :"+JniPractise.hello);
}
private void test3(){
JniPractise jniPractise = new JniPractise();
jniPractise.accessPublicMethod();
int result =jniPractise.getNum();
Log.d("@@","accessPublicMethod :"+result);
}
private void test4(){
Log.d("@@","staticMethod :"+JniPractise.accessPublicStaticMethod());
}
private void test5(){
JniPractise jniPractise = new JniPractise();
Log.d("@@","superMethod :"+jniPractise.accessSuperMethod());
}
private void test6(){
JniPractise jniPractise = new JniPractise();
Student student = jniPractise.createStudent();
Log.d("@@","createStudent name :"+student.getName());
}
🎉,谢谢大家的阅读。