美文网首页Android ndk 开发NDK
NDK 开发中 Native 与 Java 交互

NDK 开发中 Native 与 Java 交互

作者: 字节流动 | 来源:发表于2019-01-27 15:30 被阅读0次
    人生远比我们想象得漫长,所以不争一城一池的得失,要把一切机会和挫折都放到尽可能长的周期里来思考。

    本博客 NDK 开发系列文章:

    Java 与 JNI 数据类型对应关系

    Java 数据类型 JNI 数据类型
    boolean jboolean
    byte jbyte
    char jchar
    short jshort
    int jint
    long jlong
    float jfloat
    double jdouble
    String jstring
    Object jobject
    byte[] jbyteArray
    Object[] jobjectArray

    Native 中的签名

    NDK 开发中会用到 Java 对象的属性签名和方法签名,用于区分不同的属性和方法。

    属性签名

    属性的签名就是属性类型的简称。
    属性类型与其签名的对应关系如下:

    属性类型 类型签名
    boolean Z
    byte B
    char C
    short S
    int I
    long L
    float F
    double D
    void V
    String Ljava/lang/String;
    Object 以 L 开头,后加完整的包名,并以分号结束
    byte[] [B
    Object[] 以 [ 开头,后加对象类型签名,例如 String[] 对应 [Ljava/lang/String;

    方法签名

    方法签名格式:
    (参数类型签名)返回值类型签名

    那么如何获取方法签名?
    执行命令 javah <class 文件的全名>
    javah com.haohao.hellojni.NativeTest.class 生成 com_haohao_hellojni_NativeTest.h 文件,文件中便标出了方法的 Signature 。

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_haohao_hellojni_NativeTest */
    
    #ifndef _Included_com_haohao_hellojni_NativeTest
    #define _Included_com_haohao_hellojni_NativeTest
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_haohao_hellojni_NativeTest
     * Method:    getString
     * Signature: ()Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_haohao_hellojni_NativeTest_getString__
      (JNIEnv *, jobject);
    
    /*
     * Class:     com_haohao_hellojni_NativeTest
     * Method:    getString
     * Signature: (Ljava/lang/String;)Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_haohao_hellojni_NativeTest_getString__Ljava_lang_String_2
      (JNIEnv *, jobject, jstring);
    
    /*
     * Class:     com_haohao_hellojni_NativeTest
     * Method:    getInt
     * Signature: ()I
     */
    JNIEXPORT jint JNICALL Java_com_haohao_hellojni_NativeTest_getInt__
      (JNIEnv *, jobject);
    
    /*
     * Class:     com_haohao_hellojni_NativeTest
     * Method:    getInt
     * Signature: (I)I
     */
    JNIEXPORT jint JNICALL Java_com_haohao_hellojni_NativeTest_getInt__I
      (JNIEnv *, jobject, jint);
    
    /*
     * Class:     com_haohao_hellojni_NativeTest
     * Method:    input
     * Signature: (Ljava/lang/String;I)V
     */
    JNIEXPORT void JNICALL Java_com_haohao_hellojni_NativeTest_input__Ljava_lang_String_2I
      (JNIEnv *, jobject, jstring, jint);
    
    /*
     * Class:     com_haohao_hellojni_NativeTest
     * Method:    input
     * Signature: ([Ljava/lang/String;I)V
     */
    JNIEXPORT void JNICALL Java_com_haohao_hellojni_NativeTest_input___3Ljava_lang_String_2I
      (JNIEnv *, jobject, jobjectArray, jint);
    
    /*
     * Class:     com_haohao_hellojni_NativeTest
     * Method:    getBytes
     * Signature: ([Ljava/lang/String;Ljava/lang/String;)[B
     */
    JNIEXPORT jbyteArray JNICALL Java_com_haohao_hellojni_NativeTest_getBytes
      (JNIEnv *, jobject, jobjectArray, jstring);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    
    

    Native 与 Java 交互

    设置一个简单的类 NativeUtils.java 用于测试,Native 与 Java 交互的实现类似于 Java 的反射机制。

    package com.haohao.hellojni;
    
    import android.util.Log;
    
    /**
     * author: haohao
     * time: 2018/1/1
     * mail: haohaochang86@gmail.com
     * desc: description
     */
    public class NativeUtils {
    
        static {
            System.loadLibrary("native-utils");
        }
    
        private static final String TAG = "NativeUtils";
        public static int staticProp = -1;
        public int prop = -1;
    
    
        public String getStringFromJava(String str){
            Log.i(TAG, "getStringFromJava: "+ str);
            return "Hello C , I am from Java.";
        }
    
        public static String getStringFromJavaStatic(String str){
            Log.i(TAG, "getStringFromJavaStatic: " + str);
            return "Hello C , I am from Java static.";
        }
    
        public native void accessJavaClassProp();
    
        public native void callJavaClassMethod();
    
        public static native void accessStaticJavaProp();
    
        public static native void callStaticJavaMethod();
    
    }
    

    访问 Java 对象的非静态属性

    JNIEXPORT void JNICALL
    Java_com_haohao_hellojni_NativeUtils_accessJavaClassProp(JNIEnv *env, jobject instance) {
        //访问 Java 对象的非静态属性
    
        //通过 JNIEnv 和对象 instance 实例拿到 class 。
        jclass cls = (*env)->GetObjectClass(env, instance);
        //获取属性的 field id
        jfieldID fid = (*env)->GetFieldID(env, cls, "prop", "I");
        //通过 field id 获取属性的值
        jint prop = (*env)->GetIntField(env, instance, fid);
        //在 Native 层修改属性
        prop += 101;
        (*env)->SetIntField(env, instance, fid, prop);
    
    }
    

    调用 Java 对象的非静态方法

    JNIEXPORT void JNICALL
    Java_com_haohao_hellojni_NativeUtils_callJavaClassMethod(JNIEnv *env, jobject instance) {
        //调用 Java 对象的非静态方法
    
        jclass myClass = (*env)->GetObjectClass(env, instance);
        //获取发方法的 method id
        jmethodID mid = (*env)->GetMethodID(env, myClass, "getStringFromJava", "(Ljava/lang/String;)Ljava/lang/String;");
        //调用 Java 对象的方法
        jstring  jstr = (*env)->CallObjectMethod(env, instance, mid, (*env)->NewStringUTF(env, "Hello Java, I am From C."));
        //jstring 转换为 c 的字符串
        const char* cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
        LOGD("%s", cstr);
        //注意区别对待 Java 字符串和 C 的字符串,除了基本数据类型之外,其他都需要进行类型转换
        //释放资源
        (*env)->ReleaseStringUTFChars(env, jstr, cstr);
    
    }
    

    访问 Java 对象的静态属性

    JNIEXPORT void JNICALL
    Java_com_haohao_hellojni_NativeUtils_accessStaticJavaProp(JNIEnv *env, jclass type) {
        //访问 Java 对象的静态属性,
    
        jfieldID fid = (*env)->GetStaticFieldID(env, type, "staticProp", "I");
        jint staticProp = (*env)->GetStaticIntField(env, type, fid);
        staticProp += 101;
        (*env)->SetStaticIntField(env, type, fid, staticProp);
    
    }
    

    调用 Java 对象的静态方法

    JNIEXPORT void JNICALL
    Java_com_haohao_hellojni_NativeUtils_callStaticJavaMethod(JNIEnv *env, jclass type) {
        //调用 Java 对象的静态方法
    
        jmethodID mid = (*env)->GetStaticMethodID(env, type, "getStringFromJavaStatic", "(Ljava/lang/String;)Ljava/lang/String;");
        jstring jstr = (*env)->CallStaticObjectMethod(env, type, mid, (*env)->NewStringUTF(env, "Hello Java, I am From C."));
        const char* cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
        LOGD("%s", cstr);
    
        //释放资源
        (*env)->ReleaseStringUTFChars(env, jstr, cstr);
    }
    

    测试

    nativeUtils = new NativeUtils();
    Log.i(TAG, "old prop : " + nativeUtils.prop);
    nativeUtils.accessJavaClassProp();
    Log.i(TAG, "new prop : " + nativeUtils.prop);
    Log.i(TAG, "old static prop : " + NativeUtils.staticProp);
    NativeUtils.accessStaticJavaProp();
    Log.i(TAG, "new static prop : " + NativeUtils.staticProp);
    nativeUtils.callJavaClassMethod();
    NativeUtils.callStaticJavaMethod();
    

    native-utils.c 完整代码

    //
    // Created by haohao on 2018/1/1.
    //
    
    #include <jni.h>
    #include <android/log.h>
    
    #define TAG "native-utils"
    #define LOGD(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGD类型
    
    JNIEXPORT void JNICALL
    Java_com_haohao_hellojni_NativeUtils_accessJavaClassProp(JNIEnv *env, jobject instance) {
        //访问 Java 对象的非静态属性
    
        //通过 JNIEnv 和对象 instance 实例拿到 class 。
        jclass cls = (*env)->GetObjectClass(env, instance);
        //获取属性的 field id
        jfieldID fid = (*env)->GetFieldID(env, cls, "prop", "I");
        //通过 field id 获取属性的值
        jint prop = (*env)->GetIntField(env, instance, fid);
        //在 Native 层修改属性
        prop += 101;
        (*env)->SetIntField(env, instance, fid, prop);
    
    }
    
    JNIEXPORT void JNICALL
    Java_com_haohao_hellojni_NativeUtils_callJavaClassMethod(JNIEnv *env, jobject instance) {
        //调用 Java 对象的非静态方法
    
        jclass myClass = (*env)->GetObjectClass(env, instance);
        //获取发方法的 method id
        jmethodID mid = (*env)->GetMethodID(env, myClass, "getStringFromJava", "(Ljava/lang/String;)Ljava/lang/String;");
        //调用 Java 对象的方法
        jstring  jstr = (*env)->CallObjectMethod(env, instance, mid, (*env)->NewStringUTF(env, "Hello Java, I am From C."));
        //jstring 转换为 c 的字符串
        const char* cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
        LOGD("%s", cstr);
        //注意区别对待 Java 字符串和 C 的字符串,除了基本数据类型之外,其他都需要进行类型转换
        //释放资源
        (*env)->ReleaseStringUTFChars(env, jstr, cstr);
    
    }
    
    JNIEXPORT void JNICALL
    Java_com_haohao_hellojni_NativeUtils_accessStaticJavaProp(JNIEnv *env, jclass type) {
        //访问 Java 对象的静态属性,
    
        jfieldID fid = (*env)->GetStaticFieldID(env, type, "staticProp", "I");
        jint staticProp = (*env)->GetStaticIntField(env, type, fid);
        staticProp += 101;
        (*env)->SetStaticIntField(env, type, fid, staticProp);
    
    }
    
    JNIEXPORT void JNICALL
    Java_com_haohao_hellojni_NativeUtils_callStaticJavaMethod(JNIEnv *env, jclass type) {
        //调用 Java 对象的静态方法
    
        jmethodID mid = (*env)->GetStaticMethodID(env, type, "getStringFromJavaStatic", "(Ljava/lang/String;)Ljava/lang/String;");
        jstring jstr = (*env)->CallStaticObjectMethod(env, type, mid, (*env)->NewStringUTF(env, "Hello Java, I am From C."));
        const char* cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
        LOGD("%s", cstr);
    
        //释放资源
        (*env)->ReleaseStringUTFChars(env, jstr, cstr);
    }
    

    结果

    I/MainActivity: old prop : -1
    I/MainActivity: new prop : 100
    I/MainActivity: old static prop : -1
    I/MainActivity: new static prop : 100
    I/NativeUtils: getStringFromJava: Hello Java, I am From C.
    I/native-utils: Hello C , I am from Java.
    I/NativeUtils: getStringFromJavaStatic: Hello Java, I am From C.
    I/native-utils: Hello C , I am from Java static.
    

    相关文章

      网友评论

        本文标题:NDK 开发中 Native 与 Java 交互

        本文链接:https://www.haomeiwen.com/subject/fuggjqtx.html