androidrustjnauniffi

Cannot load native library on Android: Native library not found in resource path


I am developing a Rust library named Galileo with FFI to Android, and am trying to run it in Android emulator.

It compiles fine with the command and produces x86 directory where you'd expect:

cargo ndk -t i686-linux-android -o ./android_ffi build -p galileo

I use UniFFI to create Kotlin bindings and it works great:

cargo run --bin uniffi-bindgen generate --library target/i686-linux-android/debug/libgalileo.so --language kotlin --out-dir out

I then copy generated x86/libgalileo.so into my test Android application jniLibs/x86, and add generated galileo.kt next to MainActivity.kt. I also call a function from my galileo.kt from main activity.

Then I add dependency to JNA:

implementation("net.java.dev.jna:jna:5.14.0")

and add the libjnidispatch.so to jniLibs/x86. After this, the test application compiles successfully, libjnidispatch is loaded correctly (I know that, because before I put the compiled library to the correct location, running failed with missing that file). But when run, the application crushes with this in logs:

Process: com.example.myapplication, PID: 4134
java.lang.UnsatisfiedLinkError: Unable to load library 'galileo':
dlopen failed: cannot locate symbol "android_main" referenced by "/data/app/~~BbeW1CYviVt5gyj4KvK3Mw==/com.example.myapplication-gJRCDqgORFGFroidh0hO1w==/base.apk!/lib/x86/libgalileo.so"...
dlopen failed: cannot locate symbol "android_main" referenced by "/data/app/~~BbeW1CYviVt5gyj4KvK3Mw==/com.example.myapplication-gJRCDqgORFGFroidh0hO1w==/base.apk!/lib/x86/libgalileo.so"...
dlopen failed: cannot locate symbol "android_main" referenced by "/data/app/~~BbeW1CYviVt5gyj4KvK3Mw==/com.example.myapplication-gJRCDqgORFGFroidh0hO1w==/base.apk!/lib/x86/libgalileo.so"...
Native library (android-x86/libgalileo.so) not found in resource path (.)

What I am sure about:

What I do not understand:


Solution

  • I've found out where this android_main comes from, so I post it here in case anyone else struggle with it.

    I was following an example to write my rust app, and it used android-activity crate. That crate, when added, creates a bridge between Android runtime and rust by exporting functions like Java_OnLoad, the ones that Android Native (or Game) activity call when loads the .so library. Those methods, created behind the scene, need some way to call into the rust app, so android-activity crate uses convention to call android_main function, exported by the app. And since my app did not export that function, loading of .so failed.

    So, to fix this issue, one needs to either remove dependency on android-activity crate, or to add the android_main method.