expo-dev-launcher 5.0.2 → 5.0.3
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 +8 -2
- package/android/src/debug/java/expo/modules/devlauncher/launcher/DevLauncherNetworkInterceptor.kt +17 -88
- package/ios/DevLauncherNetworkInterceptor.swift +20 -66
- package/ios/EXDevLauncherController.m +3 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 5.0.3 — 2024-10-24
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- Fixed network inspector support for react-native 0.76. ([#32290](https://github.com/expo/expo/pull/32290) by [@kudo](https://github.com/kudo))
|
|
18
|
+
|
|
13
19
|
## 5.0.2 — 2024-10-24
|
|
14
20
|
|
|
15
21
|
### 🎉 New features
|
package/android/build.gradle
CHANGED
|
@@ -107,8 +107,7 @@ class DevLauncherController private constructor() :
|
|
|
107
107
|
|
|
108
108
|
private var appIsLoading = false
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
private val networkInterceptor = DevLauncherNetworkInterceptor(this)
|
|
110
|
+
private var networkInterceptor: DevLauncherNetworkInterceptor? = null
|
|
112
111
|
|
|
113
112
|
private fun isEASUpdateURL(url: Uri): Boolean {
|
|
114
113
|
return url.host.equals("u.expo.dev") || url.host.equals("staging-u.expo.dev")
|
|
@@ -192,6 +191,11 @@ class DevLauncherController private constructor() :
|
|
|
192
191
|
synchronized(this) {
|
|
193
192
|
appIsLoading = false
|
|
194
193
|
}
|
|
194
|
+
manifestURL?.let {
|
|
195
|
+
runBlockingOnMainThread {
|
|
196
|
+
networkInterceptor = DevLauncherNetworkInterceptor(it)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
195
199
|
}
|
|
196
200
|
|
|
197
201
|
override fun onAppLoadedWithError() {
|
|
@@ -287,6 +291,8 @@ class DevLauncherController private constructor() :
|
|
|
287
291
|
private fun ensureHostWasCleared(host: ReactHostWrapper, activityToBeInvalidated: ReactActivity? = null) {
|
|
288
292
|
if (host.hasInstance) {
|
|
289
293
|
runBlockingOnMainThread {
|
|
294
|
+
networkInterceptor?.close()
|
|
295
|
+
networkInterceptor = null
|
|
290
296
|
clearHost(host, activityToBeInvalidated)
|
|
291
297
|
}
|
|
292
298
|
}
|
package/android/src/debug/java/expo/modules/devlauncher/launcher/DevLauncherNetworkInterceptor.kt
CHANGED
|
@@ -2,113 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
package expo.modules.devlauncher.launcher
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import com.facebook.react.
|
|
7
|
-
import com.facebook.react.devsupport.DevServerHelper
|
|
8
|
-
import com.facebook.react.devsupport.DevSupportManagerBase
|
|
9
|
-
import com.facebook.react.devsupport.InspectorPackagerConnection
|
|
10
|
-
import expo.modules.devlauncher.DevLauncherController
|
|
11
|
-
import expo.interfaces.devmenu.ReactHostWrapper
|
|
5
|
+
import android.net.Uri
|
|
6
|
+
import com.facebook.react.packagerconnection.ReconnectingWebSocket
|
|
12
7
|
import expo.modules.kotlin.devtools.ExpoRequestCdpInterceptor
|
|
13
8
|
import java.io.Closeable
|
|
14
|
-
import java.lang.ref.WeakReference
|
|
15
|
-
import java.lang.reflect.Field
|
|
16
|
-
import java.lang.reflect.Method
|
|
17
9
|
|
|
18
|
-
internal class DevLauncherNetworkInterceptor(
|
|
19
|
-
private val
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (reactHostHashCode != reactHost.hashCode()) {
|
|
27
|
-
_inspectorPackagerConnection?.clear()
|
|
28
|
-
_inspectorPackagerConnection = null
|
|
29
|
-
reactHostHashCode = 0
|
|
30
|
-
}
|
|
31
|
-
if (_inspectorPackagerConnection == null) {
|
|
32
|
-
_inspectorPackagerConnection = InspectorPackagerConnectionWrapper(reactHost)
|
|
33
|
-
reactHostHashCode = reactHost.hashCode()
|
|
34
|
-
}
|
|
35
|
-
return requireNotNull(_inspectorPackagerConnection)
|
|
10
|
+
internal class DevLauncherNetworkInterceptor(appUrl: Uri) : Closeable, ExpoRequestCdpInterceptor.Delegate {
|
|
11
|
+
private val metroConnection = ReconnectingWebSocket(
|
|
12
|
+
createNetworkInspectorUrl(appUrl),
|
|
13
|
+
null,
|
|
14
|
+
null
|
|
15
|
+
)
|
|
16
|
+
.apply {
|
|
17
|
+
connect()
|
|
36
18
|
}
|
|
37
19
|
|
|
38
20
|
init {
|
|
39
21
|
ExpoRequestCdpInterceptor.setDelegate(this)
|
|
40
22
|
}
|
|
41
23
|
|
|
42
|
-
/**
|
|
43
|
-
* Returns true when it is allowed to send CDP events
|
|
44
|
-
*/
|
|
45
|
-
private fun shouldEmitEvents(): Boolean {
|
|
46
|
-
return DevLauncherController.wasInitialized() && weakController.get()?.appHost?.lifecycleState == LifecycleState.RESUMED
|
|
47
|
-
}
|
|
48
|
-
|
|
49
24
|
//region Closeable implementations
|
|
50
25
|
override fun close() {
|
|
51
26
|
ExpoRequestCdpInterceptor.setDelegate(null)
|
|
27
|
+
metroConnection.closeQuietly()
|
|
52
28
|
}
|
|
53
29
|
//endregion Closeable implementations
|
|
54
30
|
|
|
55
31
|
//region ExpoRequestCdpInterceptor.Delegate implementations
|
|
56
32
|
override fun dispatch(event: String) {
|
|
57
|
-
|
|
58
|
-
inspectorPackagerConnection.sendWrappedEventToAllPages(event)
|
|
59
|
-
}
|
|
33
|
+
metroConnection.sendMessage(event)
|
|
60
34
|
}
|
|
61
35
|
//endregion ExpoRequestCdpInterceptor.Delegate implementations
|
|
62
36
|
}
|
|
63
37
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
private val devServerHelperWeak: WeakReference<DevServerHelper>
|
|
70
|
-
private val inspectorPackagerConnectionField: Field
|
|
71
|
-
private val sendWrappedEventMethod: Method
|
|
72
|
-
|
|
73
|
-
private val inspectorPackagerConnection: InspectorPackagerConnection?
|
|
74
|
-
get() {
|
|
75
|
-
var inspectorPackagerConnection = inspectorPackagerConnectionWeak.get()
|
|
76
|
-
if (inspectorPackagerConnection == null) {
|
|
77
|
-
val devServerHelper = devServerHelperWeak.get() ?: return null
|
|
78
|
-
inspectorPackagerConnection = inspectorPackagerConnectionField[devServerHelper] as? InspectorPackagerConnection
|
|
79
|
-
|
|
80
|
-
if (inspectorPackagerConnection != null) {
|
|
81
|
-
inspectorPackagerConnectionWeak = WeakReference(inspectorPackagerConnection)
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return inspectorPackagerConnection
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
init {
|
|
88
|
-
val devSupportManager = requireNotNull(reactHost.devSupportManager)
|
|
89
|
-
val devSupportManagerBaseClass = DevSupportManagerBase::class.java
|
|
90
|
-
val mDevServerHelperField = devSupportManagerBaseClass.getDeclaredField("mDevServerHelper")
|
|
91
|
-
mDevServerHelperField.isAccessible = true
|
|
92
|
-
val devServerHelper = mDevServerHelperField[devSupportManager]
|
|
93
|
-
devServerHelperWeak = WeakReference(devServerHelper as DevServerHelper)
|
|
94
|
-
|
|
95
|
-
inspectorPackagerConnectionField = DevServerHelper::class.java.getDeclaredField("mInspectorPackagerConnection")
|
|
96
|
-
inspectorPackagerConnectionField.isAccessible = true
|
|
97
|
-
|
|
98
|
-
sendWrappedEventMethod = InspectorPackagerConnection::class.java.getDeclaredMethod("sendWrappedEvent", String::class.java, String::class.java)
|
|
99
|
-
sendWrappedEventMethod.isAccessible = true
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
fun clear() {
|
|
103
|
-
inspectorPackagerConnectionWeak.clear()
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
fun sendWrappedEventToAllPages(event: String) {
|
|
107
|
-
val inspectorPackagerConnection = this.inspectorPackagerConnection ?: return
|
|
108
|
-
for (page in Inspector.getPages()) {
|
|
109
|
-
if (!page.title.contains("Reanimated")) {
|
|
110
|
-
sendWrappedEventMethod.invoke(inspectorPackagerConnection, page.id.toString(), event)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
38
|
+
private fun createNetworkInspectorUrl(appUrl: Uri): String {
|
|
39
|
+
val host = appUrl.host ?: "localhost"
|
|
40
|
+
val port = if (appUrl.port > 0) appUrl.port else 8081
|
|
41
|
+
val scheme = if (appUrl.scheme == "https") "wss" else "ws"
|
|
42
|
+
return "$scheme://$host:$port/inspector/network"
|
|
114
43
|
}
|
|
@@ -9,18 +9,18 @@ var isHookInstalled = false
|
|
|
9
9
|
|
|
10
10
|
@objc(EXDevLauncherNetworkInterceptor)
|
|
11
11
|
public final class DevLauncherNetworkInterceptor: NSObject, ExpoRequestCdpInterceptorDelegate {
|
|
12
|
-
|
|
12
|
+
private let metroConnection: RCTReconnectingWebSocket
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
@objc
|
|
15
|
+
public init(bundleUrl: URL) {
|
|
16
16
|
assert(Thread.isMainThread)
|
|
17
|
+
self.metroConnection = RCTReconnectingWebSocket(
|
|
18
|
+
url: Self.createNetworkInspectorUrl(bundleUrl: bundleUrl),
|
|
19
|
+
queue: .main)
|
|
20
|
+
self.metroConnection.start()
|
|
21
|
+
super.init()
|
|
17
22
|
|
|
18
23
|
if !isHookInstalled {
|
|
19
|
-
EXDevLauncherUtils.swizzleClassMethod(
|
|
20
|
-
selector: #selector(RCTInspectorDevServerHelper.connect(withBundleURL:)),
|
|
21
|
-
withSelector: #selector(RCTInspectorDevServerHelper.EXDevLauncher_connect(withBundleURL:)),
|
|
22
|
-
forClass: RCTInspectorDevServerHelper.self
|
|
23
|
-
)
|
|
24
24
|
EXDevLauncherUtils.swizzleClassMethod(
|
|
25
25
|
selector: #selector(getter: URLSessionConfiguration.default),
|
|
26
26
|
withSelector: #selector(URLSessionConfiguration.EXDevLauncher_urlSessionConfiguration),
|
|
@@ -35,70 +35,24 @@ public final class DevLauncherNetworkInterceptor: NSObject, ExpoRequestCdpInterc
|
|
|
35
35
|
deinit {
|
|
36
36
|
assert(Thread.isMainThread)
|
|
37
37
|
ExpoRequestCdpInterceptor.shared.setDelegate(nil)
|
|
38
|
+
self.metroConnection.stop()
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
extension RCTInspectorDevServerHelper {
|
|
48
|
-
private typealias ConnectFunc = @convention(c) (AnyObject, Selector, URL)
|
|
49
|
-
-> RCTInspectorPackagerConnection?
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
Swizzled `RCTInspectorDevServerHelper.connect(withBundleURL:)` for us to get the `RCTInspectorPackagerConnection` instance
|
|
53
|
-
*/
|
|
54
|
-
@objc
|
|
55
|
-
static func EXDevLauncher_connect(withBundleURL bundleURL: URL)
|
|
56
|
-
-> RCTInspectorPackagerConnection? {
|
|
57
|
-
let inspectorPackagerConn = try? EXDevLauncherUtils.invokeOriginalClassMethod(
|
|
58
|
-
selector: #selector(RCTInspectorDevServerHelper.connect(withBundleURL:)),
|
|
59
|
-
forClass: RCTInspectorDevServerHelper.self,
|
|
60
|
-
A0: bundleURL
|
|
61
|
-
) as? RCTInspectorPackagerConnection
|
|
62
|
-
|
|
63
|
-
// Exclude the connections for dev-client bundles
|
|
64
|
-
if !bundleURL.absoluteString.starts(with: Bundle.main.bundleURL.absoluteString) {
|
|
65
|
-
DevLauncherNetworkInterceptor.inspectorPackagerConn = inspectorPackagerConn
|
|
41
|
+
private static func createNetworkInspectorUrl(bundleUrl: URL) -> URL {
|
|
42
|
+
let host = bundleUrl.host ?? "localhost"
|
|
43
|
+
let port = bundleUrl.port ?? 8081
|
|
44
|
+
let scheme = bundleUrl.scheme == "https" ? "wss" : "ws"
|
|
45
|
+
let urlString = "\(scheme)://\(host):\(port)/inspector/network"
|
|
46
|
+
guard let url = URL(string: urlString) else {
|
|
47
|
+
fatalError("Invalid network inspector URL: \(urlString)")
|
|
66
48
|
}
|
|
67
|
-
return
|
|
49
|
+
return url
|
|
68
50
|
}
|
|
69
|
-
}
|
|
70
51
|
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
Indicates whether the packager connection is established and ready to send messages
|
|
74
|
-
*/
|
|
75
|
-
func isReadyToSend() -> Bool {
|
|
76
|
-
guard isConnected() else {
|
|
77
|
-
return false
|
|
78
|
-
}
|
|
79
|
-
guard let webSocket = value(forKey: "_webSocket") as? AnyObject,
|
|
80
|
-
let readyState = webSocket.value(forKey: "readyState") as? Int else {
|
|
81
|
-
return false
|
|
82
|
-
}
|
|
83
|
-
// To support both RCTSRWebSocket (RN < 0.72) and SRWebSocket (RN >= 0.72)
|
|
84
|
-
// and not to introduce extra podspec dependencies,
|
|
85
|
-
// we use the internal and hardcoded value here.
|
|
86
|
-
// Given the fact that both RCTSRWebSocket and SRWebSocket has the readyState property
|
|
87
|
-
// and the open state is 1.
|
|
88
|
-
let OPEN_STATE = 1
|
|
89
|
-
return readyState == OPEN_STATE
|
|
90
|
-
}
|
|
52
|
+
// MARK: ExpoRequestCdpInterceptorDelegate implementations
|
|
91
53
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
*/
|
|
95
|
-
func sendWrappedEventToAllPages(_ event: String) {
|
|
96
|
-
guard isReadyToSend() else {
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
for page in RCTInspector.pages() where !page.title.contains("Reanimated") {
|
|
100
|
-
perform(NSSelectorFromString("sendWrappedEvent:message:"), with: String(page.id), with: event)
|
|
101
|
-
}
|
|
54
|
+
public func dispatch(_ event: String) {
|
|
55
|
+
self.metroConnection.send(Data(event.utf8))
|
|
102
56
|
}
|
|
103
57
|
}
|
|
104
58
|
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
@property (nonatomic, strong) NSURL *possibleManifestURL;
|
|
57
57
|
@property (nonatomic, strong) EXDevLauncherErrorManager *errorManager;
|
|
58
58
|
@property (nonatomic, strong) EXDevLauncherInstallationIDHelper *installationIDHelper;
|
|
59
|
-
@property (nonatomic, strong) EXDevLauncherNetworkInterceptor *networkInterceptor;
|
|
59
|
+
@property (nonatomic, strong, nullable) EXDevLauncherNetworkInterceptor *networkInterceptor;
|
|
60
60
|
@property (nonatomic, assign) BOOL isStarted;
|
|
61
61
|
@property (nonatomic, strong) EXDevLauncherAppDelegate *appDelegate;
|
|
62
62
|
@property (nonatomic, strong) NSURL *lastOpenedAppUrl;
|
|
@@ -84,7 +84,6 @@
|
|
|
84
84
|
self.pendingDeepLinkRegistry = [EXDevLauncherPendingDeepLinkRegistry new];
|
|
85
85
|
self.errorManager = [[EXDevLauncherErrorManager alloc] initWithController:self];
|
|
86
86
|
self.installationIDHelper = [EXDevLauncherInstallationIDHelper new];
|
|
87
|
-
self.networkInterceptor = [EXDevLauncherNetworkInterceptor new];
|
|
88
87
|
self.shouldPreferUpdatesInterfaceSourceUrl = NO;
|
|
89
88
|
|
|
90
89
|
__weak __typeof(self) weakSelf = self;
|
|
@@ -323,6 +322,7 @@
|
|
|
323
322
|
|
|
324
323
|
self.manifest = nil;
|
|
325
324
|
self.manifestURL = nil;
|
|
325
|
+
self.networkInterceptor = nil;
|
|
326
326
|
|
|
327
327
|
[self _applyUserInterfaceStyle:UIUserInterfaceStyleUnspecified];
|
|
328
328
|
|
|
@@ -576,6 +576,7 @@
|
|
|
576
576
|
if (![bundleUrl.scheme isEqualToString:@"file"]) {
|
|
577
577
|
[[RCTPackagerConnection sharedPackagerConnection] setSocketConnectionURL:bundleUrl];
|
|
578
578
|
}
|
|
579
|
+
self.networkInterceptor = [[EXDevLauncherNetworkInterceptor alloc] initWithBundleUrl:bundleUrl];
|
|
579
580
|
#endif
|
|
580
581
|
|
|
581
582
|
UIUserInterfaceStyle userInterfaceStyle = [EXDevLauncherManifestHelper exportManifestUserInterfaceStyle:manifest.userInterfaceStyle];
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-dev-launcher",
|
|
3
3
|
"title": "Expo Development Launcher",
|
|
4
|
-
"version": "5.0.
|
|
4
|
+
"version": "5.0.3",
|
|
5
5
|
"description": "Pre-release version of the Expo development launcher package for testing.",
|
|
6
6
|
"main": "build/DevLauncher.js",
|
|
7
7
|
"types": "build/DevLauncher.d.ts",
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
],
|
|
67
67
|
"testTimeout": 15000
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "2e4f18d41da033c5ced0a4a045d91cf5250016b7"
|
|
70
70
|
}
|