Skip to content

Commit

Permalink
[dev-server][dev-launcher] inspector network on ios (#21265)
Browse files Browse the repository at this point in the history
close ENG-7464
close ENG-7492

- [dev-server] enable more devtools features rather than v8only
- [dev-launcher] intercept `URLSession` requests and send CDP network events through metro-inspector-proxy to devtools

bare-expo + `useDevClient = YES` in AppDelegate.mm (this is to enable dev-launcher)

(cherry picked from commit 6f74b01)
  • Loading branch information
Kudo committed Apr 10, 2023
1 parent 5613f86 commit 2e430d2
Show file tree
Hide file tree
Showing 12 changed files with 371 additions and 14 deletions.
1 change: 1 addition & 0 deletions apps/bare-expo/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require File.join(File.dirname(`node --print "require.resolve('expo/package.json

require 'json'
podfile_properties = JSON.parse(File.read('./Podfile.properties.json')) rescue {}
ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = '1' if podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR'] == true

prepare_react_native_project!

Expand Down
4 changes: 2 additions & 2 deletions apps/bare-expo/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1235,7 +1235,7 @@ SPEC CHECKSUMS:
EXPermissions: 2291c6736a823b4c680d5bf8e12d3c1c5d11da35
Expo: b04d142a2b477a391b47c62d179c1a9e1140e6ad
expo-dev-client: 84792ce20d34fa5c882cdc3ca338ea1b2cde5013
expo-dev-launcher: c50f1b78ea294f5762902b768952898d17739983
expo-dev-launcher: d29b64da11f838face098b48f4bf55c558a39b37
expo-dev-menu: d19c631d547ad3a71299753229627b27e3e7a09e
expo-dev-menu-interface: 6c82ae323c4b8724dead4763ce3ff24a2108bdb1
ExpoAppleAuthentication: 7bd5e4150d59e8df37aa80b425850ae88adf9e65
Expand Down Expand Up @@ -1358,6 +1358,6 @@ SPEC CHECKSUMS:
Yoga: ba09b6b11e6139e3df8229238aa794205ca6a02a
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb

PODFILE CHECKSUM: c59f327102c50f126198cfae3dbc05c01a4190e9
PODFILE CHECKSUM: 221d96cc63183a5dfbb774316e11def3300ac02d

COCOAPODS: 1.11.2
3 changes: 2 additions & 1 deletion apps/bare-expo/ios/Podfile.properties.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"expo.jsEngine": "hermes"
"expo.jsEngine": "hermes",
"EX_DEV_CLIENT_NETWORK_INSPECTOR": true
}
4 changes: 2 additions & 2 deletions packages/@expo/dev-server/build/JsInspector.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/@expo/dev-server/build/JsInspector.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/@expo/dev-server/src/JsInspector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export async function openJsInspector(app: MetroInspectorProxyApp) {
// 3. The full commit hash is the desired revision
const devtoolsFrontendRev = 'd9568d04d7dd79269c5a655d7ada69650c5a8336'; // Chrome 100.0.4896.75

const urlBase = `https://chrome-devtools-frontend.appspot.com/serve_rev/@${devtoolsFrontendRev}/inspector.html`;
const urlBase = `https://chrome-devtools-frontend.appspot.com/serve_rev/@${devtoolsFrontendRev}/devtools_app.html`;
const ws = app.webSocketDebuggerUrl.replace(/^ws:\/\//, '');
const url = `${urlBase}?panel=sources&v8only=true&ws=${encodeURIComponent(ws)}`;
const url = `${urlBase}?panel=sources&ws=${encodeURIComponent(ws)}`;
await closeJsInspector();
openingBrowserInstance = await launchBrowserAsync(url);
}
Expand Down
2 changes: 2 additions & 0 deletions packages/expo-dev-launcher/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

### 🎉 New features

- Added experimental network inspector. ([#21265](https://github.com/expo/expo/pull/21265) by [@kudo](https://github.com/kudo))

### 🐛 Bug fixes

### 💡 Others
Expand Down
19 changes: 13 additions & 6 deletions packages/expo-dev-launcher/expo-dev-launcher.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,24 @@ Pod::Spec.new do |s|
'GCC_PREPROCESSOR_DEFINITIONS' => "EX_DEV_LAUNCHER_VERSION=#{s.version}"
}

# Swift/Objective-C compatibility
s.pod_target_xcconfig = { "DEFINES_MODULE" => "YES" }
other_c_flags = '$(inherited)'
dev_launcher_url = ENV['EX_DEV_LAUNCHER_URL'] || ""
if dev_launcher_url != ""
escaped_dev_launcher_url = Shellwords.escape(dev_launcher_url).gsub('/','\\/')
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
'OTHER_CFLAGS[config=Debug]' => "$(inherited) -DEX_DEV_LAUNCHER_URL=\"\\\"" + escaped_dev_launcher_url + "\\\"\""
}
other_c_flags += " -DEX_DEV_LAUNCHER_URL=\"\\\"" + escaped_dev_launcher_url + "\\\"\""
end
other_swift_flags = "$(inherited)"
if ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] == '1'
other_swift_flags += ' -DEX_DEV_CLIENT_NETWORK_INSPECTOR'
end

# Swift/Objective-C compatibility
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
'OTHER_CFLAGS[config=Debug]' => other_c_flags,
'OTHER_SWIFT_FLAGS[config=Debug]' => other_swift_flags,
}

s.user_target_xcconfig = {
"HEADER_SEARCH_PATHS" => "\"${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-launcher/Swift Compatibility Header\"",
}
Expand Down
1 change: 1 addition & 0 deletions packages/expo-dev-launcher/ios/EXDevLauncherController.m
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ - (instancetype)init {
self.errorManager = [[EXDevLauncherErrorManager alloc] initWithController:self];
self.installationIDHelper = [EXDevLauncherInstallationIDHelper new];
self.shouldPreferUpdatesInterfaceSourceUrl = NO;
[EXDevLauncherNetworkLogger.shared enable];
}
return self;
}
Expand Down
41 changes: 41 additions & 0 deletions packages/expo-dev-launcher/ios/EXDevLauncherUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,47 @@ class EXDevLauncherUtils {
}
}

/**
Swizzles implementations of given class method selectors.
This function will backup original selector implementation for `invokeOriginalClassMethod`.
*/
static func swizzleClassMethod(selector selectorA: Selector, withSelector selectorB: Selector, forClass: AnyClass) {
if let methodA = class_getClassMethod(forClass, selectorA),
let methodB = class_getClassMethod(forClass, selectorB) {
let impA = method_getImplementation(methodA)
let backupSelectorA = NSSelectorFromString("_" + NSStringFromSelector(selectorA))
let metaClass = objc_getMetaClass(String(describing: forClass)) as? AnyClass
class_addMethod(metaClass, backupSelectorA, impA, method_getTypeEncoding(methodA))
method_setImplementation(methodA, method_getImplementation(methodB))
}
}

/**
Invokes the original implementation before swizzling for the given selector
*/
static func invokeOriginalClassMethod(selector: Selector, forClass: AnyClass) throws -> Any? {
typealias ClassMethod = @convention(c) (AnyObject, Selector) -> Any
let imp = try getOriginalClassMethodImp(selector: selector, forClass: forClass)
return unsafeBitCast(imp, to: ClassMethod.self)(self, selector)
}

/**
Invokes the original implementation before swizzling for the given selector
*/
static func invokeOriginalClassMethod(selector: Selector, forClass: AnyClass, A0: Any) throws -> Any? {
typealias ClassMethod = @convention(c) (AnyObject, Selector, Any) -> Any
let imp = try getOriginalClassMethodImp(selector: selector, forClass: forClass)
return unsafeBitCast(imp, to: ClassMethod.self)(self, selector, A0)
}

private static func getOriginalClassMethodImp(selector: Selector, forClass: AnyClass) throws -> IMP {
let backupSelector = NSSelectorFromString("_" + NSStringFromSelector(selector))
guard let method = class_getClassMethod(forClass, backupSelector) else {
fatalError("Backup selector does not exist - forClass[\(forClass)] backupSelector[\(NSStringFromSelector(backupSelector))]")
}
return method_getImplementation(method)
}

static func resourcesBundle() -> Bundle? {
let frameworkBundle = Bundle(for: EXDevLauncherUtils.self)

Expand Down
Loading

0 comments on commit 2e430d2

Please sign in to comment.