Skip to content

Android Crash on React Native 0.80+: JNI NoSuchFieldError (mHybridData) #47

@hrastnik

Description

@hrastnik

Summary
When running the application on Android using React Native 0.81.2, the app crashes immediately upon startup with a JNI error. The error indicates a missing mHybridData field in CallInvokerHolderImpl.

This appears to be caused by internal changes in React Native 0.80+, where the JNI HybridData structure for CallInvoker was modified, breaking the existing implementation in cpp-adapter.cpp.

Environment

  • React Native Version: 0.81.2
  • Platform: Android
  • Library Version: Current

Stack Trace

java_vm_ext.cc:591] JNI DETECTED ERROR IN APPLICATION: JNI GetObjectField called with pending exception java.lang.NoSuchFieldError: no "Lcom/facebook/jni/HybridData;" field "mHybridData" in class "Lcom/facebook/react/turbomodule/core/CallInvokerHolderImpl;" or its superclasses
java_vm_ext.cc:591]   at boolean com.unomed.reactnativematrixsdk.ReactNativeMatrixSdkModule.nativeInstallRustCrate(long, com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder) (ReactNativeMatrixSdkModule.kt:-2)
java_vm_ext.cc:591]   at boolean com.unomed.reactnativematrixsdk.ReactNativeMatrixSdkModule.installRustCrate() (ReactNativeMatrixSdkModule.kt:24)
java_vm_ext.cc:591]   at void com.facebook.jni.NativeRunnable.run() (NativeRunnable.java:-2)
java_vm_ext.cc:591]   at void android.os.Handler.handleCallback(android.os.Message) (Handler.java:958)
java_vm_ext.cc:591]   at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:99)
java_vm_ext.cc:591]   at void com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(android.os.Message) (MessageQueueThreadHandler.kt:21)
java_vm_ext.cc:591]   at boolean android.os.Looper.loopOnce(android.os.Looper, long, int) (Looper.java:205)
java_vm_ext.cc:591]   at void android.os.Looper.loop() (Looper.java:294)
java_vm_ext.cc:591]   at void com.facebook.react.bridge.queue.MessageQueueThreadImpl$Companion.startNewBackgroundThread$lambda$0(com.facebook.react.common.futures.SimpleSettableFuture) (MessageQueueThreadImpl.kt:152)
java_vm_ext.cc:591]   at void com.facebook.react.bridge.queue.MessageQueueThreadImpl$Companion.$r8$lambda$YYXYCFexeoKtAeDpeNYkxZZlpbA(com.facebook.react.common.futures.SimpleSettableFuture) (MessageQueueThreadImpl.kt:-1)
java_vm_ext.cc:591]   at void com.facebook.react.bridge.queue.MessageQueueThreadImpl$Companion$$ExternalSyntheticLambda0.run() (D8$$SyntheticClass:0)
java_vm_ext.cc:591]   at void java.lang.Thread.run() (Thread.java:1012)
java_vm_ext.cc:591] 
java_vm_ext.cc:591]     in call to GetObjectField
java_vm_ext.cc:591]     from boolean com.unomed.reactnativematrixsdk.ReactNativeMatrixSdkModule.nativeInstallRustCrate(long, com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder)

Proposed Solution
I found a solution based on a similar issue in the uniffi-bindgen-react-native repo (Issue #295). We need to update how we cast the CallInvokerHolder in C++ to use fbjni references properly instead of looking for the raw field.

I have successfully patched this locally. Here are the required changes to android/cpp-adapter.cpp in the format of a patch file:

File: patches/@unomed+react-native-matrix-sdk+0.8.1.patch

diff --git a/node_modules/@unomed/react-native-matrix-sdk/android/cpp-adapter.cpp b/node_modules/@unomed/react-native-matrix-sdk/android/cpp-adapter.cpp
index 1656417..893cb0b 100644
--- a/node_modules/@unomed/react-native-matrix-sdk/android/cpp-adapter.cpp
+++ b/node_modules/@unomed/react-native-matrix-sdk/android/cpp-adapter.cpp
@@ -2,6 +2,7 @@
 #include <jni.h>
 #include <jsi/jsi.h>
 #include <ReactCommon/CallInvokerHolder.h>
+#include <fbjni/fbjni.h>
 #include "unomed-react-native-matrix-sdk.h"
 
 namespace jsi = facebook::jsi;
@@ -24,6 +25,8 @@ Java_com_unomed_reactnativematrixsdk_ReactNativeMatrixSdkModule_nativeInstallRus
     jlong rtPtr,
     jobject callInvokerHolderJavaObj
 ) {
+    /** The following code used to work, but since React Native 0.80+, it stopped working on Android so this is the fix.
+    
     // https://github.com/realm/realm-js/blob/main/packages/realm/binding/android/src/main/cpp/io_realm_react_RealmReactModule.cpp#L122-L145
     // React Native uses the fbjni library for handling JNI, which has the concept of "hybrid objects",
     // which are Java objects containing a pointer to a C++ object. The CallInvokerHolder, which has the
@@ -53,6 +56,30 @@ Java_com_unomed_reactnativematrixsdk_ReactNativeMatrixSdkModule_nativeInstallRus
 
     auto runtime = reinterpret_cast<jsi::Runtime *>(rtPtr);
     return unomed_reactnativematrixsdk::installRustCrate(*runtime, jsCallInvoker);
+
+    **/
+
+    try {
+        if (callInvokerHolderJavaObj == nullptr) {
+            return false;
+        }
+
+        auto alias = facebook::jni::alias_ref<jobject>(callInvokerHolderJavaObj);
+        auto holder = facebook::jni::static_ref_cast<facebook::react::CallInvokerHolder::javaobject>(alias);
+        if (!holder) {
+            return false;
+        }
+
+        auto jsCallInvoker = holder->cthis()->getCallInvoker();
+        if (!jsCallInvoker) {
+            return false;
+        }
+
+        auto runtime = reinterpret_cast<jsi::Runtime *>(rtPtr);
+        return unomed_reactnativematrixsdk::installRustCrate(*runtime, jsCallInvoker);
+    } catch (...) {
+        return false;
+    }
 }
 
 extern "C"

References

Steps to Reproduce

  1. Initialize a React Native project with version 0.81.2.
  2. Install @unomed-dev/react-native-matrix-sdk.
  3. Attempt to run on Android.
  4. App crashes on launch with JNI error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions