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:
libgalileo.sois compiled with the correct target- it is put into the correct directory, as
libjinidispatchis loaded correctly when next to it
What I do not understand:
- Why is there
android_mainin the logs. This.sofile is not a binary, it's not supposed to be run. There's noadroid_mainanywhere in my Android or Rust projects. - Why the library fails to load and how to fix it.
I've found out where this
android_maincomes 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-activitycrate. That crate, when added, creates a bridge between Android runtime and rust by exporting functions likeJava_OnLoad, the ones that Android Native (or Game) activity call when loads the.solibrary. Those methods, created behind the scene, need some way to call into the rust app, soandroid-activitycrate uses convention to callandroid_mainfunction, exported by the app. And since my app did not export that function, loading of.sofailed.So, to fix this issue, one needs to either remove dependency on
android-activitycrate, or to add theandroid_mainmethod.