The jni crate has an example on its doc home page of how to implement a function, in Rust, that you would call from Java or Kotlin. But I want to go the other way. Most of my app is in Rust, but I want to call certain Java APIs, because (as far as I know) there is no Rust API for certain Android feature. For example, I want to call getSharedPreferences on the activity/context, and then store simple data in it.
I create some setup/boilerplate, getting the Android activity, and JNIEnv
fn foo(...) {
let activity = native_activity();
let vm = activity.vm();
let vm = unsafe { JavaVM::from_raw(vm).unwrap() };
let mut env: AttachGuard = vm.attach_current_thread().unwrap();
let context = unsafe { JObject::from_raw(activity.activity()) };
self.get_shared_preferences(&mut *env, context, FILE_KEY)
}
fn get_shared_preferences(&self, env: &mut JNIEnv, context: JObject, file_key: &str) -> JObject {
let file_key_jstring = env.new_string(file_key).unwrap();
// Call getSharedPreferences(String name, int mode)
env.call_method(
context,
"getSharedPreferences",
"(Ljava/lang/String;I)Landroid/content/SharedPreferences;",
&[
JValue::Object(&file_key_jstring),
JValue::Int(0), // Context.MODE_PRIVATE = 0
],
)
.unwrap()
.l()
.unwrap()
The error is:
error: lifetime may not live long enough
--> settings/src/android.rs:99:9
|
95 | fn get_shared_preferences(&self, env: &mut JNIEnv, context: JObject, file_key: &str) -> JObject {
| - --- has type `&mut JNIEnv<'1>`
| |
| let's call the lifetime of this reference `'2`
...
99 | / env.call_method(
100 | | context,
101 | | "getSharedPreferences",
102 | | "(Ljava/lang/String;I)Landroid/content/SharedPreferences;",
... |
109 | | .l()
110 | | .unwrap()
| |_____________________^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
help: consider introducing a named lifetime parameter and update trait if needed
|
95 | fn get_shared_preferences<'a>(&self, env: &mut JNIEnv<'a>, context: JObject, file_key: &str) -> JObject<'a> {
When I took advice at the end there, it did not work, but let to another error:
error[E0515]: cannot return value referencing local variable `vm`
--> settings/src/android.rs:92:9
|
87 | let mut env: AttachGuard = vm.attach_current_thread().unwrap();
| -- `vm` is borrowed here
...
92 | self.get_shared_preferences(&mut *env, context, FILE_KEY)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
I'm lost here. I don't understand the meaning of these errors.