diff --git a/example/.gitignore b/.gitignore similarity index 100% rename from example/.gitignore rename to .gitignore diff --git a/android/.gitkeep b/android/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt new file mode 100644 index 0000000..7b39f08 --- /dev/null +++ b/android/CMakeLists.txt @@ -0,0 +1,74 @@ +# +# Copyright (c) react-native-community +# +# 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) +project(jscruntimefactory) + +set(CMAKE_VERBOSE_MAKEFILE ON) +set (CMAKE_CXX_STANDARD 20) + +string(APPEND CMAKE_CXX_FLAGS + " -fexceptions" + " -frtti" + " -O3" + " -Wno-unused-lambda-capture" + " -DREACT_NATIVE_MINOR_VERSION=${REACT_NATIVE_MINOR_VERSION}" + " -DREACT_NATIVE_PATCH_VERSION=${REACT_NATIVE_PATCH_VERSION}" +) + +include("${REACT_NATIVE_DIR}/ReactAndroid/cmake-utils/folly-flags.cmake") +add_compile_options(${folly_FLAGS}) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") + +set(PACKAGE_NAME "jscruntimefactory") +set(SRC_DIR "${CMAKE_SOURCE_DIR}/src/main/cpp") + +set(COMMON_DIR "${CMAKE_SOURCE_DIR}/../common") +file(GLOB COMMON_SOURCES "${COMMON_DIR}/*.cpp") + +add_library( + ${PACKAGE_NAME} + SHARED + ${COMMON_SOURCES} + "${SRC_DIR}/JSCExecutorFactory.cpp" + "${SRC_DIR}/OnLoad.cpp" +) + +# includes + +target_include_directories( + ${PACKAGE_NAME} + PRIVATE + "${COMMON_DIR}" + "${REACT_NATIVE_DIR}/ReactCommon" + "${REACT_NATIVE_DIR}/ReactCommon/jsiexecutor" + "${REACT_NATIVE_DIR}/ReactAndroid/src/main/jni" +) + +# find libraries + +find_library( + LOG_LIB + log +) +find_package(fbjni REQUIRED CONFIG) +find_package(jsc-android REQUIRED CONFIG) +find_package(ReactAndroid REQUIRED CONFIG) + +# link to shared libraries + +target_link_libraries( + ${PACKAGE_NAME} + ${LOG_LIB} + android + fbjni::fbjni + jsc-android::jsc + ReactAndroid::jsi + ReactAndroid::reactnative +) diff --git a/android/build.gradle.kts b/android/build.gradle.kts new file mode 100644 index 0000000..ad68469 --- /dev/null +++ b/android/build.gradle.kts @@ -0,0 +1,146 @@ +/* + * Copyright (c) react-native-community + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import com.android.build.gradle.internal.tasks.factory.dependsOn +import groovy.json.JsonSlurper +import org.apache.tools.ant.taskdefs.condition.Os +import java.util.Properties + +val reactNativeDir = findNodePackageDir("react-native") +val reactNativeManifest = file("${reactNativeDir}/package.json") +val reactNativeManifestAsJson = JsonSlurper().parseText(reactNativeManifest.readText()) as Map<*, *> +val reactNativeVersion = reactNativeManifestAsJson["version"] as String +val (major, minor, patch) = reactNativeVersion.split(".") +val rnMinorVersion = minor.toInt() +val rnPatchVersion = patch.toInt() +val prefabHeadersDir = file("${layout.buildDirectory.get()}/prefab-headers") + +if (findProperty("hermesEnabled") == "true") { + throw GradleException("Please disable Hermes because Hermes will transform the JavaScript bundle as bytecode bundle.\n") +} + +val reactProperties = Properties().apply { + file("${reactNativeDir}/ReactAndroid/gradle.properties").inputStream().use { load(it) } +} + +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") +} + +android { + namespace = "io.github.reactnativecommunity.javascriptcore" + compileSdk = safeExtGet("compileSdkVersion", 35) + + if (rootProject.hasProperty("ndkPath")) { + ndkPath = rootProject.extra["ndkPath"].toString() + } + if (rootProject.hasProperty("ndkVersion")) { + ndkVersion = rootProject.extra["ndkVersion"].toString() + } + + defaultConfig { + minSdk = safeExtGet("minSdkVersion", 24) + + @Suppress("UnstableApiUsage") + externalNativeBuild.cmake { + arguments += listOf( + "-DANDROID_STL=c++_shared", + "-DREACT_NATIVE_DIR=${reactNativeDir.toPlatformString()}", + "-DREACT_NATIVE_MINOR_VERSION=${rnMinorVersion}", + "-DREACT_NATIVE_PATCH_VERSION=${rnPatchVersion}", + ) + targets("jscruntimefactory") + abiFilters(*reactNativeArchitectures().toTypedArray()) + } + } + + externalNativeBuild { + cmake { + path("CMakeLists.txt") + } + } + + lint { + abortOnError = false + targetSdk = safeExtGet("targetSdkVersion", 35) + } + + packaging { + // Uncomment to keep debug symbols + // doNotStrip.add("**/*.so") + + jniLibs { + excludes.add("**/libc++_shared.so") + excludes.add("**/libfbjni.so") + excludes.add("**/libjsi.so") + excludes.add("**/libreactnative.so") + pickFirsts.add("**/libjscruntimefactory.so") + } + } + + buildFeatures { + prefab = true + prefabPublishing = true + } + + prefab { + register("jscruntimefactory") { + headers = file(prefabHeadersDir).absolutePath + } + } +} + +dependencies { + implementation("com.facebook.yoga:proguard-annotations:1.19.0") + compileOnly("com.facebook.fbjni:fbjni:0.7.0") + implementation("com.facebook.react:react-android") + + //noinspection GradleDynamicVersion + implementation("io.github.react-native-community:jsc-android:2026004.+") +} + +val createPrefabHeadersDir by + tasks.registering { + prefabHeadersDir.mkdirs() + } + +tasks.named("preBuild").dependsOn(createPrefabHeadersDir) + +private fun findNodePackageDir(packageName: String, absolute: Boolean = true): File { + val nodeCommand = listOf("node", "--print", "require.resolve('${packageName}/package.json')") + val proc = ProcessBuilder(nodeCommand) + .directory(rootDir) + .start() + val error = proc.errorStream.bufferedReader().readText() + if (error.isNotEmpty()) { + val nodeCommandString = nodeCommand.joinToString(" ") + throw GradleException( + "findNodePackageDir() execution failed - nodeCommand[$nodeCommandString]\n$error" + ) + } + val dir = File(proc.inputStream.bufferedReader().readText().trim()).parentFile + return if (absolute) dir.absoluteFile else dir +} + +private fun File.toPlatformString(): String { + var result = path.toString() + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + result = result.replace(File.separatorChar, '/') + } + return result +} + +private fun reactNativeArchitectures(): List { + val value = findProperty("reactNativeArchitectures") + return value?.toString()?.split(",") ?: listOf("armeabi-v7a", "x86", "x86_64", "arm64-v8a") +} + +private fun safeExtGet(prop: String, fallback: T): T { + @Suppress("UNCHECKED_CAST") + return rootProject.extra[prop] as? T ?: fallback +} diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a2f47b6 --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/android/src/main/cpp/JSCExecutorFactory.cpp b/android/src/main/cpp/JSCExecutorFactory.cpp new file mode 100644 index 0000000..045c36c --- /dev/null +++ b/android/src/main/cpp/JSCExecutorFactory.cpp @@ -0,0 +1,48 @@ +/* + * 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 "JSCExecutorFactory.h" + +#include +#include +#include + +namespace facebook::react { + +namespace { + +class JSCExecutorFactory : public JSExecutorFactory { +public: + std::unique_ptr + createJSExecutor(std::shared_ptr delegate, + std::shared_ptr jsQueue) override { + auto installBindings = [](jsi::Runtime &runtime) { + react::Logger androidLogger = + static_cast( + &reactAndroidLoggingHook); + react::bindNativeLogger(runtime, androidLogger); + }; + return std::make_unique(jsc::makeJSCRuntime(), delegate, + JSIExecutor::defaultTimeoutInvoker, + installBindings); + } +}; + +} // namespace + +// static +jni::local_ref +JSCExecutorHolder::initHybrid(jni::alias_ref, ReadableNativeMap *) { + // This is kind of a weird place for stuff, but there's no other + // good place for initialization which is specific to JSC on + // Android. + JReactMarker::setLogPerfMarkerIfNeeded(); + // TODO mhorowitz T28461666 fill in some missing nice to have glue + return makeCxxInstance(std::make_unique()); +} + +} // namespace facebook::react diff --git a/android/src/main/cpp/JSCExecutorFactory.h b/android/src/main/cpp/JSCExecutorFactory.h new file mode 100644 index 0000000..739ecc0 --- /dev/null +++ b/android/src/main/cpp/JSCExecutorFactory.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include "JSCRuntime.h" + +namespace facebook::react { + +// This is not like JSCJavaScriptExecutor, which calls JSC directly. This uses +// JSIExecutor with JSCRuntime. +class JSCExecutorHolder + : public jni::HybridClass { +public: + static constexpr auto kJavaDescriptor = + "Lio/github/reactnativecommunity/javascriptcore/JSCExecutor;"; + + static jni::local_ref initHybrid(jni::alias_ref, + ReadableNativeMap *); + + static void registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JSCExecutorHolder::initHybrid), + }); + } + +private: + friend HybridBase; + using HybridBase::HybridBase; +}; + +} // namespace facebook::react diff --git a/android/src/main/cpp/JSCRuntimeFactory.h b/android/src/main/cpp/JSCRuntimeFactory.h new file mode 100644 index 0000000..394fa47 --- /dev/null +++ b/android/src/main/cpp/JSCRuntimeFactory.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include "JSCRuntime.h" + +namespace facebook::react { + +class JSCRuntimeFactory + : public jni::HybridClass { +public: + static constexpr auto kJavaDescriptor = + "Lio/github/reactnativecommunity/javascriptcore/JSCRuntimeFactory;"; + + static jni::local_ref initHybrid(jni::alias_ref) { + return makeCxxInstance(); + } + + static void registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JSCRuntimeFactory::initHybrid), + }); + } + + std::unique_ptr + createJSRuntime(std::shared_ptr msgQueueThread) noexcept { + return std::make_unique(jsc::makeJSCRuntime()); + } + +private: + friend HybridBase; + using HybridBase::HybridBase; +}; + +} // namespace facebook::react diff --git a/android/src/main/cpp/OnLoad.cpp b/android/src/main/cpp/OnLoad.cpp new file mode 100644 index 0000000..9754852 --- /dev/null +++ b/android/src/main/cpp/OnLoad.cpp @@ -0,0 +1,18 @@ +/* + * 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 "JSCExecutorFactory.h" +#include "JSCRuntimeFactory.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { + return facebook::jni::initialize(vm, [] { + facebook::react::JSCExecutorHolder::registerNatives(); + facebook::react::JSCRuntimeFactory::registerNatives(); + }); +} diff --git a/android/src/main/java/io/github/reactnativecommunity/javascriptcore/JSCExecutor.kt b/android/src/main/java/io/github/reactnativecommunity/javascriptcore/JSCExecutor.kt new file mode 100644 index 0000000..5a9ebe4 --- /dev/null +++ b/android/src/main/java/io/github/reactnativecommunity/javascriptcore/JSCExecutor.kt @@ -0,0 +1,36 @@ +/* + * 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 io.github.reactnativecommunity.javascriptcore + +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.bridge.JavaScriptExecutor +import com.facebook.react.bridge.ReadableNativeMap +import com.facebook.soloader.SoLoader + +@DoNotStrip +internal class JSCExecutor(jscConfig: ReadableNativeMap) : + JavaScriptExecutor(initHybrid(jscConfig)) { + override fun getName(): String { + return "JSCExecutor" + } + + private companion object { + init { + loadLibrary() + } + + @JvmStatic + @Throws(UnsatisfiedLinkError::class) + fun loadLibrary() { + SoLoader.loadLibrary("jscruntimefactory") + } + + @JvmStatic private external fun initHybrid(jscConfig: ReadableNativeMap): HybridData + } +} diff --git a/android/src/main/java/io/github/reactnativecommunity/javascriptcore/JSCExecutorFactory.kt b/android/src/main/java/io/github/reactnativecommunity/javascriptcore/JSCExecutorFactory.kt new file mode 100644 index 0000000..e3f5d32 --- /dev/null +++ b/android/src/main/java/io/github/reactnativecommunity/javascriptcore/JSCExecutorFactory.kt @@ -0,0 +1,38 @@ +/* + * 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 io.github.reactnativecommunity.javascriptcore + +import com.facebook.react.bridge.JavaScriptExecutor +import com.facebook.react.bridge.JavaScriptExecutorFactory +import com.facebook.react.bridge.WritableNativeMap + +@Suppress("Unused") +class JSCExecutorFactory(private val appName: String, private val deviceName: String) : + JavaScriptExecutorFactory { + + @Throws(Exception::class) + override fun create(): JavaScriptExecutor { + val jscConfig = + WritableNativeMap().apply { + putString("OwnerIdentity", "ReactNative") + putString("AppIdentity", appName) + putString("DeviceIdentity", deviceName) + } + return JSCExecutor(jscConfig) + } + + override fun startSamplingProfiler() { + throw UnsupportedOperationException("Starting sampling profiler not supported on ${toString()}") + } + + override fun stopSamplingProfiler(filename: String) { + throw UnsupportedOperationException("Stopping sampling profiler not supported on ${toString()}") + } + + override fun toString(): String = "JSIExecutor+JSCRuntime" +} diff --git a/android/src/main/java/io/github/reactnativecommunity/javascriptcore/JSCPackage.kt b/android/src/main/java/io/github/reactnativecommunity/javascriptcore/JSCPackage.kt new file mode 100644 index 0000000..92ce1b9 --- /dev/null +++ b/android/src/main/java/io/github/reactnativecommunity/javascriptcore/JSCPackage.kt @@ -0,0 +1,24 @@ +/* + * 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 io.github.reactnativecommunity.javascriptcore + +import com.facebook.react.ReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.uimanager.ViewManager + +@Suppress("Unused") +class JSCPackage : ReactPackage { + override fun createNativeModules(reactContext: ReactApplicationContext): List { + return emptyList() + } + + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return emptyList() + } +} diff --git a/android/src/main/java/io/github/reactnativecommunity/javascriptcore/JSCRuntimeFactory.kt b/android/src/main/java/io/github/reactnativecommunity/javascriptcore/JSCRuntimeFactory.kt new file mode 100644 index 0000000..4956e6e --- /dev/null +++ b/android/src/main/java/io/github/reactnativecommunity/javascriptcore/JSCRuntimeFactory.kt @@ -0,0 +1,26 @@ +/* + * 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 io.github.reactnativecommunity.javascriptcore + +import com.facebook.jni.HybridData +import com.facebook.jni.annotations.DoNotStrip +import com.facebook.jni.annotations.DoNotStripAny +import com.facebook.react.runtime.JSRuntimeFactory +import com.facebook.soloader.SoLoader + +@Suppress("Unused") +@DoNotStripAny +class JSCRuntimeFactory : JSRuntimeFactory(initHybrid()) { + private companion object { + init { + SoLoader.loadLibrary("jscruntimefactory") + } + + @DoNotStrip @JvmStatic private external fun initHybrid(): HybridData + } +} diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 1df1b22..605b5eb 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -105,6 +105,21 @@ android { proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } + + androidComponents { + onVariants(selector().all()) { + packaging.jniLibs.excludes.add("**/libjsctooling.so") + packaging.jniLibs.pickFirsts.set([ + "**/libfbjni.so", + "**/libreactnative.so", + "**/libjsi.so", + "**/libc++_shared.so", + "**/libjsc.so", + // overwrites pickFirsts from RNGP and removes libjsctooling.so from pickFirsts + // "**/libjsctooling.so" + ]) + } + } } dependencies { diff --git a/example/android/app/src/main/java/com/jscexample/JSCReactHost.kt b/example/android/app/src/main/java/com/jscexample/JSCReactHost.kt new file mode 100644 index 0000000..133c06c --- /dev/null +++ b/example/android/app/src/main/java/com/jscexample/JSCReactHost.kt @@ -0,0 +1,103 @@ +/* + * 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.jscexample + +import android.content.Context +import com.facebook.react.ReactHost +import com.facebook.react.ReactPackage +import com.facebook.react.bridge.JSBundleLoader +import com.facebook.react.bridge.ReactContext +import com.facebook.react.common.annotations.UnstableReactNativeAPI +import com.facebook.react.common.build.ReactBuildConfig +import com.facebook.react.defaults.DefaultComponentsRegistry +import com.facebook.react.defaults.DefaultReactHostDelegate +import com.facebook.react.defaults.DefaultTurboModuleManagerDelegate +import com.facebook.react.fabric.ComponentFactory +import com.facebook.react.runtime.ReactHostImpl +import com.facebook.react.runtime.cxxreactpackage.CxxReactPackage +import io.github.reactnativecommunity.javascriptcore.JSCRuntimeFactory + +/** + * A utility class that allows you to simplify the setup of a [ReactHost] for new apps in Open + * Source. + * + * [ReactHost] is an interface responsible of handling the lifecycle of a React Native app when + * running in bridgeless mode. + */ +internal object JSCReactHost { + private var reactHost: ReactHost? = null + + /** + * Util function to create a default [ReactHost] to be used in your application. This method is + * used by the New App template. + * + * @param context the Android [Context] to use for creating the [ReactHost] + * @param packageList the list of [ReactPackage]s to use for creating the [ReactHost] + * @param jsMainModulePath the path to your app's main module on Metro. Usually `index` or + * `index.` + * @param jsBundleAssetPath the path to the JS bundle relative to the assets directory. Will be + * composed in a `asset://...` URL + * @param isHermesEnabled whether to use Hermes as the JS engine, default to true. + * @param useDevSupport whether to enable dev support, default to ReactBuildConfig.DEBUG. + * @param cxxReactPackageProviders a list of cxxreactpackage providers (to register c++ turbo + * modules) + * @param jsBundleLoader a [JSBundleLoader] to use for creating the [ReactHost] + * @param exceptionHandler Callback that can be used by React Native host applications to react to + * exceptions thrown by the internals of React Native. + * + * TODO(T186951312): Should this be @UnstableReactNativeAPI? + */ + @OptIn(UnstableReactNativeAPI::class) + fun getJSCReactHost( + context: Context, + packageList: List, + jsMainModulePath: String = "index", + jsBundleAssetPath: String = "index", + jsBundleFilePath: String? = null, + useDevSupport: Boolean = ReactBuildConfig.DEBUG, + cxxReactPackageProviders: List<(ReactContext) -> CxxReactPackage> = emptyList(), + exceptionHandler: (Exception) -> Unit = { throw it }, + ): ReactHost { + if (reactHost == null) { + + val bundleLoader = + if (jsBundleFilePath != null) { + if (jsBundleFilePath.startsWith("assets://")) { + JSBundleLoader.createAssetLoader(context, jsBundleFilePath, true) + } else { + JSBundleLoader.createFileLoader(jsBundleFilePath) + } + } else { + JSBundleLoader.createAssetLoader(context, "assets://$jsBundleAssetPath", true) + } + val jsRuntimeFactory = JSCRuntimeFactory() + val defaultTmmDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder() + cxxReactPackageProviders.forEach { defaultTmmDelegateBuilder.addCxxReactPackage(it) } + val defaultReactHostDelegate = + DefaultReactHostDelegate( + jsMainModulePath = jsMainModulePath, + jsBundleLoader = bundleLoader, + reactPackages = packageList, + jsRuntimeFactory = jsRuntimeFactory, + turboModuleManagerDelegateBuilder = defaultTmmDelegateBuilder, + exceptionHandler = exceptionHandler) + val componentFactory = ComponentFactory() + DefaultComponentsRegistry.register(componentFactory) + // TODO: T164788699 find alternative of accessing ReactHostImpl for initialising reactHost + reactHost = + ReactHostImpl( + context, + defaultReactHostDelegate, + componentFactory, + true /* allowPackagerServerAccess */, + useDevSupport, + ) + } + return reactHost as ReactHost + } +} diff --git a/example/android/app/src/main/java/com/jscexample/MainApplication.kt b/example/android/app/src/main/java/com/jscexample/MainApplication.kt index 4f3f808..4724ef3 100644 --- a/example/android/app/src/main/java/com/jscexample/MainApplication.kt +++ b/example/android/app/src/main/java/com/jscexample/MainApplication.kt @@ -6,11 +6,13 @@ import com.facebook.react.ReactApplication import com.facebook.react.ReactHost import com.facebook.react.ReactNativeHost import com.facebook.react.ReactPackage +import com.facebook.react.bridge.JavaScriptExecutorFactory import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load -import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost import com.facebook.react.defaults.DefaultReactNativeHost +import com.facebook.react.modules.systeminfo.AndroidInfoHelpers import com.facebook.react.soloader.OpenSourceMergedSoMapping import com.facebook.soloader.SoLoader +import io.github.reactnativecommunity.javascriptcore.JSCExecutorFactory class MainApplication : Application(), ReactApplication { @@ -28,10 +30,22 @@ class MainApplication : Application(), ReactApplication { override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED + + override fun getJavaScriptExecutorFactory(): JavaScriptExecutorFactory = + JSCExecutorFactory(packageName, AndroidInfoHelpers.getFriendlyDeviceName()) + } } override val reactHost: ReactHost - get() = getDefaultReactHost(applicationContext, reactNativeHost) + get() { + return JSCReactHost.getJSCReactHost( + context = applicationContext, + packageList = PackageList(reactNativeHost).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + }, + ) + } override fun onCreate() { super.onCreate() diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 5e24e3a..ba399ff 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -36,4 +36,4 @@ newArchEnabled=true # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. -hermesEnabled=true +hermesEnabled=false diff --git a/example/react-native.config.js b/example/react-native.config.js new file mode 100644 index 0000000..8e4ed66 --- /dev/null +++ b/example/react-native.config.js @@ -0,0 +1,17 @@ +const path = require('path'); + +const pkg = require('../package.json'); + +module.exports = { + dependencies: { + [pkg.name]: { + root: path.join(__dirname, '..'), + platforms: { + android: { + cmakeListsPath: path.join(__dirname, '..', 'android', 'CMakeLists.txt'), + }, + ios: null, + }, + }, + }, +};