android - 在 Xamarin 中正确绑定(bind) native 库

标签 android xamarin java-native-interface

c++ 库 ( Gifflen, animated gif maker ) 中给出此方法:

JNIEXPORT jint JNICALL Java_org_jiggawatt_giffle_Giffle_Init(JNIEnv *ioEnv, jobject ioThis, 
jstring gifName, jint w, jint h, jint numColors, jint quality, jint frameDelay) { ... }

访问它的签名:

extern "C"
{
    JNIEXPORT jint JNICALL Java_org_jiggawatt_giffle_Giffle_Init(JNIEnv *ioEnv,
    jobject ioThis, jstring gifName, jint w, jint h, jint numColors, jint quality, 
    jint frameDelay);
}

p/invoke 不应该与此类似吗?

[DllImport("libgifflen.so", CharSet = CharSet.Ansi)]
public static extern int Java_org_jiggawatt_giffle_Giffle_Init(string gifName, int w, 
int h, int numColors, int quality, int frameDelay);

我有一个基本上只是尝试访问 Init 方法的程序。

我正在成功加载库:Java.Lang.JavaSystem.LoadLibrary("gifflen");

然后我好像指向了正确的方法,但是一进入方法就崩溃了。

我用与 Java 演示应用程序中相同的值调用 Init(并且与我在这个 gif 编码器的所有其他实现中基本相同的值,因为这是所有库的相同代码库):

var pathForResult = "/storage/sdcard0/giftest/giffleResult.gif";
int optCol = 256, optQuality = 100, optDelay = 4;
Giffle.Init (pathForResult , 256, 256, optCol, optQuality, optDelay);

然后我遇到了这个崩溃:

[mono-rt]   at <unknown> <0xffffffff>
[mono-rt]   at (wrapper managed-to-native) org.jiggawatt.giffle.Giffle.Java_org_jiggawatt_giffle_Giffle_Init (string,int,int,int,int,int) <IL 0x00046, 0xffffffff>
[mono-rt]   at org.jiggawatt.giffle.Giffle.Init (string,int,int,int,int,int) [0x00001] in c:\Users\user.name\Projects\Giffle\Giffle\Giffle.cs:20
[mono-rt] 
[mono-rt]   Attempting native Android stacktrace:
[mono-rt] 
[mono-rt]   at Java_org_jiggawatt_giffle_Giffle_Init+19 [0x6433c83c]
[mono-rt]   at ???+12272 [0x6467fff0]
[libc] Fatal signal 11 (SIGSEGV) at 0x6f7475d3 (code=1), thread 29670 (myapp.someapp)

我是否在我的 Xamarin 应用程序中错误地使用了 native 库?

Code for bindings

using System;
using System.Runtime.InteropServices;

namespace org.jiggawatt.giffle
{
    public class Giffle {

        public const string GIFFLE_DLL_NAME = "libgifflen.so";

        [DllImport(GIFFLE_DLL_NAME, CharSet = CharSet.Ansi)]
        public static extern int Java_org_jiggawatt_giffle_Giffle_Init(string gifName, int w, int h, int numColors, int quality, int frameDelay);

        [DllImport(GIFFLE_DLL_NAME, CharSet = CharSet.Ansi)]
        public static extern void Java_org_jiggawatt_giffle_Giffle_Close();

        [DllImport(GIFFLE_DLL_NAME, CharSet = CharSet.Ansi)]
        public static extern int Java_org_jiggawatt_giffle_Giffle_AddFrame(int[] inArray);
    }
}

Code for test

var external = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
var appPath = System.IO.Path.Combine (external, "giftest");
if (!Directory.Exists (appPath)) {
    Directory.CreateDirectory (appPath);
}

var t = "/storage/sdcard0/giftest/result3.gif";

File.Delete (t);
int optCol = 256, optQuality = 100, optDelay = 4;

Giffle.Init (t, 256, 256, optCol, optQuality, optDelay);
var image = Bitmap.CreateBitmap (256, 256, Bitmap.Config.Argb8888);
for (int i = 0; i < 50; i++) {
    image = Bitmap.CreateBitmap (256, 256, Bitmap.Config.Argb8888);
    image.EraseColor (Color.Argb (255, 255 - i * 4, i * 4, i * 4));

    int[] pixelsCopy = new int[image.Width * image.Height];
    image.LockPixels ();
    image.GetPixels(pixelsCopy, 0, image.Width, 0, 0, image.Width, image.Height);
    image.UnlockPixels ();
    image.Recycle ();
    Giffle.Java_org_jiggawatt_giffle_Giffle_AddFrame (pixelsCopy);
}

Giffle.Java_org_jiggawatt_giffle_Giffle_Close ();

最佳答案

如果您的 C++ 代码不使用此参数,您只能像在 Java 中那样跳过此参数“JNIEnv *ioEnv,jobject ioThis”,否则您还应该在函数定义中包含此参数。而且你不应该使用 C# 类型,而是使用 java 类型。

[DllImport("libgifflen.so", EntryPoint = "Java_org_jiggawatt_giffle_Giffle_Init", CharSet = CharSet.Ansi)]
public static extern int Init(IntPtr env, IntPtr thiz, IntPtr gifName, IntPtr w, 
IntPtr h, IntPtr numColors, IntPtr quality, IntPtr frameDelay);

像这样调用你的函数:

Init(JNIEnv.Handle, System.IntPtr.Zero, (new Java.Lang.String("Your gif name")).Handle, (new Java.Lang.Integer(w)).Handle,
    (new Java.Lang.Integer(h)).Handle, (new Java.Lang.Integer(numColors)).Handle, (new Java.Lang.Integer(quality)).Handle, (new Java.Lang.Integer(frameDelay)).Handle);

同时检查这个答案:

Load .so file in Xamarin.Android

关于android - 在 Xamarin 中正确绑定(bind) native 库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33029687/

相关文章:

android - 无法在 Mac OS 上的 Android Studio 中创建新项目

安卓市场计费系统

rest - 似乎无法找到使用 Azure Messaging 推送通知的方法

c# - 当我转到上一页时,所选图像的颜色不显示在 Collection View 中

grails - 从 Grails Application 调用 Mono 下编译的 .NET DLL 还是使用 SOAP?

android - 在 Android Studio 中调试时如何禁用科学记数法?

java - 如何将一批.jpeg文件转换为.gif动画?

android - 通过传递身份验证 token Picasso Xamarin 加载图像

带有 C++ UnsatisfiedLinkError 的 Android Studio JNI

java - 如何查看JNI本地引用表?