E/AndroidRuntime: FATAL EXCEPTION: main Process: com.sgchip.pimr, PID: 20314 java.lang.UnsatisfiedLinkError: No implementation found for int com.sgchip.pimr.util.IRDA.Init() (tried Java_com_sgchip_pimr_util_IRDA_Init and Java_com_sgchip_pimr_util_IRDA_Init__)
使用第三方.so库调用JNI方法的时候出现了以上异常。
看log说明是没有找到jni的方法,链接.so库错误。
这个.so库是用来进行红外通讯的,是从另一个工程拷贝过来的。.so库里的接口都是带包名的,如果从别的项目拷贝过来,包名变了而.so库里的接口包名没变,就会造成找不到jni方法的异常。
所以解决上述异常有两个方法,一个是改变.so库里接口的包名为新项目的包名,二是把.so库放在.so库接口对应的包名里。我采用的是第二种,问题解决。
JNI的命名规则
这里顺便说一下JNI的命名规则,对于传统的JNI编程来说,JNI方法跟Java类方法的名称之间有一定的对应关系,要遵循一定的命名规则,如下所示:
- 前缀: Java_
- 类的全限定名,用下划线进行分隔(_):com_oyp_jni_JniTest
- 方法名:getTestString
- JNI函数指定第一个参数: JNIEnv *
- JNI函数指定第二个参数: jobject
- 实际Java参数: jstring, jint ….
所以对于在Java类 com.oyp.jni.JniTest类的一个方法:
public native String getTestString (String oyp);
其对应的jni层的方法如下:
jstring Java_com_oyp_jni_JniTest_getTestString(JNIEnv * e, jobject clazz, jstring oyp);
如果不这样命名,当把动态库加载进DVM的时候,通过JNIEnv *指针去查找Java Native方法对应的JNI方法的时候,就会找不到了。
注意,我们也可以利用函数注册的方法,将Java层的方法名跟JNI层的方法名的对应关系保存起来,注册到DVM中,就不需要这样的命名规范了。
JNI 数据类型
我们知道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。