天天看点

【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法错误描述错误分析错误解决方法JNI的命名规则JNI 数据类型

今天使用第三方的so库时候,调用JNI方法时出现了错误。报错如下所示:

在MainActivity中,尝试调用NeteaseMusicUtils类封装好的JNI方法,代码如下所示:

而com.netease.xtc.cloudmusic.utils.NeteaseMusicUtils代码如下:

其中so库位置如下所示:

【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法错误描述错误分析错误解决方法JNI的命名规则JNI 数据类型

再一次查看下错误日志,如下所示:

错误日志提示我们没有 Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit 方法的实现,如下所示:

【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法错误描述错误分析错误解决方法JNI的命名规则JNI 数据类型

然后我去咨询了一下第三方提供so库的工作人员,回复说NeteaseMusicUtils类的包名一定要是com.netease.cloudmusic.utils。原因是JNI接口Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit中,com.netease.xtc.cloudmusic.utils代表的是package name,NeteaseMusicUtils则是class name。

而第三方提供so库的工作人员的c文件的定义JNI接口为Java_com_netease_cloudmusic_utils_NeteaseMusicUtils_nativeInit,即:package name必须为:com.netease.cloudmusic.utils,而class name必须为 NeteaseMusicUtils。

也就是说,我们.so中函数声明涉及到的package name和class name与调用它的package name和class name不符。因此我们要改变我们工程中的package name和class name。使其与.so文件中函数签名提示的一致,在这个类中加入native方法的声明。

好吧,我新建一个包名为com.netease.cloudmusic.utils,并把NeteaseMusicUtils类移到该包名地下。

未移动NeteaseMusicUtils到com.netease.cloudmusic.utils包之前

【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法错误描述错误分析错误解决方法JNI的命名规则JNI 数据类型

移动NeteaseMusicUtils到com.netease.cloudmusic.utils包之后

【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法错误描述错误分析错误解决方法JNI的命名规则JNI 数据类型

然后重新编译,成功运行。

这里顺便说一下JNI的命名规则,对于传统的JNI编程来说,JNI方法跟Java类方法的名称之间有一定的对应关系,要遵循一定的命名规则,如下所示:

前缀: Java_

类的全限定名,用下划线进行分隔(_):com_oyp_jni_JniTest

方法名:getTestString

JNI函数指定第一个参数: JNIEnv *

JNI函数指定第二个参数: jobject

实际Java参数: jstring, jint ….

所以对于在Java类 com.oyp.jni.JniTest类的一个方法:

其对应的jni层的方法如下:

如果不这样命名,当把动态库加载进DVM的时候,通过JNIEnv *指针去查找Java Native方法对应的JNI方法的时候,就会找不到了。

注意,我们也可以利用函数注册的方法,将Java层的方法名跟JNI层的方法名的对应关系保存起来,注册到DVM中,就不需要这样的命名规范了。

我们知道Java的数据类型是跟C/C++的数据类型是不一样的,而JNI是处于Java和Native本地库(大部分是用C/C++写的)中间的一层,JNI对于两种不同的数据类型之间必须做一种转换,所以在JNI跟Java之间就会有数据类型的对应关系。 在JNI中,提供了以下各种数据类型,可以分为原生类型和引用类型: 对于原生类型有:jchar, jbyte, jshort, jint, jlong, jfloat, jdouble, jboolean,其与java端的数据类型对应如下表:

java

jni

char

jchar

byte

jbyte

short

jshort

int

jint

long

jlong

float

jfloat

double

jdouble

boolean

jboolean

对于引用类型则有:jobject, jstring, jthrowable, jclass, jarray, 以及继承于jarray,对应于其原生类型的8种jarray和jobjectarray。

【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法错误描述错误分析错误解决方法JNI的命名规则JNI 数据类型
作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法错误描述错误分析错误解决方法JNI的命名规则JNI 数据类型