rust-mobile/android-activity

How to add support of custom Activity

wusyong opened this issue · 3 comments

Hello, I found this crate seems pretty cool and would like to adopt it. But I defined a custom Activity myself in Kotlin and bind them manually.

I also need many Android APIs which seem only available on Java/Kotlin. I'm not sure if they also expose some header files. Is it possible to add such Activity support in my case?

rib commented

Hi @wusyong, if you are looking to run your app as a standalone native Rust application via android_activity then you can have a custom Activity but it would either need to subclass NativeActivity or GameActivity.

Since it looks like you currently subclass AppCompatActivity then subclassing GameActivity would probably make the most sense (since GameActivity itself subclasses AppCompatActivity)

For generally accessing Java/Kotlin APIs from Rust then you probably need to take a look at https://github.com/jni-rs/jni-rs.

The jni crate aims to help with binding between Rust and JVM APIs (incidentally I also recently took over maintenance of the jni crate)

Thanks for the reply! I'll try to experiment it if I have some time.

I do bind several functions and sometime call Android APIs already. But the binding function names go pretty lengthy, we have to use some macros to help us

rib commented

Yeah, the other thing you can do is use JNI to list all your native method implementations. It's still not very ergonomic and it's something I'd like to improve but can avoid the need to use those lengthy names.

E.g. something like: https://github.com/rib/bluey/blob/5f351c50e6f396bc4fef9c050599f9668c63b339/bluey/src/android/session.rs#L920

I have some ideas for a proc macro that I'd like to try out that could help with binding to APIs implemented in Java/Kotlin so perhaps that will eventually help. e.g. see discussion here: jni-rs/jni-rs#137 (comment) where I was starting to think about being able to declare bindings something like:

#[jni::class_bindings(my.package.MyClass)]
struct MyClassBindings {
    #[jni::method(myMethodA(boolean, int, java.lang.String, int, int) -> boolean)]
    method_a: jni::Binding,
    #[jni::method("ZILjava/lang/String;II)Z")]
    method_b: jni::Binding,
    #[jni::static_method(myStaticMethodC(boolean, int, java.lang.String, int, int) -> boolean)]
    method_c: jni::Binding,
}

(the rough idea was that it would support two alternatives for declaring the Java signature, either 1) a JNI signature like "ZILjava/lang/String;II)Z" or more naturally like myMethodA(boolean, int, java.lang.String, int, int) -> boolean)

(This is different to the case you were referring to though where your macro is to help write native function implementations in Rust - i.e. for Java/Kotlin code to call Rust instead of Rust code calling Java/Kotlin)