diff --git a/packages/react-native/ReactAndroid/build.gradle b/packages/react-native/ReactAndroid/build.gradle index 29f34c4ccdc504..c4cede92f5bb7d 100644 --- a/packages/react-native/ReactAndroid/build.gradle +++ b/packages/react-native/ReactAndroid/build.gradle @@ -512,6 +512,7 @@ android { "rninstance", "hermesinstancejni", "uimanagerjni", + "jscinstance", // prefab targets "reactnativejni", "react_render_debug", diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/JSCInstance.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/JSCInstance.java new file mode 100644 index 00000000000000..117425a88021db --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/JSCInstance.java @@ -0,0 +1,27 @@ +/* + * 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.bridgeless; + +import com.facebook.infer.annotation.Nullsafe; +import com.facebook.jni.HybridData; +import com.facebook.jni.annotations.DoNotStrip; +import com.facebook.soloader.SoLoader; + +@Nullsafe(Nullsafe.Mode.LOCAL) +public class JSCInstance extends JSEngineInstance { + static { + SoLoader.loadLibrary("jscinstance"); + } + + @DoNotStrip + protected static native HybridData initHybrid(); + + public JSCInstance() { + super(initHybrid()); + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactHost.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactHost.java index 5f1eba3764e43e..35f671c4f6486f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactHost.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactHost.java @@ -22,6 +22,7 @@ import com.facebook.infer.annotation.Nullsafe; import com.facebook.infer.annotation.ThreadConfined; import com.facebook.infer.annotation.ThreadSafe; +import com.facebook.react.JSEngineResolutionAlgorithm; import com.facebook.react.MemoryPressureRouter; import com.facebook.react.ReactInstanceEventListener; import com.facebook.react.bridge.Callback; @@ -122,6 +123,7 @@ public class ReactHost implements ReactHostInterface { private static final AtomicInteger mCounter = new AtomicInteger(0); private final int mId = mCounter.getAndIncrement(); + private @Nullable JSEngineResolutionAlgorithm mJSEngineResolutionAlgorithm = null; public ReactHost( Context context, @@ -1504,4 +1506,13 @@ private void oldDestroyReactInstanceAndContext(final String callingMethod, final } } } + + public void setJSEngineResolutionAlgorithm( + @Nullable JSEngineResolutionAlgorithm jsEngineResolutionAlgorithm) { + mJSEngineResolutionAlgorithm = jsEngineResolutionAlgorithm; + } + + public @Nullable JSEngineResolutionAlgorithm getJSEngineResolutionAlgorithm() { + return mJSEngineResolutionAlgorithm; + } } diff --git a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt index ea61441a641ba1..4f862d383a5024 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt @@ -120,6 +120,7 @@ add_react_android_subdir(src/main/jni/react/hermes/reactexecutor) add_react_android_subdir(src/main/jni/react/hermes/instrumentation/) add_react_android_subdir(src/main/jni/react/bridgeless/jni) add_react_android_subdir(src/main/jni/react/bridgeless/hermes/jni) +add_react_android_subdir(src/main/jni/react/bridgeless/jsc/jni) # GTest dependencies add_executable(reactnative_unittest diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jsc/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jsc/jni/CMakeLists.txt new file mode 100644 index 00000000000000..fed3a3cb824305 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jsc/jni/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +add_compile_options(-fvisibility=hidden -fexceptions -frtti) + +file(GLOB jscinstance_SRC CONFIGURE_DEPENDS "*.cpp") +add_library(jscinstance SHARED ${jscinstance_SRC}) + +target_include_directories(jscinstance PUBLIC .) + +target_link_libraries( + jscinstance + bridgeless + jscruntime + fbjni + reactnativejni +) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jsc/jni/OnLoad.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jsc/jni/OnLoad.cpp new file mode 100644 index 00000000000000..01c982e8c6b1e2 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jsc/jni/OnLoad.cpp @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include + +namespace facebook::react { + +class JSCInstance : public jni::HybridClass { + public: + static constexpr auto kJavaDescriptor = + "Lcom/facebook/react/bridgeless/JSCInstance;"; + + static jni::local_ref initHybrid(jni::alias_ref) { + return makeCxxInstance(); + } + + static void registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JSCInstance::initHybrid), + }); + } + + std::unique_ptr createJSRuntime() noexcept { + return jsc::makeJSCRuntime(); + } + + private: + friend HybridBase; + using HybridBase::HybridBase; +}; + +} // namespace facebook::react + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { + return facebook::jni::initialize( + vm, [] { facebook::react::JSCInstance::registerNatives(); }); +} diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java index adc6bec6311558..14aa96cb0f5512 100644 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java @@ -10,6 +10,7 @@ import android.app.Application; import androidx.annotation.NonNull; import com.facebook.fbreact.specs.SampleTurboModule; +import com.facebook.react.JSEngineResolutionAlgorithm; import com.facebook.react.ReactApplication; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; @@ -144,11 +145,18 @@ public void onCreate() { if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { DefaultNewArchitectureEntryPoint.load(); } - ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); + if (ReactFeatureFlags.enableBridgelessArchitecture) { + // TODO: initialize Flipper for Bridgeless + } else { + ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); + } } @Override public ReactNativeHost getReactNativeHost() { + if (ReactFeatureFlags.enableBridgelessArchitecture) { + throw new RuntimeException("Should not use ReactNativeHost when Bridgeless enabled"); + } return mReactNativeHost; } @@ -173,6 +181,11 @@ public ReactHostInterface reactHostInterface() { true, reactJsExceptionHandler, true); + if (BuildConfig.IS_HERMES_ENABLED_IN_FLAVOR) { + mReactHost.setJSEngineResolutionAlgorithm(JSEngineResolutionAlgorithm.HERMES); + } else { + mReactHost.setJSEngineResolutionAlgorithm(JSEngineResolutionAlgorithm.JSC); + } reactHostDelegate.setReactHost(mReactHost); } return mReactHost; diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterReactHostDelegate.java b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterReactHostDelegate.java index 42855ddfa6f386..ef3eb92712d8f0 100644 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterReactHostDelegate.java +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterReactHostDelegate.java @@ -11,6 +11,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.facebook.fbreact.specs.SampleTurboModule; +import com.facebook.react.JSEngineResolutionAlgorithm; import com.facebook.react.ReactPackage; import com.facebook.react.ReactPackageTurboModuleManagerDelegate; import com.facebook.react.TurboReactPackage; @@ -18,6 +19,7 @@ import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridgeless.BindingsInstaller; +import com.facebook.react.bridgeless.JSCInstance; import com.facebook.react.bridgeless.JSEngineInstance; import com.facebook.react.bridgeless.ReactHost; import com.facebook.react.bridgeless.ReactHostDelegate; @@ -77,7 +79,11 @@ public ReactPackageTurboModuleManagerDelegate.Builder getTurboModuleManagerDeleg @Override public JSEngineInstance getJSEngineInstance() { - return new HermesInstance(); + if (mReactHost.getJSEngineResolutionAlgorithm() == JSEngineResolutionAlgorithm.JSC) { + return new JSCInstance(); + } else { + return new HermesInstance(); + } } @Override