Skip to content

Commit a7f9080

Browse files
cortinicofacebook-github-bot
authored andcommitted
Simplify new app template for bridgeless (#40929)
Summary: Pull Request resolved: #40929 This diff reduces the footprint that bridgeless is imposing on the new app template. Specifically: - I've created a `.toReactHost` method that converts a DefaultReactNativeHost to a DefaultReactHost - I've updated RN Tester to use the same setup as the New App template which reduces code duplication. I also had to remove a couple of `UnstableReactNativeAPI` as those were bleeding in the new app template. I don't think we should ask users to opt-in in `UnstableReactNativeAPI` in the New App template itself as this means that all the apps will get this opt-in. Instead we should keep it only for specific APIs that we want the users to opt into. Changelog: [Internal] [Changed] - Simplify new app template for bridgeless Reviewed By: cipolleschi, luluwu2032 Differential Revision: D50227693 fbshipit-source-id: e86c54d5156cc27f1f898b43ca89c57d5cf148b8
1 parent 50522cf commit a7f9080

File tree

6 files changed

+97
-199
lines changed

6 files changed

+97
-199
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactHost.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import android.os.Bundle
1313
import com.facebook.react.bridge.ReactContext
1414
import com.facebook.react.bridge.queue.ReactQueueConfiguration
1515
import com.facebook.react.common.LifecycleState
16-
import com.facebook.react.common.annotations.UnstableReactNativeAPI
1716
import com.facebook.react.devsupport.interfaces.DevSupportManager
1817
import com.facebook.react.interfaces.TaskInterface
1918
import com.facebook.react.interfaces.fabric.ReactSurface
@@ -26,7 +25,6 @@ import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler
2625
*
2726
* The implementation of this interface should be Thread Safe
2827
*/
29-
@UnstableReactNativeAPI
3028
interface ReactHost {
3129

3230
/** The current [LifecycleState] for React Host */

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHost.kt

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
package com.facebook.react.defaults
99

1010
import android.content.Context
11+
import com.facebook.react.JSEngineResolutionAlgorithm
1112
import com.facebook.react.ReactHost
13+
import com.facebook.react.ReactNativeHost
1214
import com.facebook.react.ReactPackage
1315
import com.facebook.react.bridge.JSBundleLoader
1416
import com.facebook.react.common.annotations.UnstableReactNativeAPI
@@ -18,10 +20,29 @@ import com.facebook.react.runtime.JSCInstance
1820
import com.facebook.react.runtime.ReactHostImpl
1921
import com.facebook.react.runtime.hermes.HermesInstance
2022

21-
@UnstableReactNativeAPI
23+
/**
24+
* A utility class that allows you to simplify the setup of a [ReactHost] for new apps in Open
25+
* Source.
26+
*
27+
* [ReactHost] is an interface responsible of handling the lifecycle of a React Native app when
28+
* running in bridgeless mode.
29+
*/
2230
object DefaultReactHost {
2331
private var reactHost: ReactHost? = null
2432

33+
/**
34+
* Util function to create a default [ReactHost] to be used in your application. This method is
35+
* used by the New App template.
36+
*
37+
* @param context the Android [Context] to use for creating the [ReactHost]
38+
* @param packageList the list of [ReactPackage]s to use for creating the [ReactHost]
39+
* @param jsMainModulePath the path to your app's main module on Metro. Usually `index` or
40+
* `index.<platform>`
41+
* @param jsBundleAssetPath the path to the JS bundle relative to the assets directory. Will be
42+
* composed in a `asset://...` URL
43+
* @param isHermesEnabled whether to use Hermes as the JS engine, default to true.
44+
*/
45+
@OptIn(UnstableReactNativeAPI::class)
2546
@JvmStatic
2647
fun getDefaultReactHost(
2748
context: Context,
@@ -47,13 +68,42 @@ object DefaultReactHost {
4768
// TODO: T164788699 find alternative of accessing ReactHostImpl for initialising reactHost
4869
reactHost =
4970
ReactHostImpl(
50-
context,
51-
defaultReactHostDelegate,
52-
componentFactory,
53-
true,
54-
reactJsExceptionHandler,
55-
true)
71+
context,
72+
defaultReactHostDelegate,
73+
componentFactory,
74+
true,
75+
reactJsExceptionHandler,
76+
true)
77+
.apply {
78+
jsEngineResolutionAlgorithm =
79+
if (isHermesEnabled) {
80+
JSEngineResolutionAlgorithm.HERMES
81+
} else {
82+
JSEngineResolutionAlgorithm.JSC
83+
}
84+
}
5685
}
5786
return reactHost as ReactHost
5887
}
88+
89+
/**
90+
* Util function to create a default [ReactHost] to be used in your application. This method is
91+
* used by the New App template.
92+
*
93+
* This method takes in input a [ReactNativeHost] (bridge-mode) and uses its configuration to
94+
* create an equivalent [ReactHost] (bridgeless-mode).
95+
*
96+
* @param context the Android [Context] to use for creating the [ReactHost]
97+
* @param reactNativeHost the [ReactNativeHost] to use for creating the [ReactHost]
98+
*/
99+
@JvmStatic
100+
fun getDefaultReactHost(
101+
context: Context,
102+
reactNativeHost: ReactNativeHost,
103+
): ReactHost {
104+
require(reactNativeHost is DefaultReactNativeHost) {
105+
"You can call getDefaultReactHost only with instances of DefaultReactNativeHost"
106+
}
107+
return reactNativeHost.toReactHost(context)
108+
}
59109
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactNativeHost.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
package com.facebook.react.defaults
99

1010
import android.app.Application
11+
import android.content.Context
1112
import com.facebook.react.JSEngineResolutionAlgorithm
13+
import com.facebook.react.ReactHost
1214
import com.facebook.react.ReactNativeHost
1315
import com.facebook.react.ReactPackageTurboModuleManagerDelegate
1416
import com.facebook.react.bridge.JSIModulePackage
@@ -68,4 +70,18 @@ protected constructor(
6870
*/
6971
protected open val isHermesEnabled: Boolean?
7072
get() = null
73+
74+
/**
75+
* Converts this [ReactNativeHost] (bridge-mode) to a [ReactHost] (bridgeless-mode).
76+
*
77+
* @param context the Android [Context] to use for creating the [ReactHost]
78+
*/
79+
fun toReactHost(context: Context): ReactHost =
80+
DefaultReactHost.getDefaultReactHost(
81+
context,
82+
packages,
83+
jsMainModuleName,
84+
bundleAssetName ?: "index",
85+
isHermesEnabled ?: true,
86+
)
7187
}

packages/react-native/template/android/app/src/main/java/com/helloworld/MainApplication.kt

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@ import com.facebook.react.ReactApplication
66
import com.facebook.react.ReactHost
77
import com.facebook.react.ReactNativeHost
88
import com.facebook.react.ReactPackage
9-
import com.facebook.react.common.annotations.UnstableReactNativeAPI
109
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
11-
import com.facebook.react.defaults.DefaultReactHost
10+
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
1211
import com.facebook.react.defaults.DefaultReactNativeHost
1312
import com.facebook.soloader.SoLoader
1413

15-
@UnstableReactNativeAPI
1614
class MainApplication : Application(), ReactApplication {
1715

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

3432
override val reactHost: ReactHost
35-
get() =
36-
DefaultReactHost.getDefaultReactHost(
37-
context = this,
38-
packageList = PackageList(this).packages,
39-
jsMainModulePath = "index",
40-
isHermesEnabled = BuildConfig.IS_HERMES_ENABLED)
33+
get() = getDefaultReactHost(this.applicationContext, reactNativeHost)
4134

4235
override fun onCreate() {
4336
super.onCreate()

packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.kt

Lines changed: 22 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,25 @@ package com.facebook.react.uiapp
1010
import android.app.Application
1111
import com.facebook.fbreact.specs.SampleLegacyModule
1212
import com.facebook.fbreact.specs.SampleTurboModule
13-
import com.facebook.react.JSEngineResolutionAlgorithm
1413
import com.facebook.react.ReactApplication
1514
import com.facebook.react.ReactHost
1615
import com.facebook.react.ReactNativeHost
1716
import com.facebook.react.ReactPackage
1817
import com.facebook.react.TurboReactPackage
18+
import com.facebook.react.ViewManagerOnDemandReactPackage
1919
import com.facebook.react.bridge.NativeModule
2020
import com.facebook.react.bridge.ReactApplicationContext
21-
import com.facebook.react.common.annotations.UnstableReactNativeAPI
2221
import com.facebook.react.common.assets.ReactFontManager
23-
import com.facebook.react.common.mapbuffer.ReadableMapBuffer
2422
import com.facebook.react.config.ReactFeatureFlags
25-
import com.facebook.react.defaults.DefaultComponentsRegistry.Companion.register
2623
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
24+
import com.facebook.react.defaults.DefaultReactHost
2725
import com.facebook.react.defaults.DefaultReactNativeHost
28-
import com.facebook.react.fabric.ComponentFactory
29-
import com.facebook.react.interfaces.exceptionmanager.ReactJsExceptionHandler
3026
import com.facebook.react.module.model.ReactModuleInfo
3127
import com.facebook.react.module.model.ReactModuleInfoProvider
32-
import com.facebook.react.runtime.ReactHostImpl
3328
import com.facebook.react.shell.MainReactPackage
3429
import com.facebook.react.uiapp.component.MyLegacyViewManager
3530
import com.facebook.react.uiapp.component.MyNativeViewManager
31+
import com.facebook.react.uimanager.ReactShadowNode
3632
import com.facebook.react.uimanager.ViewManager
3733
import com.facebook.soloader.SoLoader
3834

@@ -95,17 +91,28 @@ class RNTesterApplication : Application(), ReactApplication {
9591
}
9692
}
9793
},
98-
object : ReactPackage {
94+
object : ReactPackage, ViewManagerOnDemandReactPackage {
9995
override fun createNativeModules(
10096
reactContext: ReactApplicationContext
101-
): List<NativeModule> {
102-
return emptyList()
103-
}
97+
): List<NativeModule> = emptyList()
98+
99+
override fun getViewManagerNames(reactContext: ReactApplicationContext) =
100+
listOf("RNTMyNativeView", "RNTMyLegacyNativeView")
104101

105102
override fun createViewManagers(
106103
reactContext: ReactApplicationContext
107104
): List<ViewManager<*, *>> =
108105
listOf(MyNativeViewManager(), MyLegacyViewManager(reactContext))
106+
107+
override fun createViewManager(
108+
reactContext: ReactApplicationContext,
109+
viewManagerName: String
110+
): ViewManager<*, out ReactShadowNode<*>> =
111+
if (viewManagerName == "RNTMyNativeView") {
112+
MyNativeViewManager()
113+
} else {
114+
MyLegacyViewManager(reactContext)
115+
}
109116
})
110117
}
111118

@@ -114,43 +121,15 @@ class RNTesterApplication : Application(), ReactApplication {
114121
}
115122
}
116123

124+
override val reactHost: ReactHost
125+
get() = DefaultReactHost.getDefaultReactHost(this.applicationContext, reactNativeHost)
126+
117127
override fun onCreate() {
118128
ReactFontManager.getInstance().addCustomFont(this, "Rubik", R.font.rubik)
119129
super.onCreate()
120130
SoLoader.init(this, /* native exopackage */ false)
121131
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
122-
load()
132+
load(bridgelessEnabled = true)
123133
}
124134
}
125-
126-
@UnstableReactNativeAPI
127-
override val reactHost: ReactHost by lazy {
128-
// Create an instance of ReactHost to manager the instance of ReactInstance,
129-
// which is similar to how we use ReactNativeHost to manager instance of ReactInstanceManager
130-
val reactHostDelegate = RNTesterReactHostDelegate(applicationContext)
131-
val reactJsExceptionHandler = RNTesterReactJsExceptionHandler()
132-
val componentFactory = ComponentFactory()
133-
register(componentFactory)
134-
ReactHostImpl(
135-
this.applicationContext,
136-
reactHostDelegate,
137-
componentFactory,
138-
true,
139-
reactJsExceptionHandler,
140-
true)
141-
.apply {
142-
jsEngineResolutionAlgorithm =
143-
if (BuildConfig.IS_HERMES_ENABLED_IN_FLAVOR) {
144-
JSEngineResolutionAlgorithm.HERMES
145-
} else {
146-
JSEngineResolutionAlgorithm.JSC
147-
}
148-
reactHostDelegate.reactHost = this
149-
}
150-
}
151-
152-
@UnstableReactNativeAPI
153-
class RNTesterReactJsExceptionHandler : ReactJsExceptionHandler {
154-
override fun reportJsException(errorMap: ReadableMapBuffer?) {}
155-
}
156135
}

0 commit comments

Comments
 (0)