在Xamarin.Android中加载.so文件

4

我想把一个Java类转换成Xamarin.Android下的C#。

这个原始的Java类有以下内容:

private native boolean OpenDeviceCtx(Object obj);
public native boolean CloseDevice();
public native boolean GetDiodesStatus(byte[] bArr);
public native boolean GetFrame(byte[] bArr);
public native boolean GetImage(int i, byte[] bArr);
public native boolean GetImage2(int i, byte[] bArr);
public native boolean GetImageByVariableDose(int i, byte[] bArr);
public native boolean GetImageSize();
public native boolean GetInterfaces(byte[] bArr);
public native String GetVersionInfo();
public native boolean IsFingerPresent();
public native boolean OpenDevice();
public native boolean OpenDeviceOnInterface(int i);
public native boolean Restore7Bytes(byte[] bArr);
public native boolean RestoreSecret7Bytes(byte[] bArr, byte[] bArr2);
public native boolean Save7Bytes(byte[] bArr);
public native boolean SaveSecret7Bytes(byte[] bArr, byte[] bArr2);
public native boolean SetDiodesStatus(int i, int i2);
public native boolean SetGlobalSyncDir(String str);
public native boolean SetLogOptions(int i, int i2);
public native boolean SetNewAuthorizationCode(byte[] bArr);
public native boolean SetOptions(int i, int i2);

static {
    System.loadLibrary("usb-1.0");
    System.loadLibrary("ftrScanAPI");
    System.loadLibrary("ftrScanApiAndroidJni");
}

我认为"本地"方法是指.so库中的方法。我的理解正确吗?
因此,为了在我的Xamarin.Android项目中加载这些库,我尝试了以下操作:
[DllImport("usb-1.0")]
public static extern int GetUSB();
[DllImport("ftrScanAPI")]
public static extern int GetScanAPI();
[DllImport("ftrScanApiAndroidJni")]
public static extern int GetScanAPIAndroidJNI();

我在项目中创建了一个文件夹结构,如下:project/lib/arm/files.so

当我运行这个项目时,出现了许多错误:

DllImport attempting to load: 'usb-1.0'.
DllImport error loading library '/storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0" not found'.
DllImport error loading library '/storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0.so': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0.so" not found'.
DllImport error loading library '/system/lib/libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//system/lib/libusb-1.0" not found'.
DllImport error loading library '/system/lib/libusb-1.0.so': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//system/lib/libusb-1.0.so" not found'.
DllImport error loading library 'libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/libusb-1.0" not found'.
DllImport error loading library 'libusb-1.0.so': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/libusb-1.0.so" not found'.
DllImport error loading library 'usb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/usb-1.0" not found'.
DllImport error loading library '/storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0" not found'.
DllImport error loading library '/storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0.so': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0.so" not found'.
DllImport error loading library '/system/lib/libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//system/lib/libusb-1.0" not found'.
DllImport error loading library '/system/lib/libusb-1.0.so': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//system/lib/libusb-1.0.so" not found'.
DllImport error loading library 'libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/libusb-1.0" not found'.
DllImport error loading library 'libusb-1.0.so': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/libusb-1.0.so" not found'.
DllImport error loading library 'libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/libusb-1.0" not found'.
DllImport unable to load library 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/libusb-1.0" not found'.
DllImport attempting to load: 'usb-1.0'.
DllImport error loading library '/storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0" not found'.
DllImport error loading library '/storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0.so': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0.so" not found'.
DllImport error loading library '/system/lib/libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//system/lib/libusb-1.0" not found'.
DllImport error loading library '/system/lib/libusb-1.0.so': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//system/lib/libusb-1.0.so" not found'.
DllImport error loading library 'libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/libusb-1.0" not found'.
DllImport error loading library 'libusb-1.0.so': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/libusb-1.0.so" not found'.
DllImport error loading library 'usb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/usb-1.0" not found'.
DllImport error loading library '/storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0" not found'.
DllImport error loading library '/storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0.so': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//storage/emulated/0/Android/data/RDScanFingerprint.RDScanFingerprint/files/.__override__/libusb-1.0.so" not found'.
DllImport error loading library '/system/lib/libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//system/lib/libusb-1.0" not found'.
DllImport error loading library '/system/lib/libusb-1.0.so': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm//system/lib/libusb-1.0.so" not found'.
DllImport error loading library 'libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/libusb-1.0" not found'.
DllImport error loading library 'libusb-1.0.so': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/libusb-1.0.so" not found'.
DllImport error loading library 'libusb-1.0': 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/libusb-1.0" not found'.
DllImport unable to load library 'dlopen failed: library "/data/app/RDScanFingerprint.RDScanFingerprint-1/lib/arm/libusb-1.0" not found'.

我做错了什么,你有任何想法吗?


https://developer.xamarin.com/guides/android/advanced_topics/using_native_libraries/ - SushiHangover
我会尝试的。谢谢。 - gregoryp
@perozzo 你在 Xamarin 集成方面有进展了吗? - Louis Lewis
1个回答

13

如果您正在使用Visual Studio并且要将已经在Android上运行的JNI-Java代码移植到Xamarin,请按照以下步骤:

  1. 将您的 .so 文件放置在 Xamarin 项目的“lib”文件夹下,例如: enter image description here
  2. 确保您的 .so 文件的“生成操作”设置为“Android Native Library”

    • 右键单击 .so 文件-> 属性 enter image description here enter image description here
  3. 在 C#-Xamarin 中,您可以通过以下方式加载库:

try
{
    JavaSystem.LoadLibrary("SDL2");
    JavaSystem.LoadLibrary("glib-2.0");
    JavaSystem.LoadLibrary("gthread-2.0");
    JavaSystem.LoadLibrary("fluidsynth");
    JavaSystem.LoadLibrary("sdl_mixer");
    JavaSystem.LoadLibrary("initmixer");
}
catch (UnsatisfiedLinkError e)
{
    return e.Message;
}
  • C#中的本地方法必须按以下方式声明:

  • [DllImport("initmixer", EntryPoint = "Java_sf2Tools_FluidsynthJNI_loadSong")]
    public static extern int loadSong(IntPtr env, IntPtr thiz, IntPtr songPath, int miliseconds);
    [DllImport("initmixer", EntryPoint = "Java_sf2Tools_FluidsynthJNI_isPlaying")]
    public static extern int isPlaying();
    [DllImport("initmixer", EntryPoint = "Java_sf2Tools_FluidsynthJNI_pauseAudio")]
    public static extern void pauseAudio();
    [DllImport("initmixer", EntryPoint = "Java_sf2Tools_FluidsynthJNI_resumeAudio")]
    public static extern void resumeAudio();
    [DllImport("initmixer", EntryPoint = "Java_sf2Tools_FluidsynthJNI_stopAudio")]
    public static extern void stopAudio();
    [DllImport("initmixer", EntryPoint = "Java_sf2Tools_FluidsynthJNI_setSoundfonts")]
    public static extern void setSoundfonts(IntPtr env, IntPtr thiz, IntPtr js);
    

    在"EntryPoint"字段中,您需要将函数名称精确地放置为它们在您的C/C++代码中的名称,通常为Java_your_package_name_YourClassName_YourMethodName。

    例如,这是我的原始C++代码:

    void Java_sf2Tools_FluidsynthJNI_setSoundfonts(JNIEnv * env, jobject this, jstring js)
    {
        //Some code
    }
    void Java_sf2Tools_FluidsynthJNI_pauseAudio(JNIEnv * env, jobject this)
    {
        //Some code
    }
    void Java_sf2Tools_FluidsynthJNI_resumeAudio(JNIEnv * env, jobject this)
    {
        //Some code
    }
    int Java_sf2Tools_FluidsynthJNI_isPlaying(JNIEnv * env, jobject this)
    {
        //Some code
    }
    void Java_sf2Tools_FluidsynthJNI_stopAudio(JNIEnv * env, jobject this)
    {
        //Some code
    }
    
    int Java_sf2Tools_FluidsynthJNI_loadSong(JNIEnv * env, jobject this, jstring songPath)
    {
        //Some code
    }
    

    或者您可以检查Android Studio通常提供的警告,以了解本机函数的完整名称:

    enter image description here

    1. 在C# Xamarin中,有时您不能像在Java中那样省略参数,如:JNIEnv * env或jobject this,您应该在这些参数上使用IntPtr作为变量类型。例如,要调用loadSong函数,我使用了以下参数。

    C/C++

    void Java_sf2Tools_FluidsynthJNI_setSoundfonts(JNIEnv * env, jobject this, jstring js)
    

    C# Xamarin

    fluidsynth.setSoundfonts(JNIEnv.Handle, System.IntPtr.Zero, new Java.Lang.String(getCFGPathFiltered()).Handle);
    
    • 注意以 "j" 开头的 C++ 参数,例如:jstring、jint,不能在 jstring 上使用 C# 字符串,应使用:

    jstring -> new Java.Lang.String("sampleString").Handle -> System.IntPtr

    jint -> new Java.Lang.Integer(4).Handle -> System.IntPtr


    我正在处理这个问题,很抱歉回复晚了。由于我没有构建它们,我该如何知道我的方法的DLL名称?我已经从Android Studio中获取了方法名称。由于我在项目中导入了3个DLL,是否有一种方法可以知道DLL名称? - gregoryp
    Java中System.LoadLibrary没有错误或异常,但在调用本地方法时,调用方法时会出现空引用异常。 - uncle_scrooge

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接