Nozbe / WatermelonDB

🍉 Reactive & asynchronous database for powerful React and React Native apps ⚡️
https://watermelondb.dev
MIT License
10.62k stars 600 forks source link

Bridgeless Mode support (New Architecture) [0.74] #1769

Open angelo-hub opened 7 months ago

angelo-hub commented 7 months ago

Bridgeless Mode is going to be default in 0.74 can offer some bandwidth to migrate to bridgeless mode as this is a super cool project

enahum commented 6 months ago

Have you been able to make it work even with the bridge on 74? On Android there is no longer getJSIModulePackage I cannot seem to find a solution to this yet.

enahum commented 6 months ago

@radex do you think you can take a look at this to solve the breaking change introduced by RN 74 ?

karengharibyan commented 6 months ago

+

hawadlu commented 5 months ago

@angelo-hub Any progress on this one?

yuyongmao commented 5 months ago

Have you been able to make it work even with the bridge on 74? On Android there is no longer getJSIModulePackage I cannot seem to find a solution to this yet.

@enahum Is there any progress on this issue? I have the same problem.

suman379 commented 4 months ago

@radex any plan for new arch?

LukasMod commented 3 months ago

@radex Can we get an answer in this thread? Are there any plans to restore the compatibility of the library with the latest version of react native (current 0.74.3)?

radex commented 3 months ago

Yes, sorry for staying quiet about it. Yes, I'm planning to work on this likely in August.

3210jr commented 3 months ago

Hey @radex - I am happy to help with chores and low hanging fruit re new architecture support. Not my area of expertise but if there is a pull request I will contribute

lucaswitch commented 3 months ago

Hey @radex - I am happy to help with chores and low hanging fruit re new architecture support. Not my area of expertise but if there is a pull request I will contribute

I'm happy to help too

juliesaia-vendora commented 2 months ago

I got it working on 0.74.5 (with bridge) with this patch, it reverts the deprecation and removes BridgelessCatalystInstance.kt.

It might be possible to do the same with 0.75, but it will be more difficult because there they actually removed the JSIModule stuff. I might try it later though

Be sure to enable building from source on Android (android/settings.gradle):

includeBuild('../node_modules/react-native') {
    dependencySubstitution {
        substitute(module("com.facebook.react:react-android")).using(project(":packages:react-native:ReactAndroid"))
        substitute(module("com.facebook.react:react-native")).using(project(":packages:react-native:ReactAndroid"))
        substitute(module("com.facebook.react:hermes-android")).using(project(":packages:react-native:ReactAndroid:hermes-engine"))
        substitute(module("com.facebook.react:hermes-engine")).using(project(":packages:react-native:ReactAndroid:hermes-engine"))
    }
}

The patch:

diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index 7258ab9..6df97c6 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -55,6 +55,8 @@ import com.facebook.react.bridge.CatalystInstance;
 import com.facebook.react.bridge.CatalystInstanceImpl;
 import com.facebook.react.bridge.JSBundleLoader;
 import com.facebook.react.bridge.JSExceptionHandler;
+import com.facebook.react.bridge.JSIModulePackage;
+import com.facebook.react.bridge.JSIModuleType;
 import com.facebook.react.bridge.JavaJSExecutor;
 import com.facebook.react.bridge.JavaScriptExecutor;
 import com.facebook.react.bridge.JavaScriptExecutorFactory;
@@ -184,6 +186,7 @@ public class ReactInstanceManager {
   private volatile Boolean mHasStartedDestroying = false;
   private final MemoryPressureRouter mMemoryPressureRouter;
   private final @Nullable JSExceptionHandler mJSExceptionHandler;
+    private final @Nullable JSIModulePackage mJSIModulePackage;
   private final @Nullable UIManagerProvider mUIManagerProvider;
   private final @Nullable ReactPackageTurboModuleManagerDelegate.Builder mTMMDelegateBuilder;
   private List<ViewManager> mViewManagers;
@@ -232,6 +235,7 @@ public class ReactInstanceManager {
       @Nullable DevBundleDownloadListener devBundleDownloadListener,
       int minNumShakes,
       int minTimeLeftInFrameForNonBatchedOperationMs,
+      @Nullable JSIModulePackage jsiModulePackage,
       @Nullable UIManagerProvider uIManagerProvider,
       @Nullable Map<String, RequestHandler> customPackagerCommandHandlers,
       @Nullable ReactPackageTurboModuleManagerDelegate.Builder tmmDelegateBuilder,
@@ -292,6 +296,7 @@ public class ReactInstanceManager {
       }
       mPackages.addAll(packages);
     }
+    mJSIModulePackage = jsiModulePackage;
     mUIManagerProvider = uIManagerProvider;

     // Instantiate ReactChoreographer in UI thread.
@@ -1399,15 +1404,20 @@ public class ReactInstanceManager {
       }
     }

+    if (mJSIModulePackage != null) {
+      catalystInstance.addJSIModules(
+          mJSIModulePackage.getJSIModules(
+              reactContext, catalystInstance.getJavaScriptContextHolder()));
+    }
+
     if (mUIManagerProvider != null) {
       UIManager uiManager = mUIManagerProvider.createUIManager(reactContext);
       if (uiManager != null) {
-        catalystInstance.setFabricUIManager(uiManager);
-
-        // Initialize the UIManager
         uiManager.initialize();
         catalystInstance.setFabricUIManager(uiManager);
       }
+    } else if (ReactFeatureFlags.enableFabricRenderer) {
+    catalystInstance.getJSIModule(JSIModuleType.UIManager);
     }
     if (mBridgeIdleDebugListener != null) {
       catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java
index d467ab9..3ae051f 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java
@@ -20,6 +20,7 @@ import com.facebook.hermes.reactexecutor.HermesExecutorFactory;
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.bridge.JSBundleLoader;
 import com.facebook.react.bridge.JSExceptionHandler;
+import com.facebook.react.bridge.JSIModulePackage;
 import com.facebook.react.bridge.JavaScriptExecutorFactory;
 import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
 import com.facebook.react.bridge.UIManagerProvider;
@@ -67,6 +68,7 @@ public class ReactInstanceManagerBuilder {
   private @Nullable JavaScriptExecutorFactory mJavaScriptExecutorFactory;
   private int mMinNumShakes = 1;
   private int mMinTimeLeftInFrameForNonBatchedOperationMs = -1;
+  private @Nullable JSIModulePackage mJSIModulesPackage;
   private @Nullable UIManagerProvider mUIManagerProvider;
   private @Nullable Map<String, RequestHandler> mCustomPackagerCommandHandlers;
   private @Nullable ReactPackageTurboModuleManagerDelegate.Builder mTMMDelegateBuilder;
@@ -77,6 +79,12 @@ public class ReactInstanceManagerBuilder {

   /* package protected */ ReactInstanceManagerBuilder() {}

+  public ReactInstanceManagerBuilder setJSIModulesPackage(
+      @Nullable JSIModulePackage jsiModulePackage) {
+    mJSIModulesPackage = jsiModulePackage;
+    return this;
+  }
+
   /** Factory for desired implementation of JavaScriptExecutor. */
   public ReactInstanceManagerBuilder setJavaScriptExecutorFactory(
       @Nullable JavaScriptExecutorFactory javaScriptExecutorFactory) {
@@ -353,6 +361,7 @@ public class ReactInstanceManagerBuilder {
         mDevBundleDownloadListener,
         mMinNumShakes,
         mMinTimeLeftInFrameForNonBatchedOperationMs,
+        mJSIModulesPackage,
         mUIManagerProvider,
         mCustomPackagerCommandHandlers,
         mTMMDelegateBuilder,
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java
index 6551937..3f1fb6f 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java
@@ -10,6 +10,7 @@ package com.facebook.react;
 import android.app.Application;
 import androidx.annotation.Nullable;
 import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.JSIModulePackage;
 import com.facebook.react.bridge.JavaScriptExecutorFactory;
 import com.facebook.react.bridge.ReactMarker;
 import com.facebook.react.bridge.ReactMarkerConstants;
@@ -84,6 +85,7 @@ public abstract class ReactNativeHost {
             .setLazyViewManagersEnabled(getLazyViewManagersEnabled())
             .setRedBoxHandler(getRedBoxHandler())
             .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
+            .setJSIModulesPackage(getJSIModulePackage())
             .setUIManagerProvider(getUIManagerProvider())
             .setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
             .setReactPackageTurboModuleManagerDelegateBuilder(
@@ -125,6 +127,10 @@ public abstract class ReactNativeHost {
     return mApplication;
   }

+  protected @Nullable JSIModulePackage getJSIModulePackage() {
+    return null;
+  }
+
   protected @Nullable UIManagerProvider getUIManagerProvider() {
     return reactApplicationContext -> null;
   }
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
index b2e2d7c..0ee0dd6 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
@@ -120,7 +120,7 @@ public interface CatalystInstance
   RuntimeScheduler getRuntimeScheduler();

   @Deprecated
-  <T extends JSIModule> void addJSIModules(List<JSIModuleSpec<T>> jsiModules);
+  void addJSIModules(List<JSIModuleSpec> jsiModules);

   /**
    * Returns a hybrid object that contains a pointer to a JS CallInvoker, which is used to schedule
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index f86dffb..67e5e35 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -537,8 +537,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
   public native RuntimeScheduler getRuntimeScheduler();

   @Override
-  @Deprecated
-  public <T extends JSIModule> void addJSIModules(List<JSIModuleSpec<T>> jsiModules) {
+  public void addJSIModules(List<JSIModuleSpec> jsiModules) {
     mJSIModuleRegistry.registerModules(jsiModules);
   }

diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModuleRegistry.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModuleRegistry.java
index 90d5cde..e81b361 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModuleRegistry.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModuleRegistry.java
@@ -26,8 +26,8 @@ class JSIModuleRegistry {
     return Assertions.assertNotNull(jsiModuleHolder.getJSIModule());
   }

-  public <T extends JSIModule> void registerModules(List<JSIModuleSpec<T>> jsiModules) {
-    for (JSIModuleSpec<T> spec : jsiModules) {
+  public void registerModules(List<JSIModuleSpec> jsiModules) {
+    for (JSIModuleSpec spec : jsiModules) {
       mModules.put(spec.getJSIModuleType(), new JSIModuleHolder(spec));
     }
   }
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessCatalystInstance.kt b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessCatalystInstance.kt
deleted file mode 100644
index 03a18c6..0000000
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessCatalystInstance.kt
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-package com.facebook.react.runtime
-
-import android.content.res.AssetManager
-import com.facebook.proguard.annotations.DoNotStrip
-import com.facebook.react.bridge.CatalystInstance
-import com.facebook.react.bridge.JSIModule
-import com.facebook.react.bridge.JSIModuleSpec
-import com.facebook.react.bridge.JSIModuleType
-import com.facebook.react.bridge.JavaScriptContextHolder
-import com.facebook.react.bridge.JavaScriptModule
-import com.facebook.react.bridge.NativeArray
-import com.facebook.react.bridge.NativeArrayInterface
-import com.facebook.react.bridge.NativeModule
-import com.facebook.react.bridge.NativeModuleRegistry
-import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener
-import com.facebook.react.bridge.RuntimeExecutor
-import com.facebook.react.bridge.RuntimeScheduler
-import com.facebook.react.bridge.UIManager
-import com.facebook.react.bridge.queue.ReactQueueConfiguration
-import com.facebook.react.common.annotations.DeprecatedInNewArchitecture
-import com.facebook.react.common.annotations.VisibleForTesting
-import com.facebook.react.internal.turbomodule.core.interfaces.TurboModuleRegistry
-import com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder
-import com.facebook.react.turbomodule.core.interfaces.NativeMethodCallInvokerHolder
-
-@DoNotStrip
-@DeprecatedInNewArchitecture
-public class BridgelessCatalystInstance(private val reactHost: ReactHostImpl) : CatalystInstance {
-
-  override fun handleMemoryPressure(level: Int) {
-    throw UnsupportedOperationException("Unimplemented method 'handleMemoryPressure'")
-  }
-
-  override fun loadScriptFromAssets(
-      assetManager: AssetManager,
-      assetURL: String,
-      loadSynchronously: Boolean
-  ) {
-    throw UnsupportedOperationException("Unimplemented method 'loadScriptFromAssets'")
-  }
-
-  override fun loadScriptFromFile(fileName: String, sourceURL: String, loadSynchronously: Boolean) {
-    throw UnsupportedOperationException("Unimplemented method 'loadScriptFromFile'")
-  }
-
-  override fun loadSplitBundleFromFile(fileName: String, sourceURL: String) {
-    throw UnsupportedOperationException("Unimplemented method 'loadSplitBundleFromFile'")
-  }
-
-  override fun setSourceURLs(deviceURL: String, remoteURL: String) {
-    throw UnsupportedOperationException("Unimplemented method 'setSourceURLs'")
-  }
-
-  override fun runJSBundle() {
-    throw UnsupportedOperationException("Unimplemented method 'runJSBundle'")
-  }
-
-  override fun hasRunJSBundle(): Boolean {
-    throw UnsupportedOperationException("Unimplemented method 'hasRunJSBundle'")
-  }
-
-  override fun getSourceURL(): String? {
-    throw UnsupportedOperationException("Unimplemented method 'getSourceURL'")
-  }
-
-  @DoNotStrip
-  override fun invokeCallback(callbackID: Int, arguments: NativeArrayInterface) {
-    throw UnsupportedOperationException("Unimplemented method 'invokeCallback'")
-  }
-
-  override fun callFunction(module: String, method: String, arguments: NativeArray) {
-    throw UnsupportedOperationException("Unimplemented method 'callFunction'")
-  }
-
-  override fun destroy() {
-    throw UnsupportedOperationException("Unimplemented method 'destroy'")
-  }
-
-  override fun isDestroyed(): Boolean {
-    throw UnsupportedOperationException("Unimplemented method 'isDestroyed'")
-  }
-
-  @VisibleForTesting
-  override fun initialize() {
-    throw UnsupportedOperationException("Unimplemented method 'initialize'")
-  }
-
-  override fun getReactQueueConfiguration(): ReactQueueConfiguration =
-      reactHost.reactQueueConfiguration!!
-
-  override fun <T : JavaScriptModule> getJSModule(jsInterface: Class<T>): T =
-      reactHost.currentReactContext?.getJSModule(jsInterface)!!
-
-  override fun <T : NativeModule> hasNativeModule(nativeModuleInterface: Class<T>): Boolean =
-      reactHost.hasNativeModule(nativeModuleInterface)
-
-  override fun <T : NativeModule> getNativeModule(nativeModuleInterface: Class<T>): T? =
-      reactHost.getNativeModule(nativeModuleInterface)
-
-  override fun getNativeModule(moduleName: String): NativeModule? =
-      reactHost.getNativeModule(moduleName)
-
-  @Deprecated(
-      message =
-          "getJSIModule(JSIModuleType moduleType) is deprecated and will be deleted in the future. Please use ReactInstanceEventListener to subscribe for react instance events instead.")
-  override fun getJSIModule(moduleType: JSIModuleType): JSIModule {
-    throw UnsupportedOperationException("Unimplemented method 'getJSIModule'")
-  }
-
-  override fun getNativeModules(): Collection<NativeModule> = reactHost.getNativeModules()
-
-  override fun extendNativeModules(modules: NativeModuleRegistry) {
-    throw UnsupportedOperationException("Unimplemented method 'extendNativeModules'")
-  }
-
-  override fun addBridgeIdleDebugListener(listener: NotThreadSafeBridgeIdleDebugListener) {
-    throw UnsupportedOperationException("Unimplemented method 'addBridgeIdleDebugListener'")
-  }
-
-  override fun removeBridgeIdleDebugListener(listener: NotThreadSafeBridgeIdleDebugListener) {
-    throw UnsupportedOperationException("Unimplemented method 'removeBridgeIdleDebugListener'")
-  }
-
-  override fun registerSegment(segmentId: Int, path: String) {
-    throw UnsupportedOperationException("Unimplemented method 'registerSegment'")
-  }
-
-  @VisibleForTesting
-  override fun setGlobalVariable(propName: String, jsonValue: String) {
-    throw UnsupportedOperationException("Unimplemented method 'setGlobalVariable'")
-  }
-
-  @Deprecated(message = "This API is unsupported in the New Architecture.")
-  override fun getJavaScriptContextHolder(): JavaScriptContextHolder? {
-    return reactHost.getJavaScriptContextHolder()
-  }
-
-  override fun getRuntimeExecutor(): RuntimeExecutor? {
-    return reactHost.getRuntimeExecutor()
-  }
-
-  override fun getRuntimeScheduler(): RuntimeScheduler {
-    throw UnsupportedOperationException("Unimplemented method 'getRuntimeScheduler'")
-  }
-
-  @Deprecated(message = "This API is unsupported in the New Architecture.")
-  override fun <T : JSIModule> addJSIModules(jsiModules: List<JSIModuleSpec<T>>) {
-    throw UnsupportedOperationException("Unimplemented method 'addJSIModules'")
-  }
-
-  override fun getJSCallInvokerHolder(): CallInvokerHolder? {
-    return reactHost.getJSCallInvokerHolder()
-  }
-
-  override fun getNativeMethodCallInvokerHolder(): NativeMethodCallInvokerHolder {
-    throw UnsupportedOperationException("Unimplemented method 'getNativeMethodCallInvokerHolder'")
-  }
-
-  @Deprecated(
-      message =
-          "setTurboModuleManager(JSIModule getter) is deprecated and will be deleted in the future. Please use setTurboModuleRegistry(TurboModuleRegistry turboModuleRegistry) instead.",
-      replaceWith = ReplaceWith("setTurboModuleRegistry(turboModuleRegistry)"))
-  override fun setTurboModuleManager(getter: JSIModule) {
-    throw UnsupportedOperationException("Unimplemented method 'setTurboModuleManager'")
-  }
-
-  @DeprecatedInNewArchitecture(
-      message =
-          "This method will be deprecated later as part of Stable APIs with bridge removal and not encouraged usage.")
-  override fun setTurboModuleRegistry(turboModuleRegistry: TurboModuleRegistry) {
-    throw UnsupportedOperationException("Unimplemented method 'setTurboModuleRegistry'")
-  }
-
-  @DeprecatedInNewArchitecture(
-      message =
-          "This method will be deprecated later as part of Stable APIs with bridge removal and not encouraged usage.")
-  override fun setFabricUIManager(fabricUIManager: UIManager) {
-    throw UnsupportedOperationException("Unimplemented method 'setFabricUIManager'")
-  }
-
-  @DeprecatedInNewArchitecture(
-      message =
-          "This method will be deprecated later as part of Stable APIs with bridge removal and not encouraged usage.")
-  override fun getFabricUIManager(): UIManager {
-    throw UnsupportedOperationException("Unimplemented method 'getFabricUIManager'")
-  }
-}
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessReactContext.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessReactContext.java
index d1cdaa9..24cc18a 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessReactContext.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessReactContext.java
@@ -81,14 +81,6 @@ class BridgelessReactContext extends ReactApplicationContext implements EventDis
     return mReactHost.getUIManager();
   }

-  @Override
-  public CatalystInstance getCatalystInstance() {
-    Log.w(
-        TAG,
-        "[WARNING] Bridgeless doesn't support CatalystInstance. Accessing an API that's not part of the new architecture is not encouraged usage.");
-    return new BridgelessCatalystInstance(mReactHost);
-  }
-
   @Override
   public boolean hasActiveReactInstance() {
     return mReactHost.isInstanceInitialized();

Really frustrating that the RN changelog mentions that this was unused in open source, idk how they missed this huge repo

LukasMod commented 1 month ago

@radex Could you update how you see the progress of this work?

We're trying to get the app ready for the new architecture as of version 0.76 and are looking for issues among the key libraries. Without watermelonDB it probably won't be possible, so any information about the progress/plans would be super valuable. Maybe someone advanced from the community would be able to help solve some problems.

swapnil001 commented 1 month ago

Hi, Any update on solution for this?

prathameshmm02 commented 1 month ago

WatermelonDB JSI module can be registered like this in React Native 0.74+:

MainApplication.kt

import others....
import com.facebook.react.ReactInstanceManager
import com.nozbe.watermelondb.jsi.JSIInstaller
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.UiThreadUtil

class MainApplication : Application(), ReactApplication {
....
    private var listenerAdded = false
    override fun onCreate() {
        super.onCreate()
        ....
        registerJSIModules()
    }

    private fun runOnJSQueueThread(action: () -> Unit) {
        reactNativeHost.reactInstanceManager.currentReactContext?.runOnJSQueueThread {
            action()
        } ?: UiThreadUtil.runOnUiThread {
            reactNativeHost.reactInstanceManager.currentReactContext?.runOnJSQueueThread {
                action()
            }
        }
    }

    @Suppress("DEPRECATION")
    private fun registerJSIModules() {
        val reactInstanceManager = reactNativeHost.reactInstanceManager

        if (!listenerAdded) {
            listenerAdded = true
            reactInstanceManager.addReactInstanceEventListener(object : ReactInstanceManager.ReactInstanceEventListener {
                override fun onReactContextInitialized(context: ReactContext) {
                    runOnJSQueueThread {
                        registerWatermelonJSI(context)
                    }
                }
            })
        }
    }

    private fun registerWatermelonJSI(context: ReactContext) {
        val holder = context.javaScriptContextHolder?.get()
        if (holder != null) {
            JSIInstaller.install(context, holder)
        }
    }
}

A patch is also required to make JSIInstaller class and methods public.

diff --git a/native/android-jsi/src/main/java/com/nozbe/watermelondb/jsi/JSIInstaller.java b/native/android-jsi/src/main/java/com/nozbe/watermelondb/jsi/JSIInstaller.java
index 055cede2f20cd6a75ffb79d156e35396c1438c91..fb7ca33847aa9ad1349b10b35d4e27575e843479 100755
--- a/native/android-jsi/src/main/java/com/nozbe/watermelondb/jsi/JSIInstaller.java
+++ b/native/android-jsi/src/main/java/com/nozbe/watermelondb/jsi/JSIInstaller.java
@@ -1,8 +1,8 @@
 package com.nozbe.watermelondb.jsi;

 import android.content.Context;
-class JSIInstaller {
-    static void install(Context context, long javaScriptContextHolder) {
+public class JSIInstaller {
+    public static void install(Context context, long javaScriptContextHolder) {
         JSIInstaller.context = context;
         new JSIInstaller().installBinding(javaScriptContextHolder);

Reference: https://github.com/mattermost/mattermost-mobile/blob/main/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.kt

Didn't get the time to test this, but probably should work?

enahum commented 1 month ago

The above works, but I have not tested it with 0.75.x

ishan-chhabra commented 1 month ago

Hi @prathameshmm02 @enahum!

I did try the workaround above but it did not work for me. I still get this error while syncing in turbo.

Error while syncing [Error: provideSyncJson unavailable. Use JSI mode to enable.]

MainApplication.kt

package something.something

import android.app.Application
import android.content.res.Configuration
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.soloader.SoLoader
import java.util.Arrays
import com.facebook.react.bridge.JSIModulePackage
import com.facebook.react.bridge.JSIModule
import com.facebook.react.bridge.JSIModuleSpec
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.JavaScriptContextHolder
import expo.modules.ApplicationLifecycleDispatcher
import expo.modules.ReactNativeHostWrapper
import com.nozbe.watermelondb.jsi.WatermelonDBJSIPackage
import com.facebook.react.ReactInstanceManager
import com.nozbe.watermelondb.jsi.JSIInstaller
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.UiThreadUtil

class MainApplication : Application(), ReactApplication {

  private var listenerAdded = false
  override val reactNativeHost: ReactNativeHost =
      ReactNativeHostWrapper(this, object : DefaultReactNativeHost(this) {
        override fun getPackages(): List<ReactPackage> =
            PackageList(this).packages.apply {
              // Packages that cannot be autolinked yet can be added manually here, for example:
              // add(MyReactNativePackage())
            }

        override fun getJSMainModuleName(): String = "index"

        override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

        override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
        override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
      })

  override val reactHost: ReactHost
    get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost)

    override fun onCreate() {
    super.onCreate()

    SoLoader.init(this, false)
    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
      // If you opted-in for the New Architecture, we load the native entry point for this app.
      load()
    }
    ApplicationLifecycleDispatcher.onApplicationCreate(this)
    registerJSIModules()
  }

    private fun runOnJSQueueThread(action: () -> Unit) {
        reactNativeHost.reactInstanceManager.currentReactContext?.runOnJSQueueThread {
            action()
        } ?: UiThreadUtil.runOnUiThread {
            reactNativeHost.reactInstanceManager.currentReactContext?.runOnJSQueueThread {
                action()
            }
        }
    }

  @Suppress("DEPRECATION")
  private fun registerJSIModules() {
    val reactInstanceManager = reactNativeHost.reactInstanceManager

    if (!listenerAdded) {
        listenerAdded = true
        reactInstanceManager.addReactInstanceEventListener(object : ReactInstanceManager.ReactInstanceEventListener {
          override fun onReactContextInitialized(context: ReactContext) {
              runOnJSQueueThread {
                registerWatermelonJSI(context)
              }
            }
          })
        }
    }

  private fun registerWatermelonJSI(context: ReactContext) {
      val holder = context.javaScriptContextHolder?.get()
      if (holder != null) {
          JSIInstaller.install(context, holder)
      }
  }

  override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
  }
}

I also patched WatermelonDB as follows:

@nozbe+watermelondb+0.27.1.patch

diff --git a/node_modules/@nozbe/watermelondb/native/android-jsi/src/main/java/com/nozbe/watermelondb/jsi/JSIInstaller.java b/node_modules/@nozbe/watermelondb/native/android-jsi/src/main/java/com/nozbe/watermelondb/jsi/JSIInstaller.java
index 055cede..fb7ca33 100755
--- a/node_modules/@nozbe/watermelondb/native/android-jsi/src/main/java/com/nozbe/watermelondb/jsi/JSIInstaller.java
+++ b/node_modules/@nozbe/watermelondb/native/android-jsi/src/main/java/com/nozbe/watermelondb/jsi/JSIInstaller.java
@@ -1,8 +1,8 @@
 package com.nozbe.watermelondb.jsi;

 import android.content.Context;
-class JSIInstaller {
-    static void install(Context context, long javaScriptContextHolder) {
+public class JSIInstaller {
+    public static void install(Context context, long javaScriptContextHolder) {
         JSIInstaller.context = context;
         new JSIInstaller().installBinding(javaScriptContextHolder);

I have also verified that all the changes stated in JSI setup on https://watermelondb.dev/docs/Installation#android-react-native are applied.

Any help will be greatly appreciated. Thank youu! :)

prathameshmm02 commented 1 month ago

@ishan-chhabra Do you have JSI enabled in your adapter?

const adapter = new SQLiteAdapter({
  schema,
  migrations,
  jsi: true,
})
arun-saleth commented 3 weeks ago

@prathameshmm02 i followed step by step.But after that i faced this issue - in android

JSI SQLiteAdapter not available… falling back to asynchronous operation. This will happen if you're using remote debugger, and may happen if you forgot to recompile native app after WatermelonDB update

prathameshmm02 commented 3 weeks ago

Have you followed JSI installation docs in Android section given here? After doing that, recompile your app and it should work fine.

arun-saleth commented 2 weeks ago

How to implement this.it show override nothing error

`// ... import com.nozbe.watermelondb.jsi.WatermelonDBJSIPackage; // ⬅️ This! import com.facebook.react.bridge.JSIModulePackage; // ⬅️ This! // ... private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { // ...

 @Override
 protected JSIModulePackage getJSIModulePackage() {
   return new WatermelonDBJSIPackage(); // ⬅️ This!
 }

} `

aleksey-mukho commented 5 days ago

Looks like this library is no longer supported. Very sad news.