Skip to content

Simplify new app template for bridgeless #40929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import android.os.Bundle
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.queue.ReactQueueConfiguration
import com.facebook.react.common.LifecycleState
import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.devsupport.interfaces.DevSupportManager
import com.facebook.react.interfaces.TaskInterface
import com.facebook.react.interfaces.fabric.ReactSurface
Expand All @@ -26,7 +25,6 @@ import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler
*
* The implementation of this interface should be Thread Safe
*/
@UnstableReactNativeAPI
interface ReactHost {

/** The current [LifecycleState] for React Host */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
package com.facebook.react.defaults

import android.content.Context
import com.facebook.react.JSEngineResolutionAlgorithm
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.JSBundleLoader
import com.facebook.react.common.annotations.UnstableReactNativeAPI
Expand All @@ -18,10 +20,29 @@ import com.facebook.react.runtime.JSCInstance
import com.facebook.react.runtime.ReactHostImpl
import com.facebook.react.runtime.hermes.HermesInstance

@UnstableReactNativeAPI
/**
* 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.
*/
object DefaultReactHost {
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.<platform>`
* @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.
*/
@OptIn(UnstableReactNativeAPI::class)
@JvmStatic
fun getDefaultReactHost(
context: Context,
Expand All @@ -47,13 +68,42 @@ object DefaultReactHost {
// TODO: T164788699 find alternative of accessing ReactHostImpl for initialising reactHost
reactHost =
ReactHostImpl(
context,
defaultReactHostDelegate,
componentFactory,
true,
reactJsExceptionHandler,
true)
context,
defaultReactHostDelegate,
componentFactory,
true,
reactJsExceptionHandler,
true)
.apply {
jsEngineResolutionAlgorithm =
if (isHermesEnabled) {
JSEngineResolutionAlgorithm.HERMES
} else {
JSEngineResolutionAlgorithm.JSC
}
}
}
return reactHost as ReactHost
}

/**
* Util function to create a default [ReactHost] to be used in your application. This method is
* used by the New App template.
*
* This method takes in input a [ReactNativeHost] (bridge-mode) and uses its configuration to
* create an equivalent [ReactHost] (bridgeless-mode).
*
* @param context the Android [Context] to use for creating the [ReactHost]
* @param reactNativeHost the [ReactNativeHost] to use for creating the [ReactHost]
*/
@JvmStatic
fun getDefaultReactHost(
context: Context,
reactNativeHost: ReactNativeHost,
): ReactHost {
require(reactNativeHost is DefaultReactNativeHost) {
"You can call getDefaultReactHost only with instances of DefaultReactNativeHost"
}
return reactNativeHost.toReactHost(context)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
package com.facebook.react.defaults

import android.app.Application
import android.content.Context
import com.facebook.react.JSEngineResolutionAlgorithm
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackageTurboModuleManagerDelegate
import com.facebook.react.bridge.JSIModulePackage
Expand Down Expand Up @@ -68,4 +70,18 @@ protected constructor(
*/
protected open val isHermesEnabled: Boolean?
get() = null

/**
* Converts this [ReactNativeHost] (bridge-mode) to a [ReactHost] (bridgeless-mode).
*
* @param context the Android [Context] to use for creating the [ReactHost]
*/
fun toReactHost(context: Context): ReactHost =
DefaultReactHost.getDefaultReactHost(
context,
packages,
jsMainModuleName,
bundleAssetName ?: "index",
isHermesEnabled ?: true,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.soloader.SoLoader

@UnstableReactNativeAPI
class MainApplication : Application(), ReactApplication {

override val reactNativeHost: ReactNativeHost =
Expand All @@ -32,12 +30,7 @@ class MainApplication : Application(), ReactApplication {
}

override val reactHost: ReactHost
get() =
DefaultReactHost.getDefaultReactHost(
context = this,
packageList = PackageList(this).packages,
jsMainModulePath = "index",
isHermesEnabled = BuildConfig.IS_HERMES_ENABLED)
get() = getDefaultReactHost(this.applicationContext, reactNativeHost)

override fun onCreate() {
super.onCreate()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,25 @@ package com.facebook.react.uiapp
import android.app.Application
import com.facebook.fbreact.specs.SampleLegacyModule
import com.facebook.fbreact.specs.SampleTurboModule
import com.facebook.react.JSEngineResolutionAlgorithm
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.TurboReactPackage
import com.facebook.react.ViewManagerOnDemandReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.common.assets.ReactFontManager
import com.facebook.react.common.mapbuffer.ReadableMapBuffer
import com.facebook.react.config.ReactFeatureFlags
import com.facebook.react.defaults.DefaultComponentsRegistry.Companion.register
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.fabric.ComponentFactory
import com.facebook.react.interfaces.exceptionmanager.ReactJsExceptionHandler
import com.facebook.react.module.model.ReactModuleInfo
import com.facebook.react.module.model.ReactModuleInfoProvider
import com.facebook.react.runtime.ReactHostImpl
import com.facebook.react.shell.MainReactPackage
import com.facebook.react.uiapp.component.MyLegacyViewManager
import com.facebook.react.uiapp.component.MyNativeViewManager
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager
import com.facebook.soloader.SoLoader

Expand Down Expand Up @@ -95,17 +91,28 @@ class RNTesterApplication : Application(), ReactApplication {
}
}
},
object : ReactPackage {
object : ReactPackage, ViewManagerOnDemandReactPackage {
override fun createNativeModules(
reactContext: ReactApplicationContext
): List<NativeModule> {
return emptyList()
}
): List<NativeModule> = emptyList()

override fun getViewManagerNames(reactContext: ReactApplicationContext) =
listOf("RNTMyNativeView", "RNTMyLegacyNativeView")

override fun createViewManagers(
reactContext: ReactApplicationContext
): List<ViewManager<*, *>> =
listOf(MyNativeViewManager(), MyLegacyViewManager(reactContext))

override fun createViewManager(
reactContext: ReactApplicationContext,
viewManagerName: String
): ViewManager<*, out ReactShadowNode<*>> =
if (viewManagerName == "RNTMyNativeView") {
MyNativeViewManager()
} else {
MyLegacyViewManager(reactContext)
}
})
}

Expand All @@ -114,43 +121,15 @@ class RNTesterApplication : Application(), ReactApplication {
}
}

override val reactHost: ReactHost
get() = DefaultReactHost.getDefaultReactHost(this.applicationContext, reactNativeHost)

override fun onCreate() {
ReactFontManager.getInstance().addCustomFont(this, "Rubik", R.font.rubik)
super.onCreate()
SoLoader.init(this, /* native exopackage */ false)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
load()
load(bridgelessEnabled = true)
}
}

@UnstableReactNativeAPI
override val reactHost: ReactHost by lazy {
// Create an instance of ReactHost to manager the instance of ReactInstance,
// which is similar to how we use ReactNativeHost to manager instance of ReactInstanceManager
val reactHostDelegate = RNTesterReactHostDelegate(applicationContext)
val reactJsExceptionHandler = RNTesterReactJsExceptionHandler()
val componentFactory = ComponentFactory()
register(componentFactory)
ReactHostImpl(
this.applicationContext,
reactHostDelegate,
componentFactory,
true,
reactJsExceptionHandler,
true)
.apply {
jsEngineResolutionAlgorithm =
if (BuildConfig.IS_HERMES_ENABLED_IN_FLAVOR) {
JSEngineResolutionAlgorithm.HERMES
} else {
JSEngineResolutionAlgorithm.JSC
}
reactHostDelegate.reactHost = this
}
}

@UnstableReactNativeAPI
class RNTesterReactJsExceptionHandler : ReactJsExceptionHandler {
override fun reportJsException(errorMap: ReadableMapBuffer?) {}
}
}
Loading