在使用JNI的过程中,新建一个C 文件,通过JAVA调用,可能会出现 java.lang.UnsatisfiedLinkError异常,目前遇到过两种情况:1,是ndk版本是64 位的,一般的手机都是32位,所以编译出来的库文件是不可用的。下载ndk 32 位的重新编译即可。 2,由于不同的手机CPU是不同的,所以要针对不同版本生成库文件。解决方法是,在jni/文件夹中生成一个文件Application.mk 里面写一句代码: APP_ABI : all 即可。
目前尝试在JNI中调用AssetManager 来加载Asset目录下的文件,在C代码中需要引入:
#include
#include
调用 AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
的时候编译器报错,大概意思就是AssetManager 找不到,但是上面我已经include 了头文件。后来找到一中解决方案:
在Android.mk 里面添加一个属性:LOCAL_LDLIBS := -landroid ,可以解决,这是我在stackoverflow上面看到的解决方案。
后来转到Android Studio 中开发Jni ,在Studio 中开发JNI的步骤如下:
首先第一步是添加native 接口,只需要生命native方法和System..loadLibrary() 即可,然后在Studio下面的Terminal中进入到app/src/main 中执行 javah -d ../jni packagename.classname
就会自动生成jni文件夹和头文件。然后我们自行建立main.c 这个名字应该是固定的(我不确定),然后编辑完main.c之后就可以点击 build -> make project ,然后Studio 会提示你找不到ndk,这时候需要配置ndk路径和 项目中的JNI配置:如下
在local.properties 中添加ndk.dir 属性:
`ndk.dir=D:\\sdk\\android-ndk-r10e`
然后在应用程序目录下的gradle.build 中的defaultConfig 节点中添加如下代码:
ndk {
moduleName "你的库的名称"
ldLibs 'log','z','m'
abiFilters "armeabi", "armeabi-v7a", "x86"
}
上面就是表明了库的信息和 引入包,最后一行是声明生成库的应用平台。
之后 make project 发现还是报错,没有生成。so文件,我的错误是ndk某些内容已经被弃用了,这时候需要添加一个android.useDeprecatedNdk=true
属性到gradle.properties 文件中(可能只有我自己有这种情况)
如果一切顺利,会在 build/intermeditates/ndk/lib 目录中生成。so文件。
JNI ReferenceTable overflow 问题解决方案:
JNI层coding经常会遇到ReferenceTable overflow问题,出现场景大多在 频繁调用函数的时候,没有释放对象
总体原则:释放所有对object的引用
jclass ref= (env)->FindClass("java/lang/String");
env->DeleteLocalRef(ref);
jstring (*NewString)(JNIEnv*, const jchar*, jsize);
const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*);
void (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*);
jstring (*NewStringUTF)(JNIEnv*, const char*);
const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*);
void (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*);
env->DeleteLocalRef(ref);
jclass ref = env->GetObjectClass(robj);
env->DeleteLocalRef(ref);
jbyte* array= (*env)->GetByteArrayElements(env,jarray,&isCopy);
(*env)->ReleaseByteArrayElements(env,jarray,array,0);
(*env)->ReleaseStringUTFChars(env,jinput,input);
jobject (*NewGlobalRef)(JNIEnv*, jobject);
void (*DeleteGlobalRef)(JNIEnv*, jobject);
jobject ref= env->NewGlobalRef(customObj);
env->DeleteGlobalRef(customObj);