在Android版本开发的过程中,需要使用一些用JNI开发的NDK的native库。这里谈一谈踩到的坑,给大家参考。
虽然java的程序我还算熟悉,但是没有了解过 JNI Native 的开发,一般是直接开发的.Net调用.so库。有一个库是从 Java 代码移植,且没有源码,于是乎碰到了一些问题。
一、JNI 对函数的命名是有要求的,.Net则可以直接调用原生看的函数库
例如monodroid 例子
[DllImport ("sanangeles", EntryPoint = "Java_com_example_SanAngeles_DemoRenderer_nativeInit")]
private static extern void nativeInit (IntPtr jnienv);
java 要求按照 Java_pakcage_class_method进行命名。
看看Java的声明
class DemoRenderer implements GLSurfaceView.Renderer {
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
nativeInit();
}
private static native void nativeInit();
}
如果你没有 JNI 的源码,不知道函数声明,你这样写
[DllImport ("sanangeles", EntryPoint = "nativeInit")]
private static extern void nativeInit (IntPtr jnienv);
那就等玩玩吧,如果你改进Java的源码,一定注意EntryPoint的声明。
二、找不到库,指令集的(eabi,eabi-v7a)的问题
默认调试的情况下,xamarin 调试状态,会根据android环境,选择执行的指令集。问题来了,它不能让你选择。于是乎你的libs只有eabi的.so,就会出现dll无法找到的问题。
调试状态,把eabi-v7a的目标库也添加进来。或者使用虚拟机的时候,选择armeabi 的环境。
你可以通过adb shell,到系统中查看库有没有被复制到 /data/app/package/lib 目录。
三、JNI 返回String的处理。
monodroid 介绍的很多方法,是通过 JNIEnv 类反射调用,没有必要非要使用反射方式
var ver = xxx(JNIEnv.Handle);
var s = new Java.Lang.Object(ver, JniHandleOwnership.TransferGlobalRef).JavaCast<Java.Lang.String>().ToString();
ver 是 IntPtr,这样避免使用反射,多进行几次转换。
建议:
如果使用NDK编写的函数库只是用monodroid来调用,没有必要使用JNI的规范,这样效率会更高,也无需传入JNIEnv对象。