第一和第二篇讲解的是JNI函数的静态注册,这一篇将讲述如何实现JNI函数的动态创建。
本文概览
1、什么是静态注册
2、什么是动态注册
3、实现动态注册
什么是静态注册
静态注册是根据JNI的方法名字来实现与Java方法的映射对应关系。如下所示,方法名的组成是根据JNIEXPORT jstring JNICALL Java_+包名+_类名+_方法名组成。包名直接要用_连接。
JNIEXPORT jstring JNICALL Java_com_common_secure_SecureProtocol_encrypt(JNIEnv *, jobject, jstring)
- 优点
可以使用javah命令实现头文件和函数名的生成。 - 缺点
因为方法的名称辨识度较高,所以方法安全性不高,使用IDA反调试so文件的时候很容易暴露接口信息。
什么是动态注册
动态注册是使用RegisterNatives方法来实现与Java方法的映射对应关系。函数原型:
jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods)
1、jclass clazz参数是java对应的类
2、JNINativeMethod* methods是java类对应的函数
JNINativeMethod是一个结构体,结构如下
ypedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
- 结构体的第一个参数 name 是java 方法名;
- 第二个参数 signature 用于描述方法的参数与返回值;
- 第三个参数 fnPtr 是函数指针,指向 jni 函数;
其中,第二个参数 signature 使用字符串记录方法的参数与返回值,具体格式形如“()V”、“(II)V”,其中分为两部分,括号内表示的是参数,括号右侧表示的是返回值;
JNINativeMethod nativeMethods[] = {
{"encrypt", "(Ljava/lang/String;)Ljava/lang/String;", (void *) encrypt}
};
3、jint nMethods是注册的函数的个数
实现动态注册
- 在java层MainActivity中创建一个方法
public native String encrypt(String data);
- 在
JNI_OnLoad方法中实现动态注册
#include <jni.h>
#include <string>
#include <android/log.h>
#include <cassert>
#include <cstdlib>
#include <iostream>
using namespace std;
#define TAG "LOG_CORE:"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)
//native 方法实现
jstring encrypt(JNIEnv *env) {
return env->NewStringUTF("JNI动态注册成功");
}
/*需要注册的函数列表,放在JNINativeMethod 类型的数组中,
以后如果需要增加函数,只需在这里添加就行了
参数:
1.java中用native关键字声明的函数名
2.签名(传进来参数类型和返回值类型的说明)
3.C/C++中对应函数的函数名(地址)
*/
static JNINativeMethod nativeMethods[] = {
{"encrypt", "(Ljava/lang/String;)Ljava/lang/String;", (void *) encrypt}
};
//此函数通过调用RegisterNatives方法来注册我们的函数
static int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *nativeMethods,int methodsNum) {
jclass clazz;
//找到声明native方法的类
clazz = env->FindClass(className);
if (clazz == NULL) {
return JNI_FALSE;
}
//注册函数 参数:java类 所要注册的函数数组 注册函数的个数
if (env->RegisterNatives(clazz, nativeMethods, methodsNum) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
static int registerNatives(JNIEnv *env) {
//指定类的路径,通过FindClass 方法来找到对应的类
const char *className = "com/rzr/jni/register/MainActivity";
return registerNativeMethods(env, className, nativeMethods,
sizeof(nativeMethods) / sizeof(nativeMethods[0]));
}
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
LOGE("JNI_OnLoad 初始化");
JNIEnv *env = NULL;
jint result = -1;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
assert(env != NULL);
//注册函数 registerNatives ->registerNativeMethods ->env->RegisterNatives
if (!registerNatives(env)) {
return -1;
}
result = JNI_VERSION_1_4;
return result;
}
参考:
https://blog.csdn.net/qq_20404903/article/details/80662316
https://www.jianshu.com/p/1d6ec5068d05
本文深入解析JNI函数的动态注册机制,对比静态注册,探讨其安全性和灵活性。介绍RegisterNatives方法及其实现步骤,包括JNINativeMethod结构体的使用,以及在JNI_OnLoad中的动态注册过程。

被折叠的 条评论
为什么被折叠?



