将 Xamarin 与 jni 集成的正确方法
Proper way to integrate Xamarin with jni
我正在将我的 Android 项目移动到 Xamarin。 Android 项目引用了一个外部库 libmyencoder.so.
这是它公开的其中一个函数的签名:
JNIEXPORT jint JNICALL encodeData (JNIEnv *, jclass, jlong,
jobject, jint, jobject, jint);
在Java这边,本地方法声明如下:
static native int encodeData(long handle,
ByteBuffer input, int inputLen, ByteBuffer output, int maxOutputLen);
在 Xamarin 文档中,我看到了一些使用 dllimport 的示例。基于此,我想我可以如下声明我的 C# 方法:
[DllImport ("myencoder",EntryPoint="encodeData")]
public extern static void encodeData(long handle, ByteBuffer input,
int inputLen, ByteBuffer output, int maxOutputLen);
这个 C# 定义是否正确?
令人困惑的是,虽然我已经定义了入口点,但我并没有在任何地方特别提到本地方法的签名。这将是:
(JLjava/nio/ByteBuffer;ILjava/nio/ByteBuffer;I)I
Xamarin 引擎是否足够智能,可以根据方法声明推断出正确的签名?
此外,我应该将 libmyencoder.so
复制到我的 Xamarin 项目目录中的什么位置?问候。
遗憾的是,来自 Xamarin 的本机调用没有很好的记录。在 github 浏览了一些源代码并进行了一些试验后,我发现
Xamarin 不依赖 Jni。您无需担心坚持 Jni 的做事方式。例如,第一个参数不必是 JNIEnv*
类型。此外,您可以简单地传递指针而不是 jobjects 作为函数参数。
将您的 "jniLibs" Java-Android 内容文件夹(包括您的 .so 文件)复制到 Xamarin.Android 项目下的 "lib" 文件夹,例如:
将 .so 文件的 "Build Action" 设置为 "AndroidNativeLibrary"。
你的方法的签名应该是这样的:
[DllImport ("myencoder",EntryPoint="encodeData")]
public extern static void encodeData(IntPtr env, IntPtr class, IntPtr handle, IntPtr input, IntPtr inputLen, IntPtr output, IntPtr maxOutputLen);
你正在使用 jint、jlong、jobject,所以你不能直接使用 C# 类型,你必须使用 java 类型,例如在 jint 参数使用中,你不能跳过参数,如:JNIEnv *, j类:
并且您必须使用 java 个参数调用您的函数,例如:
Java.Nio.ByteBuffer inputSample = Java.Nio.ByteBuffer.Allocate(10);
Java.Nio.ByteBuffer outputSample = Java.Nio.ByteBuffer.Allocate(10);
System.IntPtr jClassSample = JNIEnv.FindClass(typeof(SomeClass));
Java.Lang.Long handleVal = new Java.Lang.Long(4);
Java.Lang.Integer inputLenVal = new Java.Lang.Integer(4);
Java.Lang.Integer maxOutputLenVal = new Java.Lang.Integer(4);
encodeData(JNIEnv.Handle, jClassSample, handleVal.Handle, inputSample.Handle, inputLenVal.Handle, outputSample.Handle, maxOutputLenVal.Handle);
有关更多详细信息,请在此处查看我的答案:
Load .so file in Xamarin.Android
我正在将我的 Android 项目移动到 Xamarin。 Android 项目引用了一个外部库 libmyencoder.so.
这是它公开的其中一个函数的签名:
JNIEXPORT jint JNICALL encodeData (JNIEnv *, jclass, jlong,
jobject, jint, jobject, jint);
在Java这边,本地方法声明如下:
static native int encodeData(long handle,
ByteBuffer input, int inputLen, ByteBuffer output, int maxOutputLen);
在 Xamarin 文档中,我看到了一些使用 dllimport 的示例。基于此,我想我可以如下声明我的 C# 方法:
[DllImport ("myencoder",EntryPoint="encodeData")]
public extern static void encodeData(long handle, ByteBuffer input,
int inputLen, ByteBuffer output, int maxOutputLen);
这个 C# 定义是否正确?
令人困惑的是,虽然我已经定义了入口点,但我并没有在任何地方特别提到本地方法的签名。这将是:
(JLjava/nio/ByteBuffer;ILjava/nio/ByteBuffer;I)I
Xamarin 引擎是否足够智能,可以根据方法声明推断出正确的签名?
此外,我应该将 libmyencoder.so
复制到我的 Xamarin 项目目录中的什么位置?问候。
遗憾的是,来自 Xamarin 的本机调用没有很好的记录。在 github 浏览了一些源代码并进行了一些试验后,我发现
Xamarin 不依赖 Jni。您无需担心坚持 Jni 的做事方式。例如,第一个参数不必是 JNIEnv*
类型。此外,您可以简单地传递指针而不是 jobjects 作为函数参数。
将您的 "jniLibs" Java-Android 内容文件夹(包括您的 .so 文件)复制到 Xamarin.Android 项目下的 "lib" 文件夹,例如:
将 .so 文件的 "Build Action" 设置为 "AndroidNativeLibrary"。
你的方法的签名应该是这样的:
[DllImport ("myencoder",EntryPoint="encodeData")]
public extern static void encodeData(IntPtr env, IntPtr class, IntPtr handle, IntPtr input, IntPtr inputLen, IntPtr output, IntPtr maxOutputLen);
你正在使用 jint、jlong、jobject,所以你不能直接使用 C# 类型,你必须使用 java 类型,例如在 jint 参数使用中,你不能跳过参数,如:JNIEnv *, j类:
并且您必须使用 java 个参数调用您的函数,例如:
Java.Nio.ByteBuffer inputSample = Java.Nio.ByteBuffer.Allocate(10);
Java.Nio.ByteBuffer outputSample = Java.Nio.ByteBuffer.Allocate(10);
System.IntPtr jClassSample = JNIEnv.FindClass(typeof(SomeClass));
Java.Lang.Long handleVal = new Java.Lang.Long(4);
Java.Lang.Integer inputLenVal = new Java.Lang.Integer(4);
Java.Lang.Integer maxOutputLenVal = new Java.Lang.Integer(4);
encodeData(JNIEnv.Handle, jClassSample, handleVal.Handle, inputSample.Handle, inputLenVal.Handle, outputSample.Handle, maxOutputLenVal.Handle);
有关更多详细信息,请在此处查看我的答案:
Load .so file in Xamarin.Android