expo-dev-launcher 4.0.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/android/build.gradle +1 -1
  3. package/android/src/debug/java/expo/modules/devlauncher/DevLauncherController.kt +43 -16
  4. package/android/src/debug/java/expo/modules/devlauncher/DevLauncherPackageDelegate.kt +1 -1
  5. package/android/src/debug/java/expo/modules/devlauncher/helpers/DevLauncherReactUtils.kt +158 -46
  6. package/android/src/debug/java/expo/modules/devlauncher/launcher/DevLauncherActivity.kt +10 -8
  7. package/android/src/debug/java/expo/modules/devlauncher/launcher/DevLauncherNetworkInterceptor.kt +12 -11
  8. package/android/src/debug/java/expo/modules/devlauncher/launcher/DevLauncherReactHost.kt +109 -0
  9. package/android/src/debug/java/expo/modules/devlauncher/launcher/{DevLauncherClientHost.kt → DevLauncherReactNativeHost.kt} +2 -2
  10. package/android/src/debug/java/expo/modules/devlauncher/launcher/errors/DevLauncherErrorActivity.kt +1 -1
  11. package/android/src/debug/java/expo/modules/devlauncher/launcher/errors/DevLauncherUncaughtExceptionHandler.kt +4 -3
  12. package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherAppLoader.kt +6 -6
  13. package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherAppLoaderFactory.kt +2 -3
  14. package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherExpoAppLoader.kt +2 -2
  15. package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherLocalAppLoader.kt +2 -2
  16. package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherPublishedAppLoader.kt +2 -2
  17. package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherReactNativeAppLoader.kt +2 -2
  18. package/android/src/debug/java/expo/modules/devlauncher/react/DevLauncherDevSupportManagerSwapper.kt +119 -57
  19. package/android/src/main/java/com/facebook/react/devsupport/NonFinalBridgeDevSupportManager.java +273 -0
  20. package/android/src/main/java/com/facebook/react/runtime/NonFinalBridgelessDevSupportManager.java +177 -0
  21. package/android/src/main/java/expo/modules/devlauncher/launcher/DevLauncherControllerInterface.kt +4 -4
  22. package/android/src/react-native-74/debug/expo/modules/devlauncher/rncompatibility/DevLauncherBridgeDevSupportManager.kt +75 -0
  23. package/android/src/react-native-74/debug/expo/modules/devlauncher/rncompatibility/DevLauncherBridgelessDevSupportManager.kt +55 -0
  24. package/android/src/react-native-74/debug/expo/modules/devlauncher/rncompatibility/DevLauncherDevSupportManagerFactory.kt +3 -3
  25. package/android/src/release/java/expo/modules/devlauncher/DevLauncherController.kt +13 -9
  26. package/android/src/release/java/expo/modules/devlauncher/launcher/DevLauncherReactHost.kt +11 -0
  27. package/android/src/release/java/expo/modules/devlauncher/launcher/{DevLauncherClientHost.kt → DevLauncherReactNativeHost.kt} +1 -1
  28. package/android/src/testDebug/java/expo/modules/devlauncher/DevLauncherControllerTest.kt +3 -3
  29. package/android/src/testDebug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherAppLoaderFactoryTest.kt +3 -4
  30. package/package.json +3 -3
  31. package/android/src/react-native-74/debug/expo/modules/devlauncher/rncompatibility/DevLauncherDevSupportManager.kt +0 -286
@@ -0,0 +1,109 @@
1
+ package expo.modules.devlauncher.launcher
2
+
3
+ import android.app.Application
4
+ import com.facebook.react.JSEngineResolutionAlgorithm
5
+ import com.facebook.react.ReactHost
6
+ import com.facebook.react.ReactPackage
7
+ import com.facebook.react.bridge.JSBundleLoader
8
+ import com.facebook.react.common.annotations.UnstableReactNativeAPI
9
+ import com.facebook.react.defaults.DefaultComponentsRegistry
10
+ import com.facebook.react.defaults.DefaultReactHostDelegate
11
+ import com.facebook.react.defaults.DefaultTurboModuleManagerDelegate
12
+ import com.facebook.react.fabric.ComponentFactory
13
+ import com.facebook.react.interfaces.exceptionmanager.ReactJsExceptionHandler
14
+ import com.facebook.react.runtime.JSCInstance
15
+ import com.facebook.react.runtime.ReactHostImpl
16
+ import com.facebook.react.runtime.hermes.HermesInstance
17
+ import com.facebook.react.shell.MainReactPackage
18
+ import com.facebook.soloader.SoLoader
19
+ import devmenu.com.th3rdwave.safeareacontext.SafeAreaProviderManager
20
+ import expo.modules.adapters.react.ModuleRegistryAdapter
21
+ import expo.modules.adapters.react.ReactModuleRegistryProvider
22
+ import expo.modules.devlauncher.DevLauncherController
23
+ import expo.modules.devlauncher.DevLauncherPackage
24
+ import expo.modules.devlauncher.helpers.findDevMenuPackage
25
+ import expo.modules.devlauncher.helpers.findPackagesWithDevMenuExtension
26
+ import expo.modules.devlauncher.helpers.injectDebugServerHost
27
+ import expo.modules.devmenu.modules.DevMenuPreferences
28
+ import expo.modules.kotlin.ModulesProvider
29
+
30
+ object DevLauncherReactHost {
31
+
32
+ @OptIn(UnstableReactNativeAPI::class)
33
+ fun create(application: Application, launcherIp: String?): ReactHost {
34
+ val jsBundleAssetPath = "expo_dev_launcher_android.bundle"
35
+ val jsBundleLoader =
36
+ JSBundleLoader.createAssetLoader(application, "assets://$jsBundleAssetPath", true)
37
+ val jsResolutionAlgorithm = createJSEngineResolutionAlgorithm(application)
38
+ val jsRuntimeFactory = if (jsResolutionAlgorithm == JSEngineResolutionAlgorithm.JSC) {
39
+ JSCInstance()
40
+ } else {
41
+ HermesInstance()
42
+ }
43
+ val jsMainModuleName = "index"
44
+ val defaultReactHostDelegate =
45
+ DefaultReactHostDelegate(
46
+ jsMainModulePath = jsMainModuleName,
47
+ jsBundleLoader = jsBundleLoader,
48
+ reactPackages = getPackages(application),
49
+ jsRuntimeFactory = jsRuntimeFactory,
50
+ turboModuleManagerDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder()
51
+ )
52
+ val reactJsExceptionHandler = ReactJsExceptionHandler { _ -> }
53
+ val componentFactory = ComponentFactory()
54
+ DefaultComponentsRegistry.register(componentFactory)
55
+ val useDeveloperSupport = launcherIp != null
56
+ val reactHost = ReactHostImpl(
57
+ application,
58
+ defaultReactHostDelegate,
59
+ componentFactory,
60
+ useDeveloperSupport,
61
+ reactJsExceptionHandler,
62
+ useDeveloperSupport
63
+ )
64
+ .apply {
65
+ jsEngineResolutionAlgorithm = jsResolutionAlgorithm
66
+ }
67
+ if (useDeveloperSupport) {
68
+ injectDebugServerHost(application.applicationContext, reactHost, launcherIp!!, jsMainModuleName)
69
+ }
70
+ return reactHost
71
+ }
72
+
73
+ private fun getPackages(application: Application): List<ReactPackage> {
74
+ val devMenuPackage = findDevMenuPackage()
75
+ val devMenuRelatedPackages: List<ReactPackage> =
76
+ if (devMenuPackage != null) {
77
+ findPackagesWithDevMenuExtension(application) + devMenuPackage
78
+ } else {
79
+ emptyList()
80
+ }
81
+
82
+ val additionalPackages = (DevLauncherController.sAdditionalPackages ?: emptyList())
83
+
84
+ return listOf(
85
+ MainReactPackage(null),
86
+ ModuleRegistryAdapter(
87
+ ReactModuleRegistryProvider(emptyList()),
88
+ object : ModulesProvider {
89
+ override fun getModulesList() =
90
+ listOf(
91
+ DevMenuPreferences::class.java,
92
+ SafeAreaProviderManager::class.java
93
+ )
94
+ }
95
+ ),
96
+ DevLauncherPackage()
97
+ ) +
98
+ devMenuRelatedPackages +
99
+ additionalPackages
100
+ }
101
+
102
+ private fun createJSEngineResolutionAlgorithm(application: Application): JSEngineResolutionAlgorithm {
103
+ SoLoader.init(application.applicationContext, /* native exopackage */ false)
104
+ if (SoLoader.getLibraryPath("libjsc.so") != null) {
105
+ return JSEngineResolutionAlgorithm.JSC
106
+ }
107
+ return JSEngineResolutionAlgorithm.HERMES
108
+ }
109
+ }
@@ -17,7 +17,7 @@ import expo.modules.devmenu.modules.DevMenuPreferences
17
17
  import expo.modules.devmenu.react.createNonDebuggableJavaScriptExecutorFactory
18
18
  import expo.modules.kotlin.ModulesProvider
19
19
 
20
- class DevLauncherClientHost(
20
+ class DevLauncherReactNativeHost(
21
21
  application: Application,
22
22
  private val launcherIp: String?
23
23
  ) : DefaultReactNativeHost(application) {
@@ -34,7 +34,7 @@ class DevLauncherClientHost(
34
34
  val devMenuPackage = findDevMenuPackage()
35
35
  val devMenuRelatedPackages: List<ReactPackage> =
36
36
  if (devMenuPackage != null) {
37
- findPackagesWithDevMenuExtension(this) + devMenuPackage
37
+ findPackagesWithDevMenuExtension(application) + devMenuPackage
38
38
  } else {
39
39
  emptyList()
40
40
  }
@@ -85,7 +85,7 @@ class DevLauncherErrorActivity :
85
85
  controller
86
86
  .loadApp(
87
87
  appUrl,
88
- controller.appHost.reactInstanceManager.currentReactContext?.currentActivity as? ReactActivity?
88
+ controller.appHost.currentReactContext?.currentActivity as? ReactActivity?
89
89
  )
90
90
  }
91
91
  }
@@ -102,8 +102,8 @@ class DevLauncherUncaughtExceptionHandler(
102
102
  private fun tryToSendExceptionToBundler(exception: Throwable) {
103
103
  if (
104
104
  controller.mode != DevLauncherController.Mode.APP ||
105
- !controller.appHost.hasInstance() ||
106
- controller.appHost.reactInstanceManager.currentReactContext === null
105
+ !controller.appHost.hasInstance ||
106
+ controller.appHost.currentReactContext === null
107
107
  ) {
108
108
  return
109
109
  }
@@ -124,8 +124,9 @@ class DevLauncherUncaughtExceptionHandler(
124
124
  private fun getWebSocketUrl(): Uri {
125
125
  // URL structure replicates
126
126
  // https://github.com/facebook/react-native/blob/0.69-stable/Libraries/Utilities/HMRClient.js#L164
127
+ val devSupportManager = requireNotNull(controller.appHost.devSupportManager)
127
128
  return Uri
128
- .parse(controller.appHost.reactInstanceManager.devSupportManager.sourceUrl)
129
+ .parse(devSupportManager.sourceUrl)
129
130
  .buildUpon()
130
131
  .path("hot")
131
132
  .clearQuery()
@@ -6,9 +6,9 @@ import androidx.lifecycle.Lifecycle
6
6
  import androidx.lifecycle.LifecycleObserver
7
7
  import androidx.lifecycle.OnLifecycleEvent
8
8
  import com.facebook.react.ReactActivity
9
- import com.facebook.react.ReactInstanceManager
10
- import com.facebook.react.ReactNativeHost
9
+ import com.facebook.react.ReactInstanceEventListener
11
10
  import com.facebook.react.bridge.ReactContext
11
+ import expo.interfaces.devmenu.ReactHostWrapper
12
12
  import expo.modules.devlauncher.launcher.DevLauncherControllerInterface
13
13
  import kotlin.coroutines.Continuation
14
14
  import kotlin.coroutines.resume
@@ -34,7 +34,7 @@ import kotlin.coroutines.suspendCoroutine
34
34
  * - `onReactContext` - is called after the `ReactContext` was loaded.
35
35
  */
36
36
  abstract class DevLauncherAppLoader(
37
- private val appHost: ReactNativeHost,
37
+ private val appHost: ReactHostWrapper,
38
38
  private val context: Context,
39
39
  private val controller: DevLauncherControllerInterface
40
40
  ) {
@@ -45,8 +45,8 @@ abstract class DevLauncherAppLoader(
45
45
  return { activity ->
46
46
  onDelegateWillBeCreated(activity)
47
47
 
48
- require(appHost.reactInstanceManager.currentReactContext == null) { "App react context shouldn't be created before." }
49
- appHost.reactInstanceManager.addReactInstanceEventListener(object : ReactInstanceManager.ReactInstanceEventListener {
48
+ require(appHost.currentReactContext == null) { "App react context shouldn't be created before." }
49
+ appHost.addReactInstanceEventListener(object : ReactInstanceEventListener {
50
50
  override fun onReactContextInitialized(context: ReactContext) {
51
51
  if (reactContextWasInitialized) {
52
52
  return
@@ -54,7 +54,7 @@ abstract class DevLauncherAppLoader(
54
54
 
55
55
  controller.onAppLoaded(context)
56
56
  onReactContext(context)
57
- appHost.reactInstanceManager.removeReactInstanceEventListener(this)
57
+ appHost.removeReactInstanceEventListener(this)
58
58
  reactContextWasInitialized = true
59
59
  continuation!!.resume(true)
60
60
  }
@@ -2,8 +2,8 @@ package expo.modules.devlauncher.launcher.loaders
2
2
 
3
3
  import android.content.Context
4
4
  import android.net.Uri
5
- import com.facebook.react.ReactNativeHost
6
5
  import expo.modules.devlauncher.helpers.DevLauncherInstallationIDHelper
6
+ import expo.interfaces.devmenu.ReactHostWrapper
7
7
  import expo.modules.devlauncher.helpers.createUpdatesConfigurationWithUrl
8
8
  import expo.modules.devlauncher.helpers.getRuntimeVersion
9
9
  import expo.modules.devlauncher.helpers.loadUpdate
@@ -14,7 +14,6 @@ import expo.modules.devlauncher.launcher.manifest.DevLauncherManifestParser
14
14
  import expo.modules.manifests.core.Manifest
15
15
  import expo.modules.updatesinterface.UpdatesInterface
16
16
  import org.koin.core.component.inject
17
- import java.lang.IllegalStateException
18
17
 
19
18
  interface DevLauncherAppLoaderFactoryInterface {
20
19
  suspend fun createAppLoader(url: Uri, projectUrl: Uri, manifestParser: DevLauncherManifestParser): DevLauncherAppLoader
@@ -24,7 +23,7 @@ interface DevLauncherAppLoaderFactoryInterface {
24
23
 
25
24
  class DevLauncherAppLoaderFactory : DevLauncherKoinComponent, DevLauncherAppLoaderFactoryInterface {
26
25
  private val context: Context by inject()
27
- private val appHost: ReactNativeHost by inject()
26
+ private val appHost: ReactHostWrapper by inject()
28
27
  private val updatesInterface: UpdatesInterface? by optInject()
29
28
  private val controller: DevLauncherControllerInterface by inject()
30
29
  private val installationIDHelper: DevLauncherInstallationIDHelper by inject()
@@ -5,9 +5,9 @@ import android.graphics.Color
5
5
  import android.util.Log
6
6
  import android.view.View
7
7
  import com.facebook.react.ReactActivity
8
- import com.facebook.react.ReactNativeHost
9
8
  import com.facebook.react.bridge.ReactContext
10
9
  import com.facebook.react.modules.appearance.AppearanceModule
10
+ import expo.interfaces.devmenu.ReactHostWrapper
11
11
  import expo.modules.devlauncher.helpers.isValidColor
12
12
  import expo.modules.devlauncher.helpers.setProtectedDeclaredField
13
13
  import expo.modules.devlauncher.launcher.DevLauncherControllerInterface
@@ -17,7 +17,7 @@ import expo.modules.manifests.core.Manifest
17
17
 
18
18
  abstract class DevLauncherExpoAppLoader(
19
19
  private val manifest: Manifest,
20
- appHost: ReactNativeHost,
20
+ appHost: ReactHostWrapper,
21
21
  context: Context,
22
22
  controller: DevLauncherControllerInterface,
23
23
  private val activityConfigurator: DevLauncherExpoActivityConfigurator =
@@ -2,7 +2,7 @@ package expo.modules.devlauncher.launcher.loaders
2
2
 
3
3
  import android.content.Context
4
4
  import android.net.Uri
5
- import com.facebook.react.ReactNativeHost
5
+ import expo.interfaces.devmenu.ReactHostWrapper
6
6
  import expo.modules.devlauncher.helpers.injectReactInterceptor
7
7
  import expo.modules.devlauncher.launcher.DevLauncherControllerInterface
8
8
  import expo.modules.manifests.core.Manifest
@@ -13,7 +13,7 @@ import expo.modules.manifests.core.Manifest
13
13
  */
14
14
  class DevLauncherLocalAppLoader(
15
15
  private val manifest: Manifest,
16
- private val appHost: ReactNativeHost,
16
+ private val appHost: ReactHostWrapper,
17
17
  private val context: Context,
18
18
  controller: DevLauncherControllerInterface
19
19
  ) : DevLauncherExpoAppLoader(manifest, appHost, context, controller) {
@@ -1,7 +1,7 @@
1
1
  package expo.modules.devlauncher.launcher.loaders
2
2
 
3
3
  import android.content.Context
4
- import com.facebook.react.ReactNativeHost
4
+ import expo.interfaces.devmenu.ReactHostWrapper
5
5
  import expo.modules.devlauncher.helpers.injectLocalBundleLoader
6
6
  import expo.modules.devlauncher.launcher.DevLauncherControllerInterface
7
7
  import expo.modules.manifests.core.Manifest
@@ -13,7 +13,7 @@ import expo.modules.manifests.core.Manifest
13
13
  class DevLauncherPublishedAppLoader(
14
14
  manifest: Manifest,
15
15
  private val localBundlePath: String,
16
- private val appHost: ReactNativeHost,
16
+ private val appHost: ReactHostWrapper,
17
17
  context: Context,
18
18
  controller: DevLauncherControllerInterface
19
19
  ) : DevLauncherExpoAppLoader(manifest, appHost, context, controller) {
@@ -2,13 +2,13 @@ package expo.modules.devlauncher.launcher.loaders
2
2
 
3
3
  import android.content.Context
4
4
  import android.net.Uri
5
- import com.facebook.react.ReactNativeHost
5
+ import expo.interfaces.devmenu.ReactHostWrapper
6
6
  import expo.modules.devlauncher.helpers.injectReactInterceptor
7
7
  import expo.modules.devlauncher.launcher.DevLauncherControllerInterface
8
8
 
9
9
  class DevLauncherReactNativeAppLoader(
10
10
  private val url: Uri,
11
- private val appHost: ReactNativeHost,
11
+ private val appHost: ReactHostWrapper,
12
12
  private val context: Context,
13
13
  controller: DevLauncherControllerInterface
14
14
  ) : DevLauncherAppLoader(appHost, context, controller) {
@@ -1,101 +1,163 @@
1
1
  package expo.modules.devlauncher.react
2
2
 
3
3
  import android.util.Log
4
+ import com.facebook.react.ReactHost
4
5
  import com.facebook.react.ReactInstanceManager
6
+ import com.facebook.react.ReactNativeHost
5
7
  import com.facebook.react.common.ShakeDetector
6
8
  import com.facebook.react.devsupport.DevServerHelper
7
9
  import com.facebook.react.devsupport.DevSupportManagerBase
8
10
  import com.facebook.react.devsupport.DisabledDevSupportManager
9
11
  import com.facebook.react.devsupport.interfaces.DevSupportManager
10
12
  import com.facebook.react.packagerconnection.JSPackagerClient
13
+ import com.facebook.react.runtime.ReactHostImpl
14
+ import expo.interfaces.devmenu.ReactHostWrapper
11
15
  import expo.modules.devlauncher.helpers.getProtectedFieldValue
12
16
  import expo.modules.devlauncher.helpers.setProtectedDeclaredField
13
17
  import expo.modules.devlauncher.koin.DevLauncherKoinComponent
14
18
  import expo.modules.devlauncher.launcher.DevLauncherControllerInterface
15
- import expo.modules.devlauncher.rncompatibility.DevLauncherDevSupportManager
19
+ import expo.modules.devlauncher.rncompatibility.DevLauncherBridgeDevSupportManager
20
+ import expo.modules.devlauncher.rncompatibility.DevLauncherBridgelessDevSupportManager
16
21
  import kotlinx.coroutines.delay
17
22
  import kotlinx.coroutines.launch
18
23
  import org.koin.core.component.inject
19
24
 
20
- class DevLauncherDevSupportManagerSwapper : DevLauncherKoinComponent {
25
+ internal class DevLauncherDevSupportManagerSwapper : DevLauncherKoinComponent {
21
26
  private val controller: DevLauncherControllerInterface by inject()
22
27
 
23
- fun swapDevSupportManagerImpl(
24
- reactInstanceManager: ReactInstanceManager
25
- ) {
28
+ fun swapDevSupportManagerImpl(reactHost: ReactHostWrapper) {
29
+ if (reactHost.isBridgelessMode) {
30
+ swapDevSupportManagerImpl(reactHost.reactHost)
31
+ } else {
32
+ swapDevSupportManagerImpl(reactHost.reactNativeHost)
33
+ }
34
+ }
35
+
36
+ private fun swapDevSupportManagerImpl(reactNativeHost: ReactNativeHost) {
37
+ val reactInstanceManager = reactNativeHost.reactInstanceManager
26
38
  val currentDevSupportManager = reactInstanceManager.devSupportManager
27
- if (currentDevSupportManager is DevLauncherDevSupportManager) {
39
+ if (currentDevSupportManager is DevLauncherBridgeDevSupportManager) {
28
40
  // DevSupportManager was swapped by the DevLauncherReactNativeHostHandler
29
41
  return
30
42
  }
43
+ if (currentDevSupportManager is DisabledDevSupportManager) {
44
+ Log.i("DevLauncher", "DevSupportManager is disabled. So we don't want to override it.")
45
+ return
46
+ }
47
+
48
+ try {
49
+ val devManagerClass = DevSupportManagerBase::class.java
50
+ val newDevSupportManager = createDevLauncherBridgeDevSupportManager(devManagerClass, currentDevSupportManager)
31
51
 
52
+ ReactInstanceManager::class.java.setProtectedDeclaredField(reactInstanceManager, "mDevSupportManager", newDevSupportManager)
53
+
54
+ closeExistingConnection(devManagerClass, currentDevSupportManager)
55
+ } catch (e: Exception) {
56
+ Log.i("DevLauncher", "Couldn't inject `DevLauncherDevSupportManager`.", e)
57
+ }
58
+ }
59
+
60
+ private fun swapDevSupportManagerImpl(reactHost: ReactHost) {
61
+ val currentDevSupportManager = requireNotNull(reactHost.devSupportManager)
62
+ if (currentDevSupportManager is DevLauncherBridgelessDevSupportManager) {
63
+ // DevSupportManager was swapped by the DevLauncherReactNativeHostHandler
64
+ return
65
+ }
32
66
  if (currentDevSupportManager is DisabledDevSupportManager) {
33
67
  Log.i("DevLauncher", "DevSupportManager is disabled. So we don't want to override it.")
34
68
  return
35
69
  }
70
+
36
71
  try {
37
72
  val devManagerClass = DevSupportManagerBase::class.java
38
- val newDevSupportManager = DevLauncherDevSupportManager(
39
- applicationContext = devManagerClass.getProtectedFieldValue(currentDevSupportManager, "mApplicationContext"),
40
- reactInstanceManagerHelper = devManagerClass.getProtectedFieldValue(currentDevSupportManager, DevLauncherDevSupportManager.getDevHelperInternalFieldName()),
41
- packagerPathForJSBundleName = devManagerClass.getProtectedFieldValue(currentDevSupportManager, "mJSAppBundleName"),
42
- enableOnCreate = true,
43
- redBoxHandler = devManagerClass.getProtectedFieldValue(currentDevSupportManager, "mRedBoxHandler"),
44
- devBundleDownloadListener = devManagerClass.getProtectedFieldValue(currentDevSupportManager, "mBundleDownloadListener"),
45
- minNumShakes = 1,
46
- customPackagerCommandHandlers = devManagerClass.getProtectedFieldValue(currentDevSupportManager, "mCustomPackagerCommandHandlers")
73
+ val newDevSupportManager = createDevLauncherBridgelessDevSupportManager(
74
+ devManagerClass,
75
+ currentDevSupportManager,
76
+ reactHost
47
77
  )
48
78
 
49
- ReactInstanceManager::class.java.setProtectedDeclaredField(reactInstanceManager, "mDevSupportManager", newDevSupportManager)
79
+ ReactHostImpl::class.java.setProtectedDeclaredField(reactHost, "mDevSupportManager", newDevSupportManager)
80
+
81
+ closeExistingConnection(devManagerClass, currentDevSupportManager)
82
+ } catch (e: Exception) {
83
+ Log.i("DevLauncher", "Couldn't inject `DevLauncherDevSupportManager`.", e)
84
+ }
85
+ }
86
+
87
+ private fun createDevLauncherBridgeDevSupportManager(
88
+ devManagerClass: Class<*>,
89
+ currentDevSupportManager: DevSupportManager
90
+ ): DevLauncherBridgeDevSupportManager {
91
+ return DevLauncherBridgeDevSupportManager(
92
+ applicationContext = devManagerClass.getProtectedFieldValue(currentDevSupportManager, "mApplicationContext"),
93
+ reactInstanceDevHelper = devManagerClass.getProtectedFieldValue(currentDevSupportManager, DevLauncherBridgeDevSupportManager.getDevHelperInternalFieldName()),
94
+ packagerPathForJSBundleName = devManagerClass.getProtectedFieldValue(currentDevSupportManager, "mJSAppBundleName"),
95
+ enableOnCreate = true,
96
+ redBoxHandler = devManagerClass.getProtectedFieldValue(currentDevSupportManager, "mRedBoxHandler"),
97
+ devBundleDownloadListener = devManagerClass.getProtectedFieldValue(currentDevSupportManager, "mBundleDownloadListener"),
98
+ minNumShakes = 1,
99
+ customPackagerCommandHandlers = devManagerClass.getProtectedFieldValue(currentDevSupportManager, "mCustomPackagerCommandHandlers")
100
+ )
101
+ }
50
102
 
51
- /**
52
- * We need to invalidate the old packager connection.
53
- * However, this connection is established in the background
54
- * and we don't know when it will be available (see [DevServerHelper.openPackagerConnection]).
55
- * So we just wait for connection and then we kill it.
56
- */
57
- controller.coroutineScope.launch {
58
- try {
59
- while (true) {
60
- // Invalidate shake detector - not doing that leads to memory leaks
61
- tryToStopShakeDetector(currentDevSupportManager)
62
-
63
- val devServerHelper: DevServerHelper = devManagerClass.getProtectedFieldValue(
64
- currentDevSupportManager,
65
- "mDevServerHelper"
103
+ private fun createDevLauncherBridgelessDevSupportManager(
104
+ devManagerClass: Class<*>,
105
+ currentDevSupportManager: DevSupportManager,
106
+ reactHost: ReactHost
107
+ ): DevLauncherBridgelessDevSupportManager {
108
+ return DevLauncherBridgelessDevSupportManager(
109
+ host = reactHost as ReactHostImpl,
110
+ context = devManagerClass.getProtectedFieldValue(currentDevSupportManager, "mApplicationContext"),
111
+ packagerPathForJSBundleName = devManagerClass.getProtectedFieldValue(currentDevSupportManager, "mJSAppBundleName")
112
+ )
113
+ }
114
+
115
+ /**
116
+ * We need to invalidate the old packager connection.
117
+ * However, this connection is established in the background
118
+ * and we don't know when it will be available (see [DevServerHelper.openPackagerConnection]).
119
+ * So we just wait for connection and then we kill it.
120
+ */
121
+ private fun closeExistingConnection(devManagerClass: Class<*>, devSupportManager: DevSupportManager) {
122
+ controller.coroutineScope.launch {
123
+ try {
124
+ while (true) {
125
+ // Invalidate shake detector - not doing that leads to memory leaks
126
+ tryToStopShakeDetector(devSupportManager)
127
+
128
+ val devServerHelper: DevServerHelper = devManagerClass.getProtectedFieldValue(
129
+ devSupportManager,
130
+ "mDevServerHelper"
131
+ )
132
+
133
+ try {
134
+ val packagerConnectionLock: Boolean = DevServerHelper::class.java.getProtectedFieldValue(
135
+ devServerHelper,
136
+ "mPackagerConnectionLock"
66
137
  )
67
138
 
68
- try {
69
- val packagerConnectionLock: Boolean = DevServerHelper::class.java.getProtectedFieldValue(
70
- devServerHelper,
71
- "mPackagerConnectionLock"
72
- )
73
-
74
- if (!packagerConnectionLock) {
75
- devServerHelper.closePackagerConnection()
76
- return@launch
77
- }
78
- } catch (_: NoSuchFieldException) {
79
- // mPackagerConnectionLock was removed from the React Native in v0.63.4
80
- val packagerClient: JSPackagerClient? = DevServerHelper::class.java.getProtectedFieldValue(
81
- devServerHelper,
82
- "mPackagerClient"
83
- )
84
-
85
- if (packagerClient != null) {
86
- devServerHelper.closePackagerConnection()
87
- return@launch
88
- }
139
+ if (!packagerConnectionLock) {
140
+ devServerHelper.closePackagerConnection()
141
+ return@launch
89
142
  }
143
+ } catch (_: NoSuchFieldException) {
144
+ // mPackagerConnectionLock was removed from the React Native in v0.63.4
145
+ val packagerClient: JSPackagerClient? = DevServerHelper::class.java.getProtectedFieldValue(
146
+ devServerHelper,
147
+ "mPackagerClient"
148
+ )
90
149
 
91
- delay(50)
150
+ if (packagerClient != null) {
151
+ devServerHelper.closePackagerConnection()
152
+ return@launch
153
+ }
92
154
  }
93
- } catch (e: Exception) {
94
- Log.w("DevLauncher", "Couldn't close the packager connection: ${e.message}", e)
155
+
156
+ delay(50)
95
157
  }
158
+ } catch (e: Exception) {
159
+ Log.w("DevLauncher", "Couldn't close the packager connection: ${e.message}", e)
96
160
  }
97
- } catch (e: Exception) {
98
- Log.i("DevLauncher", "Couldn't inject `DevLauncherDevSupportManager`.", e)
99
161
  }
100
162
  }
101
163