-
-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathandroid.rs
104 lines (96 loc) · 2.96 KB
/
android.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use flutter_rust_bridge::StreamSink;
use jni::objects::GlobalRef;
use jni::{AttachGuard, JNIEnv, JavaVM};
use once_cell::sync::OnceCell;
use std::cell::RefCell;
use std::sync::atomic::{AtomicUsize, Ordering};
use tokio::runtime::Runtime;
use crate::mobile_init::Error;
static CLASS_LOADER: OnceCell<GlobalRef> = OnceCell::new();
pub static JAVAVM: OnceCell<JavaVM> = OnceCell::new();
std::thread_local! {
static JNI_ENV: RefCell<Option<AttachGuard<'static>>> = RefCell::new(None);
}
pub fn create_runtime(_: StreamSink<String>) -> Result<Runtime, Error> {
let vm = JAVAVM.get().ok_or(Error::JavaVM)?;
let env = vm.attach_current_thread().unwrap();
// We create runtimes multiple times. Only run our loader setup once.
if CLASS_LOADER.get().is_none() {
setup_class_loader(&env).unwrap();
}
let runtime = {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.thread_name_fn(|| {
static ATOMIC_ID: AtomicUsize = AtomicUsize::new(0);
let id = ATOMIC_ID.fetch_add(1, Ordering::SeqCst);
format!("intiface-thread-{}", id)
})
.on_thread_stop(move || {
JNI_ENV.with(|f| *f.borrow_mut() = None);
})
.on_thread_start(move || {
// We now need to call the following code block via JNI calls. God help us.
//
// java.lang.Thread.currentThread().setContextClassLoader(
// java.lang.ClassLoader.getSystemClassLoader()
// );
let vm = JAVAVM.get().unwrap();
let env = vm.attach_current_thread().unwrap();
let thread = env
.call_static_method(
"java/lang/Thread",
"currentThread",
"()Ljava/lang/Thread;",
&[],
)
.unwrap()
.l()
.unwrap();
env
.call_method(
thread,
"setContextClassLoader",
"(Ljava/lang/ClassLoader;)V",
&[CLASS_LOADER.get().unwrap().as_obj().into()],
)
.unwrap();
JNI_ENV.with(|f| *f.borrow_mut() = Some(env));
})
.build()
.unwrap()
};
Ok(runtime)
}
fn setup_class_loader(env: &JNIEnv) -> Result<(), Error> {
let thread = env
.call_static_method(
"java/lang/Thread",
"currentThread",
"()Ljava/lang/Thread;",
&[],
)?
.l()?;
let class_loader = env
.call_method(
thread,
"getContextClassLoader",
"()Ljava/lang/ClassLoader;",
&[],
)?
.l()?;
CLASS_LOADER
.set(env.new_global_ref(class_loader)?)
.map_err(|_| Error::ClassLoader)
}
// THIS HAS TO BE COMMENTED OUT OR REMOVED FROM GENERATED CODE WHEN BUILDING IOS CODEGEN OTHERWISE
// IOS BUILDS WILL FAIL
#[cfg(target_os = "android")]
#[no_mangle]
pub extern "C" fn JNI_OnLoad(vm: jni::JavaVM, _res: *const std::os::raw::c_void) -> jni::sys::jint {
let env = vm.get_env().unwrap();
jni_utils::init(&env).unwrap();
btleplug::platform::init(&env).unwrap();
let _ = JAVAVM.set(vm);
jni::JNIVersion::V6.into()
}