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

什么是静态注册

静态注册是根据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)
  • jclass clazz参数是java对应的类
  • 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}
};
  • 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;
}

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/25/dynamic-registration-of-jni-functions-for-jni-and-ndk-development/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
JNI和NDK开发之动态注册JNI函数
什么是静态注册 静态注册是根据JNI的方法名字来实现与Java方法的映射对应关系。如下所示,方法名的组成是根据JNIEXPORT jstring JNICALL Java_+包名+_类名+_方……
<<上一篇
下一篇>>
文章目录
关闭
目 录