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.
- package/CHANGELOG.md +6 -0
- package/android/build.gradle +1 -1
- package/android/src/debug/java/expo/modules/devlauncher/DevLauncherController.kt +43 -16
- package/android/src/debug/java/expo/modules/devlauncher/DevLauncherPackageDelegate.kt +1 -1
- package/android/src/debug/java/expo/modules/devlauncher/helpers/DevLauncherReactUtils.kt +158 -46
- package/android/src/debug/java/expo/modules/devlauncher/launcher/DevLauncherActivity.kt +10 -8
- package/android/src/debug/java/expo/modules/devlauncher/launcher/DevLauncherNetworkInterceptor.kt +12 -11
- package/android/src/debug/java/expo/modules/devlauncher/launcher/DevLauncherReactHost.kt +109 -0
- package/android/src/debug/java/expo/modules/devlauncher/launcher/{DevLauncherClientHost.kt → DevLauncherReactNativeHost.kt} +2 -2
- package/android/src/debug/java/expo/modules/devlauncher/launcher/errors/DevLauncherErrorActivity.kt +1 -1
- package/android/src/debug/java/expo/modules/devlauncher/launcher/errors/DevLauncherUncaughtExceptionHandler.kt +4 -3
- package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherAppLoader.kt +6 -6
- package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherAppLoaderFactory.kt +2 -3
- package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherExpoAppLoader.kt +2 -2
- package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherLocalAppLoader.kt +2 -2
- package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherPublishedAppLoader.kt +2 -2
- package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherReactNativeAppLoader.kt +2 -2
- package/android/src/debug/java/expo/modules/devlauncher/react/DevLauncherDevSupportManagerSwapper.kt +119 -57
- package/android/src/main/java/com/facebook/react/devsupport/NonFinalBridgeDevSupportManager.java +273 -0
- package/android/src/main/java/com/facebook/react/runtime/NonFinalBridgelessDevSupportManager.java +177 -0
- package/android/src/main/java/expo/modules/devlauncher/launcher/DevLauncherControllerInterface.kt +4 -4
- package/android/src/react-native-74/debug/expo/modules/devlauncher/rncompatibility/DevLauncherBridgeDevSupportManager.kt +75 -0
- package/android/src/react-native-74/debug/expo/modules/devlauncher/rncompatibility/DevLauncherBridgelessDevSupportManager.kt +55 -0
- package/android/src/react-native-74/debug/expo/modules/devlauncher/rncompatibility/DevLauncherDevSupportManagerFactory.kt +3 -3
- package/android/src/release/java/expo/modules/devlauncher/DevLauncherController.kt +13 -9
- package/android/src/release/java/expo/modules/devlauncher/launcher/DevLauncherReactHost.kt +11 -0
- package/android/src/release/java/expo/modules/devlauncher/launcher/{DevLauncherClientHost.kt → DevLauncherReactNativeHost.kt} +1 -1
- package/android/src/testDebug/java/expo/modules/devlauncher/DevLauncherControllerTest.kt +3 -3
- package/android/src/testDebug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherAppLoaderFactoryTest.kt +3 -4
- package/package.json +3 -3
- 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
|
|
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(
|
|
37
|
+
findPackagesWithDevMenuExtension(application) + devMenuPackage
|
|
38
38
|
} else {
|
|
39
39
|
emptyList()
|
|
40
40
|
}
|
package/android/src/debug/java/expo/modules/devlauncher/launcher/errors/DevLauncherErrorActivity.kt
CHANGED
|
@@ -85,7 +85,7 @@ class DevLauncherErrorActivity :
|
|
|
85
85
|
controller
|
|
86
86
|
.loadApp(
|
|
87
87
|
appUrl,
|
|
88
|
-
controller.appHost.
|
|
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.
|
|
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(
|
|
129
|
+
.parse(devSupportManager.sourceUrl)
|
|
129
130
|
.buildUpon()
|
|
130
131
|
.path("hot")
|
|
131
132
|
.clearQuery()
|
package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherAppLoader.kt
CHANGED
|
@@ -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.
|
|
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:
|
|
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.
|
|
49
|
-
appHost.
|
|
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.
|
|
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:
|
|
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()
|
package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherExpoAppLoader.kt
CHANGED
|
@@ -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:
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
11
|
+
private val appHost: ReactHostWrapper,
|
|
12
12
|
private val context: Context,
|
|
13
13
|
controller: DevLauncherControllerInterface
|
|
14
14
|
) : DevLauncherAppLoader(appHost, context, controller) {
|
package/android/src/debug/java/expo/modules/devlauncher/react/DevLauncherDevSupportManagerSwapper.kt
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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
|
|
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 =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
150
|
+
if (packagerClient != null) {
|
|
151
|
+
devServerHelper.closePackagerConnection()
|
|
152
|
+
return@launch
|
|
153
|
+
}
|
|
92
154
|
}
|
|
93
|
-
|
|
94
|
-
|
|
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
|
|