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.so
is compiled with the correct targetlibjinidispatch
is loaded correctly when next to itWhat I do not understand:
android_main
in the logs. This .so
file is not a binary, it's not supposed to be run. There's no adroid_main
anywhere in my Android or Rust projects.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.