JNI
JAVA调用C
Java访问C库的方法
- 加载C库
System.loadLibrary - 建立Java函数名到C库函数名的映射关系
隐式建立
类a.b.c.d.JNIDemo要调用hello函数
C语言中要实现Java_a_b_c_d_JNIDemo_hello
可以用工具生成头文件
javac -d . JNIDemo.java
javah -jni a.b.c.d.JNIDemo
显示建立
JNI_OnLoad
加载C库时就会调用这个函数
RegisterNatives
定义一个映射数组JNINativeMethod[]
每个数组项含3个成员
Java里调用的函数名
JNI字段描述符
用"["表示数组,比如"int []"表示为"[I"
对于类,要用全称"L包.子包.类名;"(前面有"L",后面有";"),比如"Ljava/lang/String;"
除String类外,其他的类都用Object表示,即"Ljava/lang/Object;"
C语言实现的本地函数
注册这个数组
(*env)->RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods)
注意:C函数比Java里的声明多2个参数: (JNIEnv *env, jclass cls)
env提供一些辅助函数,后面有例子
cls是对Java类或实例的引用
如果是static方法,则cls是对Java类的引用
否则,cls是对类的实例化对象的引用
- 在Java程序里调用函数
简单例子
Java和C库传递数据
传递基本类型数据
直接使用、直接返回
传递字符串 (jni.pdf P39)
传递数组 (jni.pdf P48
C调用JAVA (jni.pdf P97)- 创建虚拟机
- 获得class
- 实例化对象
对于静态方法,不需要实例化对象
也是通过调用JAVA方法实现
- 调用JAVA方法
1. 获得方法ID
2. 构造参数
3. 调用方法 - 其他
设置属性
1. 获得属性ID
2. 设置属性
3. 读取属性
static const JNINativeMethod methods[] = {
{"hello","(I)I",(void *)c_hello},
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env;
jclass cls;
cached_jvm = jvm; /* cache the JavaVM pointer */
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
return JNI_ERR; /* JNI version not supported */
}
cls = (*env)->FindClass(env, "C");
if (cls == NULL) {
return JNI_ERR;
}
/* Use weak global ref to allow C class to be unloaded */
Class_C = (*env)->NewWeakGlobalRef(env, cls);
if (Class_C == NULL) {
return JNI_ERR;
}
/* Compute and cache the method ID */
MID_C_g = (*env)->GetMethodID(env, cls, "g", "()V");
if (MID_C_g == NULL) {
return JNI_ERR;
}
return JNI_VERSION_1_2;
}
- 编译so
gcc -I/usr/lib/jvm/jdk1.8.0_121/include/ -I/usr/lib/jvm/jdk1.8.0_121/include/linux/ -fPIC -shared -o libnative.so native.c
-
运行
export LD_LIBRARY_PATH=.
java JniDemo -
生成jni描述符
a. 先在native方法的java类目录下执行
javac JniTest.java 生成.class文件
b. 退到androidstudio工程的java目录下,执行
javah -jni com.aispeech.xytttest.callnative.NativeWakeup -
碰到的问题:
a. libnativewakeup.so: has text relocations
参考
调用.so文件时报如下错误:
libcooee.so: has text relocations
说明编译.so文件时使用了较低版本sdk
而project 中的配置 targetSdkVersion22 大于so编译时使用的sdkversion,所以只需要把功能中
的targetSdkVersion降低即可
defaultConfig {
applicationId “com.example”
minSdkVersion 16
targetSdkVersion 22
}