JNI和NDK开发之动态注册JNI函数

什么是静态注册

静态注册是根据JNI的方法名字来实现与Java方法的映射对应关系。如下所示,方法名的组成是根据JNIEXPORT jstring JNICALL Java_+包名+_类名+_方法名组成。包名直接要用_连接。

1
JNIEXPORT jstring JNICALL Java_com_common_secure_SecureProtocol_encrypt(JNIEnv *, jobject, jstring)
  • 优点

可以使用javah命令实现头文件和函数名的生成。

  • 缺点

因为方法的名称辨识度较高,所以方法安全性不高,使用IDA反调试so文件的时候很容易暴露接口信息。

什么是动态注册

动态注册是使用RegisterNatives方法来实现与Java方法的映射对应关系。函数原型:

1
jint RegisterNatives(jclass clazz, const JNINativeMethod* methods, jint nMethods)
  • jclass clazz参数是java对应的类
  • JNINativeMethod* methods是java类对应的函数

JNINativeMethod是一个结构体,结构如下

1
2
3
4
5
ypedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;

结构体的第一个参数name是java 方法名;第二个参数signature用于描述方法的参数与返回值;第三个参数fnPtr是函数指针,指向 jni 函数;

其中,第二个参数signature使用字符串记录方法的参数与返回值,具体格式形如()V(II)V,其中分为两部分,括号内表示的是参数,括号右侧表示的是返回值;

1
2
3
JNINativeMethod nativeMethods[] = {
{"encrypt", "(Ljava/lang/String;)Ljava/lang/String;", (void *) encrypt}
};
  • jint nMethods是注册的函数的个数

实现动态注册

在Java层MainActivity中创建一个方法

1
public native String encrypt(String data);

JNI_OnLoad方法中实现动态注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#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;
}

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :