Android Studio NDK 入门教程(8)--JNI动态注册本地方法
2016-09-09 15:20
633 查看
概述
可能大家觉得javah生成的函数名又臭又长,不太好看。这里可以提供另外一种方法来动态注册c++函数,让其根Java中的native方法关联起来。实现
这里通过JNIEnv的Resisternatives方法完成方法的注册。相关方法介绍://方法映射描述结构体 typedef struct { const char* name;//Java方法名 const char* signature;//方法签名 void* fnPtr;//C++ 方法指针 } JNINativeMethod; //这是JNIEnv提供的注册本地方法 //clazz:方法对应的class //methods:对应的方法数组指针 //nMethods:有几个方法 //返回值:注册成功返回JNI_OK jint RegisterNatives(jclass clazz, const JNINativeMethod* methods, jint nMethods); //当本地库被加载时VM调用JNI_OnLoad(例如,通过系统调用LoadLibrary)。JNI_OnLoad必须返回由本地库所需的JNI版本。 //为了使用任何新的JNI函数,一个本地库必须导出JNI_OnLoad函数并返回JNI_VERSION_1_2或更高的版本。 //如果本地库不导出JNI_OnLoad功能,VM假定库只需要JNI_VERSION_1_1版本。 //如果虚拟机不认JNI_OnLoad返回的版本号,本地库不能加载。 JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved);
看了上面的函数,我们可以知道在loadLibrary的时候会首先调用JNI_OnLoad。因此打算在JNI_OnLoad中完成方法注册:
//filename:my.cpp // Created by wastrel on 2016/9/8. // #include <stddef.h> #include "jni.h" //返回一个字符串 JNIEXPORT jstring JNICALL native_hello(JNIEnv *env, jclass clazz) { return env->NewStringUTF("Hello from C++"); } //求两个int的值 JNIEXPORT jint JNICALL native_add(JNIEnv *env, jobject object, jint a, jint b) { return a + b; } //方法数组,JNINativeMethod的第一个参数是Java中的方法名,第二个参数是函数签名,第三个参数是对应的方法指针。 //Java方法的签名一定要与对应的C++方法参数类型一致,否则注册方法可能失败。 static JNINativeMethod method_table[] = { {"native_hello", "()Ljava/lang/String;", (void *) native_hello}, {"native_add", "(II)I", (void *) native_add} }; JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { //OnLoad方法是没有JNIEnv参数的,需要通过vm获取。 JNIEnv *env = NULL; if (vm->AttachCurrentThread(&env, NULL) == JNI_OK) { //获取对应声明native方法的Java类 jclass clazz = env->FindClass("com/example/registerjni/HelloJNI"); if (clazz == NULL) { return JNI_FALSE; } //注册方法,成功返回正确的JNIVERSION。 if (env->RegisterNatives(clazz, method_table, sizeof(method_table)/ sizeof(method_table[0]))==JNI_OK) { return JNI_VERSION_1_4; } } return JNI_FALSE; }
对应的native声明Java文件:
package com.example.registerjni; /** * Created by wastrel on 2016/9/8. */ public class HelloJNI { static { System.loadLibrary("helloJNI"); } public native static String native_hello(); public native int native_add(int a,int b); }
注意:如果你的方法声明了static,那么对应的第二个参数应该是jclass类型。如果你清楚他的实际类型,即便你写成jobject也不会引起程序错误,因为jclass本身也是jobject。但还是建议写为正确的方式,这样可以显得清晰一些。
注意:C++和Java有所不同,如果把
static JNINativeMethod method_table写在开头,你编译的时候会提示找不到函数指针,这是因为自上而下编译的原因。所以应该把定义写在实现方法后面,或者用一个头文件来完成函数的定义。
后记
这只是一种建立Native方法与Java方法的方式,如果没有特殊的需要,不建议使用这种方法来注册。因为使用这种优雅的注册方法,你必须确保你的函数方法和签名的正确性。这可能会增加出错的概率。相关文章推荐
- Android Studio NDK 入门教程--JNI签名验证防止恶意调用
- Android Studio Jni开发(三)Native方法动态注册
- Android JNI开发(1)--JavaVM和 JNIEnv 动态注册本地方法
- Android Studio NDK 入门教程(6)--JNI签名验证防止恶意调用
- Android JNI动态注册Native 方法(实现IDA中改名)
- Android-调用本地方法计算int数值相加结果显示在界面上/NDK-JNI开发实例(三)
- Android-调用本地方法实现将C进程分支出来即生成系统进程/NDK-JNI开发实例(九)
- Android-使用C++实现调用本地方法返回字符串显示在界面上/NDK-JNI开发实例(八)
- [转]Android通过NDK调用JNI,使用opencv做本地c++代码开发配置方法
- Android Studio ndk-Jni开发详细入门,Aes加密demo
- Android Studio NDK 入门教程(4)--优雅的在C++中输出Logcat
- 安卓实战开发之JNI入门及高效的配置(android studio一键生成.h,so及方法签名)
- Android Studio NDK 入门教程(2)--Java与C++之间的简单数据转换与传递
- Android JNI使用方法(“动态注册”)
- Android Studio NDK 入门教程(5)--Java对象的传递与修改
- [Android]JNI动态注册Java函数教程
- Android-java调用本地方法返回字符串显示在界面上/NDK-JNI开发实例(二)
- Android-调用本地方法传递数组参数/NDK-JNI开发实例(五)
- Android(安卓)开发通过NDK调用JNI,使用opencv做本地c++代码开发配置方法 边缘检测 范例代码
- Android Studio NDK 入门教程(3)--Java与C++之间的类型签名