Android Studio3.0开发JNI流程------JNI静态注册和动态注册(多个类的native动态注册-经典篇)
来源:互联网 发布:老房子 顶层 知乎 编辑:程序博客网 时间:2024/05/18 15:08
网上关于多个类的动态注册以及管理案例太少啦……
静态注册其实不用多言,Android Studio默认的工程就是静态注册的。
静态注册
一般在写C++代码都会有JNIEXPORT和JNICALL,这两个关键字是两个宏定义,它主要的作用就是说明该函数为JNI函数,在Java虚拟机加载的时候会链接对应的native方法。
在Java虚拟机加载so库时,如果发现含有上面两个宏定义的函数时就会链接到对应Java层的native方法,那么怎么知道对应Java中的哪个类的哪个native方法呢,我们仔细观察JNI函数名的构成其实是:以Java为前缀,并且用“_”下划线将包名、类名以及native方法名连接起来就是对应的JNI函数了。
其实就是:Java+包名+类名+方法名(native方法)
例如:
Java_fj_clover_testjni_MainActivity_stringFromJNI( )
静态方法注册JNI有哪些弊端?
1. 必须遵循某些规则
2. 名字过长
3. 多个class需Javah多遍,其实Android Studio中可不用这么做
4. 运行时去找效率不高
好了说了那么多,那么我们来讲解JNI动态注册。
动态注册
动态注册:在JNi层实现的,JAVA层不需要关心,因为在system.load时就会去调用JNI_OnLoad,有就注册,没就不注册。
动态注册的原理:JNI 允许我们提供一个函数映射表,注册给 JVM,这样 JVM 就可以用函数映射表来调用相应的函数,
而不必通过函数名来查找相关函数(这个查找效率很低,函数名超级长)。
动态注册的过程
第一步:参数映射表,就是需要注册的函数列表,放在JNINativeMethod 类型的数组中,只要有native方法就在这里添加。
//参数映射表//这是在MainActivity中的native方法static JNINativeMethod gMethods_MainActivity[] = { {"stringFromJNI", "()Ljava/lang/String;",(void *) stringFromJNI}, {"setString","(Ljava/lang/String;)Ljava/lang/String;",(void *) setString},};
参数说明:
参数1:就是java代码中用native关键字声明的函数名字符串
参数2:native方法的签名(参数类型和返回值类型)
参数3:C/C++中对应函数的函数名(地址)
参数1的名称是对应Java中的native方法名,但是参数3的名称可以随意取,为了知名见义可以与native方法名保持一致。
第二步:注册native方法
//找到MainActivity.java类static int registerNatives(JNIEnv *engv) { jclass clazz; clazz = engv->FindClass("fj/clover/differentclassregister/MainActivity"); //找到类 if (clazz == NULL) { return JNI_FALSE; } //int len = sizeof(methods) / sizeof(methods[0]); if (engv->RegisterNatives(clazz, gMethods_MainActivity,sizeof(gMethods_MainActivity) / sizeof(gMethods_MainActivity[0])) < 0) { return JNI_FALSE; } return JNI_TRUE;}
第三步:加载jni
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env = NULL; jint result = -1; if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) { return -1; } assert(env != NULL); //为了方便管理我们将不同java类中的native方法分别注册 registerNatives_HongBao(env); //注册MainActivity类的native方法 return JNI_VERSION_1_4;}
当 JVM 执行到 System.loadLibrary() 函数时,会立即调用 JNI_OnLoad() 方法,因此在该方法中进行各种资源的初始化操作最为恰当。
第四步:实现native方法
//实现在MainActivity类的两个方法stringFromJNI() setString()static jstring stringFromJNI(JNIEnv *env, jobject obj) { return env->NewStringUTF("欢迎来到jin的世界...");}jstring setString(JNIEnv *env, jobject instance, jstring str_) { return str_;}
好了,基本流程介绍完成,我们来点有难度的动态注册,现在来个多个类的动态注册。
多个类中native方法的动态注册。
MainActivity.java主要用来验证native方法。
public class MainActivity extends AppCompatActivity { static { System.loadLibrary("native-lib"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //调用MainActivity中的方法(stringFromJNI()方法)... TextView tv1 = (TextView) findViewById(R.id.sample_text1); tv1.setText(stringFromJNI()); //调用MainActivity中的方法(setString()方法)... TextView tv2 = (TextView) findViewById(R.id.sample_text2); tv2.setText(setString("Hello,欢迎来到JNI的世界...")); //调用HongBao类中的java方法<sub()方法> TextView tv3 = (TextView) findViewById(R.id.sample_text3); tv3.setText("测试HongBao类java中sub(5,3)方法相减的结果:"+HongBao.sub(5,3)); //调用HongBao类中的java native方法<add()方法> TextView tv4 = (TextView) findViewById(R.id.sample_text4); tv4.setText("测试HongBao类native的add(5,3)方法相加的结果:"+HongBao.add(3,5)); } /** * A native method that is implemented by the 'native-lib' native library, * which is packaged with this application. */ public static native String stringFromJNI(); //添加的一个带参有返回值的native函数 public native String setString(String str);}
HongBao.java
public class HongBao { /** * 假设这个类有很多方法,我们省略一些其他的方法... */ /** * 该jni方法是测试两个数字相加并返回该结果... * @param x * @param y * @return */ public static native int add(int x, int y); /** * 测试两个整形数字相减 * @param x * @param y * @return */ public static int sub(int x, int y) { return x - y; }}
分别注册以上两个类的方法
头文件native-lib.h声明
#include <jni.h>#ifndef DIFFERENTCLASSREGISTER_NATIVE_LIB_H#define DIFFERENTCLASSREGISTER_NATIVE_LIB_Hstatic jstring stringFromJNI(JNIEnv *env, jobject jobject1); //so层获取一个字符串jstring setString(JNIEnv *env, jobject instance,jstring str);//so层获取带参的字符串static jint add(JNIEnv *env, jclass clazz,jint x,jint y);//HongBao类的native方法
实现体native-lib.cpp
#include <jni.h>#include <string>#include <assert.h>#include <stdlib.h>#include <ctype.h>#include "native-lib.h" //引入头文件...//参数映射表//这是在MainActivity中的native方法static JNINativeMethod gMethods_MainActivity[] = { {"stringFromJNI", "()Ljava/lang/String;", (void *) stringFromJNI}, {"setString", "(Ljava/lang/String;)Ljava/lang/String;", (void *) setString},};//这是在HongBao中的native方法static JNINativeMethod gMethods_HongBao[] = { {"add", "(II)I", (void *) add},};//实现在MainActivity类的两个方法stringFromJNI() setString()static jstring stringFromJNI(JNIEnv *env, jobject obj) { return env->NewStringUTF("欢迎来到jin的世界...");}jstring setString(JNIEnv *env, jobject instance, jstring str_) { return str_;}static jint add(JNIEnv *env, jclass clazz, jint x, jint y) { return x + y;}//找到MainActivity.java类static int registerNatives(JNIEnv *engv) { jclass clazz; clazz = engv->FindClass("fj/clover/differentclassregister/MainActivity"); //找到MainActivity类 if (clazz == NULL) { return JNI_FALSE; } //int len = sizeof(methods) / sizeof(methods[0]); if (engv->RegisterNatives(clazz, gMethods_MainActivity, sizeof(gMethods_MainActivity) / sizeof(gMethods_MainActivity[0])) < 0) { return JNI_FALSE; } return JNI_TRUE;}//注册 HongBao 中的native方法static int registerNatives_HongBao(JNIEnv *engv) { jclass clazz; clazz = engv->FindClass("fj/clover/differentclassregister/HongBao"); //找到HongBao类 if (clazz == NULL) { return JNI_FALSE; } if (engv->RegisterNatives(clazz, gMethods_HongBao, sizeof(gMethods_HongBao) / sizeof(gMethods_HongBao[0])) < 0) { return JNI_FALSE; } return JNI_TRUE;}JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env = NULL; jint result = -1; if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { return result; } assert(env != NULL); //为了方便管理我们将不同java类中的native方法分别注册 if (registerNatives(env) < 0) { //注册HongBao类的native方法 return result; } if (registerNatives_HongBao(env) < 0) { //注册MainActivity类的native方法 return result; } /*registerNatives(env); registerNatives_HongBao(env); */ return JNI_VERSION_1_6;}
运行结果:
是不是很神奇,好了,现在改装我们的程序,将不同类的native方法进行分开处理,便于模块化管理。
多个类中native方法分模块化处理
这样可以将不同类的native方法分开,便于处理。
创建hongbao.h头文件
#include <jni.h>//声明注册方法int registerNatives_HongBao(JNIEnv *engv);//声明HongBao的本地方法jint add(JNIEnv *env, jclass clazz,jint x,jint y);//HongBao类的native方法
hongbao.cpp的主要实现体
#include <jni.h>#include <string>#include <stdlib.h>#include "hongbao.h" //引入hongbao.h头文件//HongBao.java中native方法的实现体jint add(JNIEnv *env, jclass clazz, jint x, jint y) { return x + y;}//HongBao.java中的参数映射表static JNINativeMethod gMethods_HongBao[] = { {"add", "(II)I", (void *) add},};//注册 HongBao 中的native方法int registerNatives_HongBao(JNIEnv *engv) { jclass clazz; clazz = engv->FindClass("fj/clover/differentclassregister/HongBao"); if (clazz == NULL) { return JNI_FALSE; } if (engv->RegisterNatives(clazz, gMethods_HongBao,sizeof(gMethods_HongBao) / sizeof(gMethods_HongBao[0])) < 0) { return JNI_FALSE; } return JNI_TRUE;}
native-lib.h头文件
// Created by Clover on 2017/12/22.#include <jni.h>static jstring stringFromJNI(JNIEnv *env, jobject jobject1); //so层获取一个字符串jstring setString(JNIEnv *env, jobject instance,jstring str);//so层获取带参的字符串
native-lib.cpp方法实现体
#include <jni.h>#include <string>#include <assert.h>#include <stdlib.h>#include <ctype.h>#include "native-lib.h" //引入头文件...#include "hongbao/hongbao.h"//参数映射表//这是在MainActivity中的native方法static JNINativeMethod gMethods_MainActivity[] = { {"stringFromJNI", "()Ljava/lang/String;", (void *) stringFromJNI}, {"setString", "(Ljava/lang/String;)Ljava/lang/String;", (void *) setString},};//实现在MainActivity类的两个方法stringFromJNI() setString()static jstring stringFromJNI(JNIEnv *env, jobject obj) { return env->NewStringUTF("欢迎来到jin的世界...");}jstring setString(JNIEnv *env, jobject instance, jstring str_) { return str_;}//找到MainActivity.java类static int registerNatives(JNIEnv *engv) { jclass clazz; clazz = engv->FindClass("fj/clover/differentclassregister/MainActivity"); //找到MainActivity类 if (clazz == NULL) { return JNI_FALSE; } //int len = sizeof(methods) / sizeof(methods[0]); if (engv->RegisterNatives(clazz, gMethods_MainActivity, sizeof(gMethods_MainActivity) / sizeof(gMethods_MainActivity[0])) < 0) { return JNI_FALSE; } return JNI_TRUE;}JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env = NULL; jint result = -1; if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { return result; } assert(env != NULL); //为了方便管理我们将不同java类中的native方法分别注册 if (registerNatives(env) < 0) { //注册HongBao类的native方法 return result; } if (registerNatives_HongBao(env) < 0) { //注册MainActivity类的native方法 return result; } return JNI_VERSION_1_6;}
运行结果和上面一样的。
其中需要注意的地方就是配置DNK。添加库要添加hongbao库
add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/hongbao/hongbao.cpp src/main/cpp/native-lib.cpp )
好了,奉上博主的代码:
http://download.csdn.net/download/cloverjf/10170456
经过博主改编的代码:
在IDA导出分析中找不到类名了(全部静态处理,在IDA中无法看到导出信息,进一步防止被反编译……)
http://download.csdn.net/download/cloverjf/10173839
- Android Studio3.0开发JNI流程------JNI静态注册和动态注册(多个类的native动态注册-经典篇)
- Android jni 静态注册 和动态注册
- 静态注册JNI和动态注册JNI
- 静态注册JNI和动态注册JNI
- android NDK开发 静态/动态注册 jni
- JNI方法的静态注册和动态注册RegisterNatives
- Android 动态注册JNI
- Android: JNI动态注册
- Android JNI动态注册
- Android 动态注册JNI
- Android JNI的动态注册
- Android Studio Jni开发(三)Native方法动态注册
- 安卓 jni 开发之 native 方法的动态注册
- 初识JNI(二)-静态注册和动态注册
- Android开发值JNI函数动态注册
- android 动态注册Jni函数
- Android 动态注册JNI函数
- Android 动态注册JNI函数
- 用conda安装tensorflow-gpu1.4
- JAVA实现魔术师发牌问题
- 快速排序
- 贪心
- 直接使用命令去下载文件(简单)
- Android Studio3.0开发JNI流程------JNI静态注册和动态注册(多个类的native动态注册-经典篇)
- Lua之__index与__newindex
- 2-SAT 题表
- 动态规划 python 实现 三角形最大值路径
- SDUT-3377-->数据结构实验之查找五:平方之哈希表
- 测量lisp小程序
- MyBatis自带的缓存配置(Cache)
- Leetcode Merge Two Sorted Lists 解题报告
- CodeForces 10 C.Digital Root(数论)