Load .so file in Xamarin.Android

2019-02-26 06:57发布

问题:

I'm trying to convert a Java class to C# in Xamarin.Android.

The original Java class have this:

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");
}

I think this "native" methods are the methods inside the .so libraries. Am I correct?

So, to load those libraries in my Xamarin.Android project, I tried to do this:

[DllImport("usb-1.0")]
public static extern int GetUSB();
[DllImport("ftrScanAPI")]
public static extern int GetScanAPI();
[DllImport("ftrScanApiAndroidJni")]
public static extern int GetScanAPIAndroidJNI();

And created a folder structure in my project like: project/lib/arm/files.so

When I run the project I get lots of errors:

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'.

Any idea of what am I doing wrong?

回答1:

If you are using Visual Studio, and you are porting to Xamarin some JNI-Java code that was already working on Android, follow this Steps:

  1. Place your .so files under a "lib" folder on your Xamarin project, example:
  2. Make sure that your .so files are set the "Build Action" to "Android Native Library"

    • Right click to your .so files -> Properties
  3. In C#-Xamarin you can load your libraries in the following way

    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;
    }
    
  4. The native methods in C# must be declarated in the following way:

    [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);
    

On the "EntryPoint" field you have to put the name of the function exactly as they was in your C/C++ code normally Java_your_package_name_YourClassName_YourMethodName.

For Example here is my original C++ code:

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
}

Or maybe check the warnings that usually gives Android Studio to know the full name of your native functions:

  1. In C# Xamarin sometimes you can not skip arguments that you do in java like: JNIEnv * env, or jobject this, you should use IntPtr as a vartype on this parameters. For example to call loadSong function I used the following arguments.

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);
  • Pay atention to the C++ arguments that start with "j" for example: jstring, jint, you can not use C# string on jstring for example, you should use:

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

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