作者:字节流动
来源: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 对象的属性签名和方法签名,用于区分不同的属性和方法。
属性签名
属性的签名就是属性类型的简称。
属性类型与其签名的对应关系如下:
属性类型 | 类型签名 |
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
如 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 完整代码
结果
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 编译的三种方式
- NDK 开发中引入第三方静态库和动态库
- NDK 开发中 Native 与 Java 交互
- NDK POSIX 多线程编程
- NDK Android OpenSL ES 音频采集与播放
- NDK FFmpeg 编译
- NDK FFmpeg 音视频解码
- NDK 直播流媒体服务器搭建
- NDK 直播推流与引流
- NDK 开发中快速定位 Crash 问题
「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。