安卓 jni 开发之 native 方法的动态注册
博客: 安卓之家
微博: 追风917
CSDN: 蒋朋的家
简书: 追风917
最近一直在搞 jni 开发,里面坑挺多,其实都是自己不注意导致的。如果你不知道 jni,但是你又想了解这个坑,请先到隔壁喝个茶,取点经,隔壁地址:
Android 开发 之 JNI入门 - NDK从入门到精通
昨天突发奇想,既然 native 方法的命名是这样的:
Java_完整包名类名_方法名()
那么如果包名或者类名含有下划线“_”时,会怎么样呢?哈哈哈
很悲剧,按照上面的 native 方法的命名规则,会出现 Native method not found
的异常,那么该如何处理呢?只能保证包名和类名不出现下划线吗?
此时,我又想起了 bunnyblue 大神的名言:
对于程序来言,一切都是可以实现的,就是代价的问题
多么简单粗暴,一切都是可以搞的,那么这个该如何处理呢,就是本篇文章里讲到的动态注册 native 方法
动态注册 native 方法
先上一段代码吧:
static jstring nativeDynamicRegFromJni(JNIEnv *env, jobject obj)
{return (*env) -> NewStringUTF(env, "动态注册调用成功");
}JNINativeMethod nativeMethod[] = {{"dynamicRegFromJni", "()Ljava/lang/String;", (void*)nativeDynamicRegFromJni}};JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved)
{JNIEnv *env;if ((*jvm) -> GetEnv(jvm, (void**) &env, JNI_VERSION_1_4) != JNI_OK){return -1;}jclass clz = (*env) -> FindClass(env, "github/jp1017/hellojni/MainActivity");(*env) -> RegisterNatives(env, clz, nativeMethod, sizeof(nativeMethod) / sizeof(nativeMethod[0]));return JNI_VERSION_1_4;
}
上面就是动态注册的全部代码了,java 代码中的函数是 dynamicRegFromJni
,调用的 native 方法是 nativeDynamicRegFromJni
,该方法没有参数,返回值是一个字符串。
如果你看不出来,请继续往下看,容我慢慢道来:
动态注册的原理是这样的:JNI 允许我们提供一个函数映射表,注册给 JVM,这样 JVM 就可以用函数映射表来调用相应的函数,
而不必通过函数名来查找相关函数(这个查找效率很低,函数名超级长)。
JNINativeMethod
这是一个结构体,在 jni.h 头文件中定义:
typedef struct {const char* name;const char* signature;void* fnPtr;} JNINativeMethod;
Java 与 jni 通过该结构体建立联系,其中有三个变量:
- name:Java 中函数的名字。
- signature:签名符号,描述了函数的参数和返回值
- fnPtr:函数指针,指向一个被调用的函数
我们看上面定义的结构体数组:
JNINativeMethod nativeMethod[] = {{"dynamicRegFromJni", "()Ljava/lang/String;", (void*)nativeDynamicRegFromJni}};
可以看出,里面有一个成员,该成员第一个参数 “dynamicRegFromJni”,java 函数名;第二个参数“()Ljava/lang/String:”,是签名符号,意思是该函数没有参数,返回一个字符串;第三个参数就是要调用的 native 方法。
关于 签名符号
可以参考这里:Android JNI编程—JNI基础
当 java 通过 System.loadLibrary 加载完 JNI 动态库后,紧接着会调用 JNI_OnLoad 的函数。
JNI_OnLoad()函数
JNI_OnLoad()函数有两个重要的作用:
1 指定 jni 版本:告诉 JVM 该组件使用哪一个 jni 版本(若未提供JNI_OnLoad()函数,JVM 会默认该使用最老的 JNI 1.1版本),如果要使用新版本的JNI,例如JNI 1.4版,则必须由 JNI_OnLoad() 函数返回常量 JNI_VERSION_1_4 (该常量定义在 jni.h 中) 来告知 JVM 。
2 一系列初始化操作,当 JVM 执行到 System.loadLibrary() 函数时,会立即调用 JNI_OnLoad() 方法,因此在该方法中进行各种资源的初始化操作最为恰当,
RegisterNatives
动态注册的工作就是在这里完成的。
RegisterNatives在 jni.h 中是这么定义的:
jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods)
该函数有三个参数:
- clazz: java 类名,通过 FindClass 得到
- methods:JNINativeMethod 结构体指针
- nMethods: 方法个数
我们看上面该函数的调用:
(*env) -> RegisterNatives(env, clz, nativeMethod, sizeof(nativeMethod) / sizeof(nativeMethod[0]));
咦,里面怎么又四个参数,嗯,是的,这个是 C 编写规则,如果是 C++ 的话,是这样的:
env -> RegisterNatives(clz, nativeMethod, sizeof(nativeMethod) / sizeof(nativeMethod[0]));
看出差别了吗,如果你遇到下面类似错误:
error: request for member 'FindClass' in something not a structure or union
可能就是 C 和 C++ 编写规则的问题咯,check 一下,没什么大问题的。
ok,这样就完成了 native 方法的动态注册
这里补充一点,jni 开发中 80% 会发生的错误:
Native method not found
比如我今天遇到了很多次这个错误:
UnsatisfiedLinkError: Native method not found: github.jp1017.hellojni.MainActivity.dynamicRegFromJni:()Ljava/lang/String;
该问题的发生原因很多,我这里报错是因为自己粗心,代码 大小写 写错,类名 写错等,所以这里提醒大家对待你的代码要像你的女朋友一样,千万不可马虎大意呀。
总结
上面的代码我给上传到了 github: https://github.com/jp1017/HelloJni
jni 开发告一段落了,这几天总结了很多坑,详情请点击这里:
Android Studio 下 jni 开发填坑记
安卓开源库收集整理中,欢迎 PR, star,地址:https://github.com/XXApple/AndroidLibs
分享是一种美德,更是一种生活方式!!
也许你会说我是一个梦想者,但我不是唯一的一个。
悦分享,越快乐^_^
欢迎交流,转载请注明出处,谢谢!
安卓 jni 开发之 native 方法的动态注册相关推荐
- android中oncreate方法,android开发之onCreate( )方法详解
这里我们只关注一句话:This is where you should do all of your normal static set up.其中我们只关注normal static, normal ...
- android开发之onCreate( )方法详解
android开发之onCreate( )方法详解 onCreate( )方法是android应用程序中最常见的方法之一,那么,我们在使用onCreate()方法的时候应该注意哪些问题呢? 先看看Go ...
- JNI开发之-Android.mk和Application.mk 详解
Android.mk和Application.mk 详解 Android.mk 基础知识 变量和宏 NDK 定义的 include 变量 目标信息变量 模块描述变量 NDK 提供的函数宏 Applic ...
- Unity3D游戏开发之Unity3D中的动态阴影
http://blog.csdn.net/qinyuanpei/article/details/32355267 博主今天想和大家分享的是Unity3D中的动态阴影,昨天博主重温了一下自己喜欢的游戏& ...
- edtext 从右边开始输入 安卓_Android开发之EditText属性详解
1.EditText输入的文字为密码形式的设置 (1)通过.xml里设置: 把该EditText设为:android:password="true" // 以".&quo ...
- [Unity3D]Unity3D游戏开发之Unity3D中的动态阴影
大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei. 博主今天想和大家分享的是Unity3D中的动态阴影,昨天博主重温了一下自己喜欢的游戏< ...
- JNI查找 native 方法的规则(静态、动态注册)
转载自:JNI查找 native 方法的规则 通过上一篇文章,大家明白了调用 native 方法之前,首先要调用 System.loadLibrary 接口加载一个实现了native 方法的动态库才能 ...
- 【Android NDK 开发】JNI 动态注册 ( 动态注册流程 | JNI_OnLoad 方法 | JNINativeMethod 结构体 | GetEnv | RegisterNatives )
文章目录 I . 动态注册流程 ( 总结 ) II . JNI_OnLoad 方法 III . 被注册的本地 C/C++ 方法参数 IV . JNINativeMethod 结构体 ( 核心重点 ) ...
- android的动态注册,Android应用开发之BroadcastReceiver(广播)的静态注册和动态注册 --Android开发...
本文将带你了解Android应用开发之BroadcastReceiver(广播)的静态注册和动态注册 --Android开发,希望本文对大家学Android有所帮助 BroadcastReceiver ...
最新文章
- github删除文件_github 仓库中删除历史大文件
- python3 set_python3.x 基础三:set集合
- Qt C++ 命名空间namespaces讲解
- codeigniter 辅助函数 - 敏感词过滤
- 字体乱码的时候,可以使用英文下的写法
- 沙盘正在注销进程start_电脑关不了机,一直处于正在注销,这是为什么
- centos7下给bond网卡配置bridge桥接
- python学习笔记16--javascript总结
- 【优化算法】变色龙算法(CSA)【含Matlab源码 1796期】
- 23.3.3 Web存储机制【JavaScript高级程序设计第三版】
- “数据打通”不等于“数据共融”,智能数据营销解决方案了解一下
- 《投射技术》与科学研究汉字笔迹心理学的希望
- autojs左右滑动脚本代码_Swiper.js实现移动端元素左右滑动
- 主码、候选码与外码的区别
- 偏差-方差权衡(bias-variance-tradeoff)
- PHOENIX IO模块配置
- 第二篇:Haploview做单倍型教程2--分析教程
- 2021年中国人工智能企业数量、投资数量及金额分析:国内互联网巨头腾讯企业投资达82家[图]
- Linux 如何设置代理
- 堡垒机拓扑图_fanzhenlong/堡垒机部署方案总结.md at master · leadsino/fanzhenlong · GitHub...