天天看點

NDK 開發中 Native 與 Java 互動Java 與 JNI 資料類型對應關系Native 中的簽名Native 與 Java 互動

作者:位元組流動

來源:

https://blog.csdn.net/Kennethdroid/article/details/86418725

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 對象的屬性簽名和方法簽名,用于區分不同的屬性和方法。

屬性簽名

屬性的簽名就是屬性類型的簡稱。

屬性類型與其簽名的對應關系如下:

屬性類型 類型簽名
Z
B
C
S
I
L
F
D
void V
Ljava/lang/String;
以 L 開頭,後加完整的包名,并以分号結束
[B
以 [ 開頭,後加對象類型簽名,例如 String[] 對應 [Ljava/lang/String;

方法簽名

方法簽名格式:

(參數類型簽名)傳回值類型簽名

那麼如何擷取方法簽名?

執行指令

javah

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: [email protected]
 * 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 開發系列文章:

「視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。
NDK 開發中 Native 與 Java 互動Java 與 JNI 資料類型對應關系Native 中的簽名Native 與 Java 互動

繼續閱讀