use std::sync::OnceLock;
use jni::objects::{JClass, JObject, JValue};
use jni::refs::Global;
use jni::{Env, JavaVM, jni_sig, jni_str};
static JVM: OnceLock<JavaVM> = OnceLock::new();
static CLASS_CENTRAL: OnceLock<Global<JClass<'static>>> = OnceLock::new();
static CLASS_PERIPHERAL: OnceLock<Global<JClass<'static>>> = OnceLock::new();
pub fn init_jvm(vm: JavaVM) {
vm.attach_current_thread(|env| {
let activity =
unsafe { JObject::from_raw(env, ndk_context::android_context().context().cast()) };
let class_loader = env
.call_method(
&activity,
jni_str!("getClassLoader"),
jni_sig!("()Ljava/lang/ClassLoader;"),
&[],
)
.expect("getClassLoader failed")
.l()
.expect("not an object");
let central_ref = load_class(env, &class_loader, "org.jakebot.blew.BleCentralManager");
let peripheral_ref =
load_class(env, &class_loader, "org.jakebot.blew.BlePeripheralManager");
let _ = CLASS_CENTRAL.set(central_ref);
let _ = CLASS_PERIPHERAL.set(peripheral_ref);
std::mem::forget(activity);
Ok::<_, jni::errors::Error>(())
})
.expect("init_jvm failed");
JVM.set(vm).expect("JVM already initialized");
}
fn load_class(env: &mut Env, class_loader: &JObject, class_name: &str) -> Global<JClass<'static>> {
let j_name = env.new_string(class_name).expect("new_string");
let cls = env
.call_method(
class_loader,
jni_str!("loadClass"),
jni_sig!("(Ljava/lang/String;)Ljava/lang/Class;"),
&[JValue::Object(&j_name)],
)
.unwrap_or_else(|e| panic!("{class_name} not found: {e}"))
.l()
.expect("not an object");
let cls = unsafe { JClass::from_raw(env, cls.as_raw()) };
env.new_global_ref(cls).expect("global ref")
}
pub(crate) fn jvm() -> &'static JavaVM {
JVM.get()
.expect("JVM not initialized -- did you register tauri-plugin-blew?")
}
pub(crate) fn central_class() -> &'static Global<JClass<'static>> {
CLASS_CENTRAL.get().expect("JNI classes not initialized")
}
pub(crate) fn peripheral_class() -> &'static Global<JClass<'static>> {
CLASS_PERIPHERAL.get().expect("JNI classes not initialized")
}