Android NDK学习:native 通过JNI调用java的属性跟方法

native调用Java的普通属性

  • Java 代码
public class JniUtils {
    static{
        System.loadLibrary("JNIEnvOne");
    }
    public String name = "liu";
    //访问普通属性
    public native void modifField();
}
  • C 代码
//调用普通属性
JNIEXPORT void JNICALL Java_com_liu_JniUtils_modifField
(JNIEnv * env, jobject obj){
    //获取类
    jclass jclazz = (*env)->GetObjectClass(env, obj);
    //获取属性,属性签名
    jfieldID field = (*env)->GetFieldID(env, jclazz, "name", "Ljava/lang/String;");
    //拿到属性的值(JNI的)
    //get<Type>Field 模式,不同的类型
    jstring jojb = (*env)->GetObjectField(env, obj, field);
    //转成c的字符串
    //isCopy 是否赋值的意思。
    jboolean isCopy = NULL;
    char* c_str = (*env)->GetStringChars(env, jojb, &isCopy);
    if (isCopy){
        printf("%s\n", "this str is copy");
    }
    char* mid = "I am from C";
    //拼接C的字符串
    strcat(c_str, mid);

    //set<Type>Field 模式
    (*env)->SetObjectField(env, obj, field, (*env)->NewStringUTF(env, c_str));
    //释放
    (*env)->ReleaseStringChars(env, jojb, c_str);

}

调用步骤:
- 获取类。 (*env)->GetObjectClass(env, obj);
- 获取属性签名。(*env)->GetFieldID(env, jclazz, “name”, “Ljava/lang/String;”);
- 拿到属性的值。(*env)->GetObjectField(env, obj, field);
- 把值转换成C可操作的类型。(*env)->GetStringChars(env, jojb, &isCopy);
- 操作属性的值。strcat(c_str, mid)/重新赋值等等
- 转换成JNI需要的类型。((*env)->NewStringUTF(env, c_str))
- 设置到属性里面。SetObjectField
- 把创建的字符串释放。(*env)->ReleaseStringChars(env, jojb, c_str);

native调用Java的静态属性

  • Java 代码
public class JniUtils {
    static{
        System.loadLibrary("JNIEnvOne");
    }
    public static String staticName = "liu";
    //访问静态属性
    public native void modifStaticField();
}
  • C 代码
//获取静态属性
JNIEXPORT void JNICALL Java_com_liu_JniUtils_modifStaticField
(JNIEnv * env, jobject obj){
    //先获取jclass
    jclass cls = (*env)->GetObjectClass(env, obj);
    //获取属性签名
    jfieldID fid = (*env)->GetStaticFieldID(env, cls, "staticName", "Ljava/lang/String;");
    //获取属性
    jstring field = (*env)->GetStaticObjectField(env, cls, fid);

    //转换成c的类型
    char* str = (*env)->GetStringChars(env, field, NULL);

    char* s = "static str";

    strcat(s, str);

    jstring result = (*env)->NewStringUTF(env, s);
    (*env)->SetStaticObjectField(env, cls, fid, result);

    (*env)->ReleaseStringChars(env, field, str);

}

步骤:
- 获取类
- 获取属性签名
- 获取属性
- 转换成C可操作的类型
- 操作值
- 转换成JNI需要的类型
- 设置属性
- 释放资源

native调用Java的普通方法

  • Java代码
public class JniUtils {
    static{
        System.loadLibrary("JNIEnvOne");
    }
    //访问普通方法
    public native void callMethod(int count);
    public void normalMethod(int count){
        System.out.println("普通方法被调用了。count:"+count);
    }
}
  • C 代码
//调用普通方法
JNIEXPORT void JNICALL Java_com_liu_JniUtils_callMethod
(JNIEnv * env, jobject obj,jint count){
    //获取类
    jclass cls = (*env)->GetObjectClass(env, obj);
    //获取方法签名
    jmethodID mid = (*env)->GetMethodID(env, cls, "normalMethod", "(I)V");
    //调用方法
    (*env)->CallObjectMethod(env, obj, mid, count);
}

步骤:
- 获取类
- 获取方法签名
- 调用方法

native调用Java的静态方法

  • Java 代码
public class JniUtils {
    static{
        System.loadLibrary("JNIEnvOne");
    }
    //访问静态方法
    public native void callStaticMethod();
    public static void staticMethod(){
        System.out.println("static 方法被调用了。count:");
    }
}
  • C 代码

//调用静态方法
JNIEXPORT void JNICALL Java_com_liu_JniUtils_callStaticMethod
(JNIEnv * env, jobject obj, jint count){
    //获取类
    jclass cls = (*env)->GetObjectClass(env, obj);
    //获取方法签名
    jmethodID mid = (*env)->GetStaticMethodID(env, cls, "staticMethod", "()V");
    //调用方法
    (*env)->CallStaticVoidMethod(env, cls, mid);
}

Java层调用native,返回乱码问题及调用构造方法

  • Java 代码
public class JniUtils {
    static{
        System.loadLibrary("JNIEnvOne");
    }
    //访问构造方法
    public native void callConstructMethod();
    public String name = "liu";
}
  • C 代码

//解决字符串的乱码问题,及访问类的构造器
//通过new String(byte[],charset)。转换编码来解决乱码问题
jstring conv_str_to_java(JNIEnv* env, char* str){
    //先找到类
    jclass cls = (*env)->FindClass(env, "java/lang/String");
    //获取构造器的方法签名
    jmethodID mid = (*env)->GetMethodID(env, cls, "<init>", "([BLjava/lang/String;)V");
    //需要转换的字符串长度
    int arr_len = strlen(str);
    //jbyte-char。初始化一个同等长度的字符数组
    jbyteArray arr = (*env)->NewByteArray(env, arr_len);
    //str数组赋值到jbytArray
    (*env)->SetByteArrayRegion(env, arr, 0, arr_len, str);

    //把需要的编码,转换成JNI需要的类型
    jstring charsetName = (*env)->NewStringUTF(env, "GB2312");
    //调用String的构造方法,初始化String类
    jstring result = (*env)->NewObject(env, cls, mid, arr, charsetName);

    return result;
}

//调用普通属性
JNIEXPORT void JNICALL Java_com_liu_JniUtils_callConstructMethod
(JNIEnv * env, jobject obj){
    //获取类
    jclass jclazz = (*env)->GetObjectClass(env, obj);
    //获取属性,属性签名
    jfieldID field = (*env)->GetFieldID(env, jclazz, "name", "Ljava/lang/String;");
    //拿到属性的值(JNI的)
    //get<Type>Field 模式,不同的类型
    jstring jojb = (*env)->GetObjectField(env, obj, field);
    //转成c的字符串
    char* c_str = (*env)->GetStringChars(env, jojb,NULL);
    char* mid = "我是C的字符串";
    //拼接C的字符串
    strcat(c_str, mid);

    //set<Type>Field 模式
    //这样是有乱码的
    //(*env)->SetObjectField(env, obj, field, (*env)->NewStringUTF(env, c_str));

    //通过上面的函数转换后,就没有乱码了
    (*env)->SetObjectField(env, obj, field, conv_str_to_java(env,c_str));
    //释放
    (*env)->ReleaseStringChars(env, jojb, c_str);


}

native调用Java的普通的类的方法

  • Java 代码
public class JniUtils {
    static{
        System.loadLibrary("JNIEnvOne");
    }
    //访问普通类的普通方法
    public native long callNormalClassMethod();
}
  • C 代码
//访问普通类的方法
JNIEXPORT jlong JNICALL Java_com_liu_JniUtils_callNormalClassMethod
(JNIEnv * env, jobject obj){
    //找到类
    jclass cls = (*env)->FindClass(env, "java/util/Date");
    //获取构造方法的签名
    jmethodID construct_id = (*env)->GetMethodID(env, cls, "<init>", "()V");
    //初始化 类
    jobject date_obj = (*env)->NewObject(env, cls,construct_id);
    //获取方法的签名
    jmethodID mid = (*env)->GetMethodID(env, cls, "getTime", "()J");

    //访问方法
    jlong t = (*env)->CallLongMethod(env, date_obj, mid);
    return t;
}

查看类属性和方法的签名

  • cd native方法生成的类的文件夹下
  • 执行javap -s -p xx.xx.JniUtils

猜你喜欢

转载自blog.csdn.net/ecliujianbo/article/details/79902570