Android JNI常用API函数介绍
Android JNI常用API函数介绍
一、前言
Android JNI的 普通用法估计很多人都会,网上文章介绍的api感觉不全面或者写得太细了但是并没有汇总显示。
所以感觉有必要写一篇通俗简单、全面的JNI函数API,让JNI初学者对JNI相关内容有个底。
首先要明白JNI函数API定义在哪里?
之后遇到函数API参数不明白的情况,可以进行对比确认。
其实所有jniDemo.cpp调用的api函数都是在 jni.h 文件中定义。
Android13 的Jni.h 目录在:system\extras\module_ndk_libs\libnativehelper\include_jni\jni.h 。
Android Studio 创建JNI工程,点击env的函数方法名,就会跳转到api函数的文件;
比如代码 env->GetStringUTFChars,按住Ctrl+鼠标点击 GetStringUTFChars 方法,就会跳转到源文件jni.h中;
底层具体实现功能的不同cpp函数的API这里不会介绍,只介绍JNI相关的API函数;
看完本文,你会发现JNI实际使用到的API函数不多,也不难。
Android JNI的基础知识介绍,之前已经有介绍,不熟悉的可以先看看:
Android Jni的介绍和简单Demo实现:
https://blog.csdn.net/wenzhi20102321/article/details/136291126
本文主要介绍Java和底层C++数据交互过程的jniDemo.cpp中相关API函数知识,有兴趣的可以看看。
二、主要函数api和相关内容
1、常用api函数汇总
jni需要使用的API函数其实就是在jni.h代码文件中定义。
在Android JNI开发中,常用的API函数包括以下几个:
(1)JNIEnv结构体相关函数:
GetVersion():获取JNI的版本号。
GetJavaVM():获取Java虚拟机实例。
NewGlobalRef():创建全局引用。
DeleteGlobalRef():删除全局引用。
(2)JavaVM结构体相关函数:
AttachCurrentThread():将当前线程附加到Java虚拟机上。
DetachCurrentThread():将当前线程从Java虚拟机上分离。
GetEnv():获取当前线程的JNIEnv实例。
(3)jclass相关函数:
FindClass():查找Java类。
GetMethodID():获取Java方法的ID。
GetStaticMethodID():获取静态Java方法的ID。
(4)jobject相关函数:
NewObject():创建Java对象。
CallVoidMethod():调用Java对象的无返回值方法。
CallObjectMethod():调用Java对象的有返回值方法。
Call<Type>Method():调用Java对象的有返回基本数据类型值方法,比如:CallIntMethod()
(5)字段相关函数:
GetFieldID():获取Java字段的ID。
GetStaticFieldID():获取静态Java字段的ID。
Get<Type>Field():获取Java字段的值。
Set<Type>Field():设置Java字段的值。
(6)数组相关函数:
New<Type>Array():创建Java数组。比如:NewBooleanArray()
Get<Type>ArrayElements():获取Java数组的元素。比如:GetIntArrayElements()
Release<Type>ArrayElements():释放Java数组的元素。
(7)字符串函数
GetStringUTFChars():用于将Java字符串转换为C风格的字符串(以UTF-8编码表示)。
GetStringChars():用于将Java字符串转换为Unicode字符数组。
ReleaseStringUTFChars():用于释放由GetStringUTFChars获得的C字符串。
ReleaseStringChars():用于释放由GetStringChars获得的Unicode字符数组。
NewStringUTF():用于创建一个Java字符串,其内容是以UTF-8编码表示的C风格字符串。
NewString():用于创建一个Java字符串,其内容是Unicode字符数组。
这些函数是JNI开发中经常使用的API,可以用来在Java和C/C++之间进行数据的传递和调用。
上面这个汇总表就是常用的API函数汇总表格;
上面API函数只要用 env->API函数就可以调用:
在JNI库中实现一个Java方法,用于获取JNI版本号。
例如jni.cpp代码中 :
JNIEXPORT jint JNICALL Java_your_package_name_GetVersion_get(JNIEnv *env, jclass clazz) {
return env->GetVersion(); //调用函数获取JNI的版本号
}
结构体相关的API函数比较少用,其他API函数都是比较简单和常用。
从上面API函数看,有些API是会随Type类型改变的,
所以先要知道JNI里面数据的类型以及API函数的类型字段。
从jni.h文件看Type关键字包含:
Boolean、Byte、Char、Short、Int、Long、Float、Double;
这个是要记住的,很多不同方法的返回值就要用到对应的类型名称函数。
这几个Type关键字就是对应的Java的8中基本数据类型;除了基本数据类型还有String和Object;
下面就对上面提到的api进行展开说明和示例讲解:
2、JNIEnv结构体相关函数:
(1)GetVersion():获取JNI的版本号
这个函数比较简单,没有什么参数并且返回的是int的基本数据类型。
JNIEXPORT jint JNICALL Java_your_package_name_GetVersion_get(JNIEnv *env, jclass clazz) {
return env->GetVersion(); //调用函数获取JNI的版本号
}
(2)GetJavaVM():获取Java虚拟机实例
#include <jni.h>
JavaVM* g_vm;
//JNI_OnLoad 是JNI默认的声明周期方法,类似Android界面Activity 的onCreate方法
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
// 保存全局的JavaVM实例
g_vm = vm;
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL Java_com_example_MyClass_nativeMethod(JNIEnv* env, jobject obj) {
// 在本地方法中使用GetJavaVM函数获取JavaVM实例
JavaVM* javaVM;
env->GetJavaVM(&javaVM); //实例化javaVM指针对象
// 使用 JavaVM 实例进行操作
// ...
// 如果需要全局访问JavaVM实例,可以使用全局变量g_vm
// ...
//如果要调用Java的方法
//c++调用Java方法:public void cppCallBackMethod(String name, int age)
//中间获取jclass对象,方法id,定义相关参数变量。。。。
(*env).CallVoidMethod(obj, cppCallBackMethod, env->NewStringUTF(message), age);
}
从上面代码看到:
JNI的原生流程 JNI_OnLoad方法中,JavaVM* 可以获取到 JNIEnv*;
native对于的cpp映射方法中, JNIEnv* 通过GetJavaVM函数可以获取到JavaVM*;
需要调用Java类的方法时候,需要用到 JNIEnv*;
非映射方法中如果要调用Java类里面的方法,就要用JavaVM获取到JNIEnv,再调用方法。
(3)NewGlobalRef() 和 DeleteGlobalRef()
NewGlobalRef():创建全局引用 ;DeleteGlobalRef():删除全局引用
JNI的NewGlobalRef函数用于创建一个全局引用,以确保Java对象在本地方法中的访问不会受到垃圾回收的影响。下面是一个使用示例:
#include <jni.h>
// 全局引用
jobject globalRef;
JNIEXPORT void JNICALL Java_com_example_MyClass_initialize(JNIEnv *env, jobject obj) {
// 创建全局引用
globalRef = (*env)->NewGlobalRef(env, obj);
// globalRef = obj; //引用会被回收,这样赋值其他方法中调用会报错
}
JNIEXPORT void JNICALL Java_com_example_MyClass_performCallback(JNIEnv *env, jobject obj) {
// 延时回调Java方法
jclass cls = (*env)->GetObjectClass(env, globalRef);
jmethodID methodID = (*env)->GetMethodID(env, cls, "callbackMethod", "()V");
(*env)->CallVoidMethod(env, globalRef, methodID);
}
JNIEXPORT void JNICALL Java_com_example_MyClass_cleanup(JNIEnv *env, jobject obj) {
// 删除全局引用
(*env)->DeleteGlobalRef(env, globalRef);
}
这里可以看到创建的全局引用的jobject是可以在其他方法使用的;
如果需要用到延时较长时间的回调Java代码就可以用“线程+全局引用”的方式。
(4) AttachCurrentThread 和 DetachCurrentThread
JNI的AttachCurrentThread函数用于将当前线程附加到Java虚拟机中,以便在本地线程中调用Java方法。
示例代码如下:
#include <jni.h>
void myNativeMethod(JNIEnv *env) {
// 在本地线程中调用Java方法
jclass cls = (*env)->FindClass(env, "com/example/MyClass");
jmethodID methodID = (*env)->GetStaticMethodID(env, cls, "myMethod", "()V");
(*env)->CallStaticVoidMethod(env, cls, methodID);
}
void *myThread(void *arg) {
JavaVM *jvm;
JNIEnv *env;
// 获取Java虚拟机实例
if ((*g_vm)->AttachCurrentThread(g_vm, &env, NULL) != JNI_OK) {
// 错误处理
return NULL;
}
// 在本地线程中调用Java方法
myNativeMethod(env);
// 分离当前线程
(*g_vm)->DetachCurrentThread(g_vm);
// 线程结束
return NULL;
}
JNIEXPORT void JNICALL Java_com_example_MyClass_startThread(JNIEnv *env, jobject obj) {
// 创建并启动新线程
pthread_t thread;
pthread_create(&thread, NULL, myThread, NULL);
pthread_detach(thread);
}
(5)GetEnv 获取环境指针
GetEnv 函数用于获取当前线程的JNIEnv环境指针,以便调用API函数和。
上面获取Java虚拟机示例代码中也是有调用到了 GetEnv 函数,使用示例如下:
JavaVM* g_vm;
//JNI_OnLoad 是JNI默认的声明周期方法,类似Android界面Activity 的onCreate方法
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) { // GetEnv实例化 env 指针对象
return JNI_ERR;
}
}
JNIEXPORT void JNICALL Java_com_example_MyClass_nativeMethod(JNIEnv* env, jobject obj) {
// 在本地方法中使用GetJavaVM函数获取JavaVM实例
...
}
上面代码可以看到在JNI 生命周期方法中可以通过GetEnv函数获取到JNIEnv*,
nativie的映射方法是自带了JNIEnv*;
有了 JNIEnv* 指针对象就可以调用JNI 的API函数了。
本文所有介绍的API函数都是要使用到JNIEnv*指针对象进行调用的。
3、jclass、jobject、Filed相关函数:
jclass、jobject、Filed相关函数的使用主要都是在C/C++需要调用Java的方法或者修改Java的属性的时候需要的。
示例代码如下:
extern "C" JNIEXPORT jstring JNICALL
Java_com_demo_jnicallback_MainActivity_stringFromJNI(
JNIEnv* env,
jobject thiz /* this */) {
std::string hello = "Hello from C++";
LOGI("stringFromJNI hello = %s", hello.c_str());
//c++调用Java方法:public void cppCallBackMethod(String name, int age)
jclass mainActivityCls=env->FindClass("com/demo/jnicallback/MainActivity");//获取类对象
jmethodID cppCallBackMethod = env->GetMethodID(mainActivityCls, "cppCallBackMethod", "(Ljava/lang/String;I)V");
const char *message = "cppA";
int age = 10;
env->CallVoidMethod(thiz, cppCallBackMethod, env->NewStringUTF(message), age);
//获取属性的fieldId,--》这里就用到了签名类型
jfieldID ageFid = env->GetFieldID(mainActivityCls,"age","I");
//获取属性值
int age = env->GetIntField(mainActivityThis,ageFid);
//修改属性值,C++中修改变量值后,Java重新获取打印发现是修改过的
env->SetIntField(mainActivityThis, ageFid , 11);
return env->NewStringUTF(hello.c_str());
}
FindClass 都是固定的写法,只是传入的字符串路径不同;
GetMethodID是获取普通方法id,如果Java的是静态方法就用GetStaticMethodID
GetFieldID 和 GetMethodID 函数 都是三个参数:
第一个参数是jclass对象,
第二个参数是Java的方法名称或者变量名称字符串,
第三个参数是方法签名或者变量类型签名。
调用Java方法的函数是:CallXXXMethod,
如果调用的是没有返回值 XXX就是Void,
如果有返回值XXX就是数据类型名称,比如Int,如果是String或者对象类型XXX就是Object
GetXXXField 和 SetXXXField 是获取和设置Java类的属性,XXX也是类型名称或者Object。
NewObject 函数的使用示例:
JNIEXPORT jobject JNICALL Java_com_example_MyNativeClass_createNewObject(JNIEnv *env, jobject obj) {
// 创建新的Java对象
jclass cls = env->FindClass("com/example/MyClass"); // 查找类名
jmethodID methodID = env->GetMethodID(cls, "createNewObject", "()Lcom/example/MyObject;"); // 获取方法ID
jobject newObject = env->NewObject(cls, methodID); // 创建新对象
return newObject;
}
Android JNI复杂用法,回调,C++中调用Java方法:
https://blog.csdn.net/wenzhi20102321/article/details/136419405
4、数组和字符串处理
主要相关的API函数:
数组相关函数:
New<Type>Array():创建Java数组。比如:NewBooleanArray()
Get<Type>ArrayElements():获取Java数组的元素。比如:GetIntArrayElements()
Release<Type>ArrayElements():释放Java数组的元素。
字符串函数
GetStringUTFChars():用于将Java字符串转换为C风格的字符串(以UTF-8编码表示)。
GetStringChars():用于将Java字符串转换为Unicode字符数组。
ReleaseStringUTFChars():用于释放由GetStringUTFChars获得的C字符串。
ReleaseStringChars():用于释放由GetStringChars获得的Unicode字符数组。
NewStringUTF():用于创建一个Java字符串,其内容是以UTF-8编码表示的C风格字符串。
NewString():用于创建一个Java字符串,其内容是Unicode字符数组。
示例demo代码:
(1)MainActivity.java代码
package com.demo.jniobject;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import java.util.Arrays;
public class MainActivity extends AppCompatActivity {
String TAG = "MainActivity.java";
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate");
TextView tv = findViewById(R.id.sample_text);
//返回cpp的字符串
String jniString = stringFromJNI();
Log.i(TAG, "onCreate jniString = " + jniString);
tv.setText(jniString);
//传递int值,cpp 返回int值
int intToJNIBack = intToJNI(16);
Log.i(TAG, "onCreate intToJNIBack = " + intToJNIBack);
//传递String值,cpp 返回String值
String stringToJNIBack = stringToJNI("liwenzhi");
Log.i(TAG, "onCreate stringToJNIBack = " + stringToJNIBack);
//传递String和int值,cpp返回String值
String stringAndIntToJNIBack = stringAndIntToJNI("陈wang",18);
Log.i(TAG, "onCreate stringAndIntToJNIBack = " + stringAndIntToJNIBack);
//传递String数值和int数组值,cpp返回String数值的值
String[] listStringAndListIntToJNIBack = listStringAndListIntToJNI(new String[] {"姚pengtao", "朱dejiu","周fuping"},new int[] {20,21,30});
Log.i(TAG, "onCreate listStringAndListIntToJNIBack = " + Arrays.asList(listStringAndListIntToJNIBack));
Log.i(TAG, "onCreate End jniString = " + jniString);
}
//Java到cpp并且获取返回数据方法
public native String stringFromJNI(); //返回cpp的字符串
public native int intToJNI(int age); //传递int值,cpp 返回int值
public native String stringToJNI(String name); //传递String值,cpp 返回String值
public native String stringAndIntToJNI(String name, int age); //传递String和int值,cpp返回String值
public native String[] listStringAndListIntToJNI(String[] names, int[] ages); //传递String数值和int数组值,cpp返回String数值的值
}
上面这个Java代码就包含很字符串已经数值的数据传递;
具体的处理过程可以看看cpp代码。
(2)native-lib.cpp 代码
#include <jni.h>
#include <string>
#include <android/log.h>
#define LOG_TAG "native-lib.cpp"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
//Java 方法: public native String stringFromJNI()
extern "C" JNIEXPORT jstring JNICALL
Java_com_demo_jniobject_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
LOGI("stringFromJNI hello = %s", hello.c_str());
return env->NewStringUTF(hello.c_str());
}
//Java 方法: public native int intToJNI(int age)
extern "C" JNIEXPORT jint JNICALL
Java_com_demo_jniobject_MainActivity_intToJNI(JNIEnv *env, jobject thiz, jint age) {
int cppAge = age +10;
return cppAge;
}
//Java 方法:public native String stringToJNI(String name)
extern "C" JNIEXPORT jstring JNICALL
Java_com_demo_jniobject_MainActivity_stringToJNI(JNIEnv *env, jobject thiz, jstring name) {
return name;//这里直接返回,想要修改字符串内容可以看看下面代码
}
//Java 方法:public native String stringAndIntToJNI(String name, int age)
extern "C" JNIEXPORT jstring JNICALL
Java_com_demo_jniobject_MainActivity_stringAndIntToJNI(JNIEnv *env, jobject thiz, jstring name,jint age) {
// 将jstring转换为C字符串
const char* c_str1 = env->GetStringUTFChars(name, nullptr);
// 进行字符串拼接,不能像Java一样,"" + 5,这样会报错,要先转换类型
// 将jint转换为C++字符串
std::string numStr = std::to_string(age);
std::string result = std::string(c_str1) + "cpp 拼接 age = " + numStr;
LOGD("stringAndIntToJNI name = %s", c_str1);
// 释放GetStringUTFChars函数申请的资源
env->ReleaseStringUTFChars(name, c_str1);
// 将C字符串转换为jstring
return env->NewStringUTF(result.c_str());
}
//Java 方法:public native String[] listStringAndListIntToJNI(String[] names, int[] ages)
extern "C" JNIEXPORT jobjectArray JNICALL
Java_com_demo_jniobject_MainActivity_listStringAndListIntToJNI(JNIEnv *env, jobject thiz,jobjectArray names, jintArray ages) {
// 获取数组长度
jint length = env->GetArrayLength(names);
// 创建一个新的数组,用于存储修改后的数据
jobjectArray newArray = env->NewObjectArray(length, env->FindClass("java/lang/String"), nullptr);
// 获取原始int数组的指针
jint *originalArray = env->GetIntArrayElements(ages, nullptr);
// 遍历原始数组
for (int i = 0; i < length; i++) {
// 获取原始数组元素
jstring element = (jstring) env->GetObjectArrayElement(names, i);
jint elementInt = originalArray[i] + 2;
std::string numStr = std::to_string(elementInt);
// 将原始字符串转换为新的字符串
const char *c_str = env->GetStringUTFChars(element, nullptr);
std::string modifiedStr = "Modified: ";
modifiedStr += c_str;
modifiedStr += ",age =";
modifiedStr += numStr;
//释放String
env->ReleaseStringUTFChars(element, c_str);
LOGE("listStringAndListIntToJNI modifiedStr = %s", modifiedStr.c_str());
// 创建一个新的字符串对象,并将其设置到新的数组中
jstring newElement = env->NewStringUTF(modifiedStr.c_str());
env->SetObjectArrayElement(newArray, i, newElement);
}
// 释放原始int数组的指针
env->ReleaseIntArrayElements(ages, originalArray, 0);
// 返回修改后的数组
return newArray;
}
里面的代码是不难,但是没写过的,就不知道用哪些api,字符串怎么修改,怎么拼接,打印;
每个Type类型没必要所有的都用一遍,会用一个其他的都是差不多的,变通一下就行;
除了基本类型的Type,如果用到其他Java对象也是和String一样写法就行。
复杂用法可以看看我之前写的文章:
Android JNI 复杂数据demo ,字符串、数组对象等数据操作讲解:
https://blog.csdn.net/wenzhi20102321/article/details/136511145
三、其他
1、主要函数API总结
主要API内容:
(1)JNIEnv 结构体相关函数
(2)JavaVM 结构体相关函数
(3)jclass 相关函数
(4)jobject 相关函数
(5)字段相关函数
(6)数组相关函数
(7)字符串函数
其实主要的JNI API 函数就上面这些相关的内容;大部分会用,那么JNI 的API 就没啥难度了。
其他的API函数可以看jni.h文件,但是这个文件是没有注释的,根据字面意义理解就差不多了。
除了JNIEnv和JavaVM使用的获取使用比较少,其他API使用的还是比较多的;
但是JNI API函数的调用基本都是基于JNIEnv指针对象的,
native对应的映射方法默认就有JNIEnv指针对象和类对象jobject 。
JNI其他API接收文章:JNI的常用方法的中文API:
https://blog.csdn.net/szembed/article/details/126936199
2、在线查看jni.h源码:
地址:
系统中其他文件的代码也是可以用这个网址进行查看。
除了system目录下的jni.h ,在prebuilts目录下同样是有很多jni.h
./prebuilts/jdk/jdk9/linux-x86/include/jni.h
./prebuilts/jdk/jdk9/darwin-x86/include/jni.h
./prebuilts/jdk/jdk17/linux-x86/include/jni.h
./prebuilts/jdk/jdk17/darwin-x86/include/jni.h
./prebuilts/jdk/jdk17/windows-x86/include/jni.h
./prebuilts/jdk/jdk8/linux-x86/include/jni.h
./prebuilts/jdk/jdk8/darwin-x86/include/jni.h
./prebuilts/jdk/jdk11/linux-x86/include/jni.h
./prebuilts/jdk/jdk11/darwin-x86/include/jni.h
./prebuilts/jdk/jdk11/darwin-arm64/include/jni.h
里面的代码除了格式化形式不同,代码内容大部分都是一样的,看其中一个就行。
3、JNI cpp中 JavaVM 和 JNIEnv的关系:
Jni是Java Native Interface的缩写,是Java提供的一种机制,用来实现Java与其他编程语言的交互。
JavaVM(Java Virtual Machine)是Java虚拟机的实例,它负责解释和执行Java字节码。
JNIEnv(Java Native Interface Environment)是一种数据结构,用于在本地方法中访问Java虚拟机的接口。
JavaVM是整个Java虚拟机的实例,它在程序启动时创建,并负责加载、解释和执行Java字节码。
JNIEnv是在本地方法中访问Java虚拟机的接口,它通过JavaVM实例获取,并提供了一系列与Java虚拟机交互的函数。
通过JNIEnv,本地方法可以调用Java方法、访问Java对象和数组,并进行异常处理等操作。
因此,可以说JNIEnv是JavaVM的一部分,通过JNIEnv可以与Java虚拟机进行交互。
在本地方法中,可通过JNIEnv访问Java对象、方法和数组等,并调用相应的函数与Java虚拟机进行通信。
需要注意的是,JavaVM*是线程安全的,可以在多线程环境下使用。*
*但是,JNIEnv*是线程特定的,每个线程需要通过JavaVM*获取自己的JNIEnv*才能进行操作。
3、JNI cpp中 的 JNI_OnLoad 函数
JNI_OnLoad函数是一个可选函数,当JNI库被加载时会被自动调用。
*JNI_OnLoad使用场景一般是:全局变量设置 或者 动态加载JNI。
(1)全局变量设置
在该函数中,可以将传入的JavaVM实例保存为全局变量,以便在其他本地方法中使用。
(1) 通过JNIEnv*获取当前线程的JNIEnv*:
在本地方法中,可以通过JNIEnv*的GetJavaVM函数获取当前线程的JavaVM*实例。然后可以使用JNIEnv*进行与Java代码的交互,如调用Java方法、创建Java对象等。
(2) 执行与Java代码交互的操作:
使用JNIEnv*进行与Java代码的交互操作,例如调用Java方法、创建Java对象、访问Java对象等。
(3) 在JNI_OnUnload函数中进行清理操作(可选):
JNI_OnUnload函数在JNI库被卸载时被自动调用,可以在该函数中进行一些清理操作,例如释放资源或取消全局引用。
上面使用 GetJavaVM() API函数示例和NewGlobalRef() API函数示例 都是有设置全局变量的API 使用示例。
(2)动态注册JNI方法
动态注册主要代码如下:
//包名+类名字符串定义:
const char *mainactivity_class_name = "com/demo/jnistatic/MainActivity";
// 重点:定义类名和函数签名,如果有多个方法要动态注册,在数组里面定义即可
static const JNINativeMethod methods[] = {
{"stringFromJNI", "()Ljava/lang/String;", (void *) cpp_stringFromJNI},
{"intFromJNI", "(I)I", (void *) cpp_intFromJNI},
};
// 定义注册方法
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
LOGD("动态注册");
JNIEnv *env;
if ((vm)->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
LOGD("动态注册GetEnv fail");
return JNI_ERR;
}
// 获取类引用
jclass clazz = env->FindClass(mainactivity_class_name);
// 注册native方法
jint regist_result = env->RegisterNatives(clazz, methods,
sizeof(methods) / sizeof(methods[0]));
if (regist_result) { // 非零true 进if
LOGD("动态注册 fail regist_result = %d", regist_result);
} else {
LOGI("动态注册 success result = %d", regist_result);
}
return JNI_VERSION_1_6;
}
4、Android JNI静态注册和动态注册方法详解
https://blog.csdn.net/wenzhi20102321/article/details/136700209
5、Android Jni的介绍和简单Demo实现
https://blog.csdn.net/wenzhi20102321/article/details/136291126
6、JNI复杂用法,回调,C++中调用Java方法
https://blog.csdn.net/wenzhi20102321/article/details/136419405