在使用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 <android/asset_manager.h>
    #include <android/asset_manager_jni.h>

调用 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的引用

  • findClass
jclass ref= (env)->FindClass("java/lang/String");
    env->DeleteLocalRef(ref);
  • NewString/ NewStringUTF/NewObject/NewByteArray
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);
  • GetObjectField/GetObjectClass/GetObjectArrayElement
jclass ref = env->GetObjectClass(robj);
    env->DeleteLocalRef(ref);
  • GetByteArrayElements
jbyte* array= (*env)->GetByteArrayElements(env,jarray,&isCopy);
    (*env)->ReleaseByteArrayElements(env,jarray,array,0);
  • const char* input =(*env)->GetStringUTFChars(env,jinput, &isCopy);
(*env)->ReleaseStringUTFChars(env,jinput,input);
  • NewGlobalRef/DeleteGlobalRef
jobject     (*NewGlobalRef)(JNIEnv*, jobject);     
    void        (*DeleteGlobalRef)(JNIEnv*, jobject);
    jobject ref= env->NewGlobalRef(customObj);
    env->DeleteGlobalRef(customObj);