diff --git a/Cargo.lock b/Cargo.lock index 561008b..4d95a6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -245,6 +245,7 @@ dependencies = [ "btleplug", "chrono", "jni 0.19.0", + "jni-utils", "keepawake", "libc", "roxmltree", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 66c4422..07e0b9c 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -53,3 +53,8 @@ keepawake = "0.6.0" btleplug = { workspace = true } jni = "0.19" libc = "0.2" +# Pinned to the version btleplug 0.11 resolves to, and it must stay that way: +# the class cache `init` populates is a static *inside this crate*, so a second +# copy at a different version would be a second, empty cache and `connect` +# would go back to panicking. +jni-utils = "0.1.1" diff --git a/src-tauri/src/android.rs b/src-tauri/src/android.rs index 98327f0..6ad2620 100644 --- a/src-tauri/src/android.rs +++ b/src-tauri/src/android.rs @@ -55,6 +55,19 @@ pub extern "system" fn Java_paris_tourolle_bikecontrol_MainActivity_initBtleplug let _ = JVM.set(vm); } + // btleplug's futures are Java objects wrapped by `jni-utils`, and every one + // of its wrappers resolves its class through a cache that only + // `jni_utils::init` fills. droidplug does not call it — its own `init` + // registers droidplug's classes and assumes the application has already + // done this one. Miss it and scanning still works, because scan results + // arrive on a plain callback, while the first `connect` panics on an + // unwrapped `None` deep inside jni-utils, killing the task that was + // connecting. Order matters: this must come first. + if let Err(e) = jni_utils::init(&env) { + tracing::error!("jni-utils failed to initialise: {e}"); + return; + } + match btleplug::platform::init(&env) { Ok(()) => { READY.store(true, Ordering::Release);