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

字数 446阅读 62

基础类型

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

推荐阅读更多精彩内容