diff --git a/packages/manganis/manganis-macro/src/ffi.rs b/packages/manganis/manganis-macro/src/ffi.rs index 7a570212c..26f7357b0 100644 --- a/packages/manganis/manganis-macro/src/ffi.rs +++ b/packages/manganis/manganis-macro/src/ffi.rs @@ -398,7 +398,7 @@ impl FfiBridgeParser { // Use with_activity which returns Option, wrapping our Result in the Option let inner_result: Option> = manganis::android::with_activity(|mut env, activity| { // Find the class - let class_result = env.find_class(#class_name_lit); + let class_result = manganis::android::load_class_from_classloader(env, activity, #class_name_lit); let class = match class_result { Ok(c) => c, Err(e) => return Some(Err(format!("Failed to find class {}: {:?}", #class_name_lit, e))), diff --git a/packages/manganis/manganis/src/android/java.rs b/packages/manganis/manganis/src/android/java.rs index fd44731ee..b825a98fc 100644 --- a/packages/manganis/manganis/src/android/java.rs +++ b/packages/manganis/manganis/src/android/java.rs @@ -111,15 +111,34 @@ pub fn request_permissions_via_helper( Ok(()) } -/// Load a Java class from the APK's classloader +/// Load a Java class from the APK's classloader. +/// +/// `JNIEnv::find_class` resolves against the *system* classloader on a thread that +/// was attached from native code (`JavaVM::attach_current_thread`), which cannot see +/// classes packaged in the APK, so it raises `ClassNotFoundException`. The activity's +/// own classloader can, so we ask the activity for it and call `loadClass` on it. +/// +/// `class_name` may be given in either JNI form (`com/example/Foo`) or binary form +/// (`com.example.Foo`); `loadClass` requires the binary form, so slashes are converted. pub fn load_class_from_classloader<'env>( env: &mut JNIEnv<'env>, + activity: &JObject<'_>, class_name: &str, ) -> Result> { - let class_name_jstring = new_string(env, class_name)?; - let class = env.call_static_method( - "java/lang/Class", - "forName", + let binary_name = class_name.replace('/', "."); + let activity_class = env.get_object_class(activity)?; + let loader = env + .call_method( + &activity_class, + "getClassLoader", + "()Ljava/lang/ClassLoader;", + &[], + )? + .l()?; + let class_name_jstring = new_string(env, &binary_name)?; + let class = env.call_method( + &loader, + "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;", &[JValue::Object(&class_name_jstring)], )?;