美文网首页
jni新手笔记四:jni数据类型

jni新手笔记四:jni数据类型

作者: DON_1007 | 来源:发表于2019-03-21 19:01 被阅读0次

    基础类型

    java类型 jni类型 签名
    boolean jboolean Z
    byte jbyte B
    char jchar C
    short jshort S
    int jint I
    long jlong J
    float jfloat F
    double jdouble D

    复杂类型

    image.png

    jni对象的的签名规则为 L类路径; ,例如jstring的签名为 Ljava/lang/String;
    数组的签名规则为 [类型,例如int[]签名是[Ilong[]签名是[L

    有了javajni 变量对象的对应关系及其签名,就可以知道在jni中如何使用了,下面做几个简单演示。

    在这之前先在jni中引入Androidlog库,以便在logcat中输出运行结果。根据你选择的编译类型在 Android.mkCMakeLists.txt中引入Android log

    Android.mk

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    # 库名
    LOCAL_MODULE    := hello
    
    LOCAL_SRC_FILES := src/main/ndk/ndktest.cpp \
                       src/main/ndk/hello.cpp
    
    # 使用系统log
    LOCAL_LDLIBS    :=-llog
    
    include $(BUILD_SHARED_LIBRARY)
    

    CMakeLists.txt

    cmake_minimum_required(VERSION 3.4.1)
    
    add_library( # Specifies the name of the library. 库名
                 hello
    
                 # Sets the library as a shared library.
                 SHARED
    
                 # Provides a relative path to your source file(s).
                 src/main/ndk/hello.cpp
                 src/main/ndk/ndktest.cpp)
    
    # Specifies a path to native header files.
    include_directories(src/main/ndk/)
    
    # 使用系统log
    find_library( # Sets the name of the path variable.
                  log-lib
    
                  # Specifies the name of the NDK library that
                  # you want CMake to locate.
                  # {sdk-path}/ndk-bundle/sysroot/usr/include/android/log.h
                  log )
    
    target_link_libraries( # Specifies the target library.
                           hello
    
                           # Links the target library to the log library
                           # included in the NDK.
                           ${log-lib} )
    

    ndktest.cpp中定义几个宏,方便使用

    #include<android/log.h>
    
    #define TAG "jni-ndktest" 
    #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) 
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) 
    #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) 
    #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)
    #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)
    

    一、基础变量

    javaNDKTest 中新增方法 primitiveTest

        /**
         * jni 基础类型测试
         *
         * @param params1
         * @param params2
         * @param params3
         * @return
         */
        public int primitiveTest(float params1, int params2, boolean params3) {
            Log.i(TAG, "primitiveTest params1:" + params1
                    + " params2:" + params2
                    + " params3:" + params3);
            return 100;
        }
    
    

    ndktest.cpp中新增方法int callPrimitiveMethod(JNIEnv *, jobject);调用 java方法primitiveTest

    /**
     * 基础变量测试
     * @param pEnv
     * @param obj
     * @return
     */
    int callPrimitiveMethod(JNIEnv *pEnv, jobject obj) {
        jclass testClass = pEnv->GetObjectClass(obj);
        jmethodID methodID = pEnv->GetMethodID(testClass, "primitiveTest", "(FIZ)I");
        jint result = pEnv->CallIntMethod(obj, methodID, 15.f, 100, true);
        LOGI("callPrimitiveMethod result:%d", result);
        return 0;
    }
    

    Java_com_don_ndk_NDKTest_getHello 中调用 callPrimitiveMethod 方法

    JNIEXPORT jstring JNICALL Java_com_don_ndk_NDKTest_getHello
            (JNIEnv *pEnv, jobject obj, jint param) {
    
        jstring result = pEnv->NewStringUTF(getHello());
    
    //    callObjectMethod(pEnv, obj);
    //    callStaticMethod(pEnv, obj);
    
        callPrimitiveMethod(pEnv, obj);
        return result;
    }
    

    运行程序,logcat中输出

    I/NDKTest: primitiveTest params1:15.0 params2:100 params3:true
    I/jni-ndktest: callPrimitiveMethod result:100
    

    二、jstring

    javaNDKTest 中新增方法 stringTest

        /**
         * jni jstring 测试
         *
         * @param params1
         * @param params2
         * @return
         */
        public String stringTest(String params1, String params2) {
            Log.i(TAG, "stringTest params1:" + params1 + " params2:" + params2);
            return params1 + "    " + params2;
        }
    
    

    ndktest.cpp中新增方法int calljstringMethod(JNIEnv *, jobject); 调用 java方法stringTest

    /**
     * jstring测试
     * @param pEnv 
     * @param obj 
     * @return 
     */
    int calljstringMethod(JNIEnv *pEnv, jobject obj) {
        jclass testClass = pEnv->GetObjectClass(obj);
        jmethodID methodID = pEnv->GetMethodID(testClass, "stringTest",
                                               "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
        jstring result = (jstring) pEnv->CallObjectMethod(obj, methodID, pEnv->NewStringUTF("幸福"),
                                                          pEnv->NewStringUTF("安康"));
        const char *charResult = pEnv->GetStringUTFChars(result, JNI_FALSE);
        LOGI("calljstringMethod result:%s", charResult);
        pEnv->ReleaseStringUTFChars(result, charResult);
        return 0;
    }
    

    Java_com_don_ndk_NDKTest_getHello 中调用 方法calljstringMethod

    JNIEXPORT jstring JNICALL Java_com_don_ndk_NDKTest_getHello
            (JNIEnv *pEnv, jobject obj, jint param) {
    
        jstring result = pEnv->NewStringUTF(getHello());
    
    //    callObjectMethod(pEnv, obj);
    //    callStaticMethod(pEnv, obj);
    //    callPrimitiveMethod(pEnv, obj);
        calljstringMethod(pEnv, obj);
        return result;
    }
    

    运行程序,logcat中输出

    I/NDKTest: stringTest params1:幸福 params2:安康
    I/jni-ndktest: calljstringMethod result:幸福    安康
    

    三、数组

    javaNDKTest 中新增方法 arrayTest

        /**
         * jni 数组测试
         *
         * @param array
         * @return
         */
        public String[] arrayTest(int[] array) {
            String[] resultArray = new String[array.length];
            for (int i = 0; i < array.length; i++) {
                resultArray[i] = "array index " + i + " is " + array[i];
            }
            return resultArray;
        }
    
    

    ndktest.cpp中新增方法 callArrayMethod 调用java方法arrayTest

    /**
     * 数组测试
     * @param pEnv
     * @param obj
     * @return
     */
    int callArrayMethod(JNIEnv *pEnv, jobject obj) {
        jclass testClass = pEnv->GetObjectClass(obj);
        jmethodID methodID = pEnv->GetMethodID(testClass, "arrayTest", "([I)[Ljava/lang/String;");
        jint buf[] = {10, 20, 30, 40, 50};
        jintArray intArray = pEnv->NewIntArray(5);
        pEnv->SetIntArrayRegion(intArray, 0, 5, buf);
        jobjectArray resultArray = (jobjectArray) pEnv->CallObjectMethod(obj, methodID, intArray);
        for (int i = 0; i < pEnv->GetArrayLength(resultArray); i++) {
            jstring result = (jstring) pEnv->GetObjectArrayElement(resultArray, i);
            const char *charResult = pEnv->GetStringUTFChars(result, JNI_FALSE);
            LOGI("callArrayMethod index %d is %s", i, charResult);
            pEnv->ReleaseStringUTFChars(result, charResult);
        }
        return 0;
    }
    

    Java_com_don_ndk_NDKTest_getHello 中调用方法callArrayMethod

    JNIEXPORT jstring JNICALL Java_com_don_ndk_NDKTest_getHello
            (JNIEnv *pEnv, jobject obj, jint param) {
    
        jstring result = pEnv->NewStringUTF(getHello());
    
    //    callObjectMethod(pEnv, obj);
    //    callStaticMethod(pEnv, obj);
    //    callPrimitiveMethod(pEnv, obj);
    //    calljstringMethod(pEnv, obj);
        callArrayMethod(pEnv, obj);
        return result;
    }
    

    运行程序,logcat中输出

    I/jni-ndktest: callArrayMethod index 0 is array index 0 is 10
    I/jni-ndktest: callArrayMethod index 1 is array index 1 is 20
    I/jni-ndktest: callArrayMethod index 2 is array index 2 is 30
    I/jni-ndktest: callArrayMethod index 3 is array index 3 is 40
    I/jni-ndktest: callArrayMethod index 4 is array index 4 is 50
    

    四、自定义对象

    新增对象TestBean,用以测试jni调用对象

    package com.don.ndk;
    
    public class TestBean {
    
        public TestBean() {
    
        }
    
        public String name;
        public int score;
        public float money;
    
        @Override
        public String toString() {
            return "TestBean{" +
                    "name='" + name + '\'' +
                    ", score=" + score +
                    ", money=" + money +
                    '}';
        }
    }
    

    javaNDKTest 中新增方法 objTest

        /**
         * jni 自定义对象测试
         *
         * @param testBean
         * @return
         */
        public TestBean objTest(TestBean testBean) {
            Log.i(TAG, "objTest " + testBean);
    
            TestBean resultBean = new TestBean();
            resultBean.name = "小红";
            resultBean.score = 100;
            resultBean.money = 1000000.f;
            return resultBean;
        }
    
    

    ndktest.cpp中新增方法int callObjMethod(JNIEnv *, jobject);调用 java方法objTest

    /**
     * jobject测试
     * @param pEnv
     * @param obj
     * @return
     */
    int callObjMethod(JNIEnv *pEnv, jobject obj) {
        jclass testClass = pEnv->GetObjectClass(obj);
        jmethodID methodID = pEnv->GetMethodID(testClass, "objTest",
                                               "(Lcom/don/ndk/TestBean;)Lcom/don/ndk/TestBean;");
    
        // 获取TestBean的类
        jclass beanClass = pEnv->FindClass("com/don/ndk/TestBean");
        // 获取TestBean的构造方法,TestBean中一定要有显式的构造方法
        jmethodID initMethodID = pEnv->GetMethodID(beanClass, "<init>", "()V");
        jfieldID nameFiledID = pEnv->GetFieldID(beanClass, "name", "Ljava/lang/String;");
        jfieldID scoreFiledID = pEnv->GetFieldID(beanClass, "score", "I");
        jfieldID moneyFiledID = pEnv->GetFieldID(beanClass, "money", "F");
    
        // 构造TestBean对象
        jobject testBean = pEnv->NewObject(beanClass, initMethodID);
        // 给TestBean对象赋值
        jstring name = pEnv->NewStringUTF("小明");
        pEnv->SetObjectField(testBean, nameFiledID, name);
        pEnv->DeleteLocalRef(name);
        pEnv->SetIntField(testBean, scoreFiledID, 60);
        pEnv->SetFloatField(testBean, moneyFiledID, -10000.f);
    
        jobject result = pEnv->CallObjectMethod(obj, methodID, testBean);
    
        // 获取返回对象中的值
        jstring resultName = (jstring) pEnv->GetObjectField(result, nameFiledID);
        const char *charResultName = pEnv->GetStringUTFChars(resultName, JNI_FALSE);
        jint resultScore = pEnv->GetIntField(result, scoreFiledID);
        jfloat resultMoney = pEnv->GetFloatField(result, moneyFiledID);
    
        LOGI("callObjMethod result name:%s score:%d money:%f", charResultName, resultScore,
             resultMoney);
        pEnv->ReleaseStringUTFChars(resultName, charResultName);
        return 0;
    }
    

    这里需要特别强调一点,因为这里构造TestBean对象使用的是TestBean的默认方法,所以在TestBean中一定要有显式的构造方法,否则jni找不到方法,会崩溃

    Java_com_don_ndk_NDKTest_getHello 中调用方法callObjMethod

    JNIEXPORT jstring JNICALL Java_com_don_ndk_NDKTest_getHello
            (JNIEnv *pEnv, jobject obj, jint param) {
    
        jstring result = pEnv->NewStringUTF(getHello());
    
    //    callObjectMethod(pEnv, obj);
    //    callStaticMethod(pEnv, obj);
    //    callPrimitiveMethod(pEnv, obj);
    //    calljstringMethod(pEnv, obj);
    //    callArrayMethod(pEnv, obj);
        callObjMethod(pEnv, obj);
        return result;
    }
    

    运行程序,logcat中输出

    I/NDKTest: objTest TestBean{name='小明', score=60, money=-10000.0}
    I/jni-ndktest: callObjMethod result name:小红 score:100 money:1000000.000000
    

    参考:
    Java Native Interface Specification—Contents

    相关文章

      网友评论

          本文标题:jni新手笔记四:jni数据类型

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