Skip to content

Commit 2d1f3c1

Browse files
cortinicohuntie
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 bfa19cb commit 2d1f3c1

File tree

6 files changed

+96
-199
lines changed

6 files changed

+96
-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,14 +6,12 @@ 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.react.flipper.ReactNativeFlipper
1413
import com.facebook.soloader.SoLoader
1514

16-
@UnstableReactNativeAPI
1715
class MainApplication : Application(), ReactApplication {
1816

1917
override val reactNativeHost: ReactNativeHost =
@@ -33,12 +31,7 @@ class MainApplication : Application(), ReactApplication {
3331
}
3432

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

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

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

Lines changed: 21 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,26 @@ 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
2926
import com.facebook.react.flipper.ReactNativeFlipper.initializeFlipper
30-
import com.facebook.react.interfaces.exceptionmanager.ReactJsExceptionHandler
3127
import com.facebook.react.module.model.ReactModuleInfo
3228
import com.facebook.react.module.model.ReactModuleInfoProvider
33-
import com.facebook.react.runtime.ReactHostImpl
3429
import com.facebook.react.shell.MainReactPackage
3530
import com.facebook.react.uiapp.component.MyLegacyViewManager
3631
import com.facebook.react.uiapp.component.MyNativeViewManager
32+
import com.facebook.react.uimanager.ReactShadowNode
3733
import com.facebook.react.uimanager.ViewManager
3834
import com.facebook.soloader.SoLoader
3935

@@ -96,17 +92,28 @@ class RNTesterApplication : Application(), ReactApplication {
9692
}
9793
}
9894
},
99-
object : ReactPackage {
95+
object : ReactPackage, ViewManagerOnDemandReactPackage {
10096
override fun createNativeModules(
10197
reactContext: ReactApplicationContext
102-
): List<NativeModule> {
103-
return emptyList()
104-
}
98+
): List<NativeModule> = emptyList()
99+
100+
override fun getViewManagerNames(reactContext: ReactApplicationContext) =
101+
listOf("RNTMyNativeView", "RNTMyLegacyNativeView")
105102

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

@@ -115,6 +122,9 @@ class RNTesterApplication : Application(), ReactApplication {
115122
}
116123
}
117124

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

0 commit comments

Comments
 (0)