Skip to content

Commit

Permalink
[dev-launcher][ios] strip initialURL when deep linking from dev launc…
Browse files Browse the repository at this point in the history
…her (expo#22879)

# Why

when launching app through the dev-client deeplinks, the `Linking.getInitialURL()` returns `exp+{scheme}://expo-development-client/?url...` which is not expected behavior for user.
close ENG-8934

# How

- strip the initial deep link if the url host matching `expo-development-client`
- this behavior aligns to dev-launcher on android which `Linking.getInitialURL` returns null because it uses new Intent and new Activity to launch the app.

# Test Plan

- ci passed
- tested on https://github.com/brentvatne/deep-linking-demo
- also tested on universal link
  • Loading branch information
Kudo authored Jun 16, 2023
1 parent 7603b8a commit f7f790d
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 26 deletions.
1 change: 1 addition & 0 deletions packages/expo-dev-launcher/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- Refactored network inspector code and add unit tests. ([#22669](https://github.com/expo/expo/pull/22669), [#22693](https://github.com/expo/expo/pull/22693) by [@kudo](https://github.com/kudo))
- Fixed `No compatible apps connected. JavaScript Debugging can only be used with the Hermes engine.` when using JavaScript debugger on Android. ([#20280](https://github.com/expo/expo/pull/20280) by [@kudo](https://github.com/kudo))
- Fix "multiple screens with the same name" warning on dev mode. ([#22847](https://github.com/expo/expo/pull/22847) by [@gabrieldonadel](https://github.com/gabrieldonadel))
- [iOS] Fixed incorrect `Linking.getInitialURL()` value when launching through expo-dev-client's deep links. ([#22879](https://github.com/expo/expo/pull/22879) by [@kudo](https://github.com/kudo))

### 💡 Others

Expand Down
2 changes: 1 addition & 1 deletion packages/expo-dev-launcher/ios/EXDevLauncherController.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ NS_ASSUME_NONNULL_BEGIN

- (void)clearRecentlyOpenedApps;

- (NSDictionary<UIApplicationLaunchOptionsKey, NSObject*> *)getLaunchOptions;
- (NSDictionary *)getLaunchOptions;

- (EXManifestsManifest * _Nullable)appManifest;

Expand Down
24 changes: 19 additions & 5 deletions packages/expo-dev-launcher/ios/EXDevLauncherController.m
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,28 @@ - (void)clearRecentlyOpenedApps

- (NSDictionary<UIApplicationLaunchOptionsKey, NSObject*> *)getLaunchOptions;
{
NSMutableDictionary *launchOptions = [self.launchOptions mutableCopy];
NSURL *deepLink = [self.pendingDeepLinkRegistry consumePendingDeepLink];
if (!deepLink) {
return nil;

if (deepLink) {
// Passes pending deep link to initialURL if any
launchOptions[UIApplicationLaunchOptionsURLKey] = deepLink;
} else if (launchOptions[UIApplicationLaunchOptionsURLKey] && [EXDevLauncherURLHelper isDevLauncherURL:launchOptions[UIApplicationLaunchOptionsURLKey]]) {
// Strips initialURL if it is from myapp://expo-development-client/?url=...
// That would make dev-launcher acts like a normal app.
launchOptions[UIApplicationLaunchOptionsURLKey] = nil;
}

return @{
UIApplicationLaunchOptionsURLKey: deepLink
};
if ([launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey][UIApplicationLaunchOptionsUserActivityTypeKey] isEqualToString:NSUserActivityTypeBrowsingWeb]) {
// Strips universal launch link if it is from https://expo-development-client/?url=...
// That would make dev-launcher acts like a normal app, though this case should rarely happen.
NSUserActivity *userActivity = launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey][@"UIApplicationLaunchOptionsUserActivityKey"];
if (userActivity.webpageURL && [EXDevLauncherURLHelper isDevLauncherURL:userActivity.webpageURL]) {
userActivity.webpageURL = nil;
}
}

return launchOptions;
}

- (EXManifestsManifest *)appManifest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ public class ExpoDevLauncherReactDelegateHandler: ExpoReactDelegateHandler, RCTB

private weak var reactDelegate: ExpoReactDelegate?
private var bridgeDelegate: RCTBridgeDelegate?
private var launchOptions: [AnyHashable : Any]?
private var deferredRootView: EXDevLauncherDeferredRCTRootView?
private var rootViewModuleName: String?
private var rootViewInitialProperties: [AnyHashable : Any]?
Expand Down Expand Up @@ -44,14 +43,15 @@ public class ExpoDevLauncherReactDelegateHandler: ExpoReactDelegateHandler, RCTB

self.reactDelegate = reactDelegate
self.bridgeDelegate = EXRCTBridgeDelegateInterceptor(bridgeDelegate: bridgeDelegate, interceptor: self)
self.launchOptions = launchOptions

EXDevLauncherController.sharedInstance().autoSetupPrepare(self, launchOptions: launchOptions)
if let sharedController = UpdatesControllerRegistry.sharedInstance.controller {
// for some reason the swift compiler and bridge are having issues here
EXDevLauncherController.sharedInstance().updatesInterface = sharedController
}
return EXDevLauncherDeferredRCTBridge(delegate: self.bridgeDelegate!, launchOptions: self.launchOptions)
// swiftlint:disable force_unwrapping
return EXDevLauncherDeferredRCTBridge(delegate: self.bridgeDelegate!, launchOptions: launchOptions)
// swiftlint:enable force_unwrapping
}

public override func createRootView(reactDelegate: ExpoReactDelegate, bridge: RCTBridge, moduleName: String, initialProperties: [AnyHashable : Any]?) -> RCTRootView? {
Expand All @@ -67,36 +67,30 @@ public class ExpoDevLauncherReactDelegateHandler: ExpoReactDelegateHandler, RCTB

// MARK: RCTBridgeDelegate implementations

// swiftlint:disable implicitly_unwrapped_optional
public func sourceURL(for bridge: RCTBridge!) -> URL! {
return EXDevLauncherController.sharedInstance().sourceUrl()
}
// swiftlint:enable implicitly_unwrapped_optional

// MARK: EXDevelopmentClientControllerDelegate implementations

public func devLauncherController(_ developmentClientController: EXDevLauncherController, didStartWithSuccess success: Bool) {
var launchOptions: [AnyHashable: Any] = [:]

if let initialLaunchOptions = self.launchOptions {
for (key, value) in initialLaunchOptions {
launchOptions[key] = value
}
}

for (key, value) in developmentClientController.getLaunchOptions() {
launchOptions[key] = value
}

let bridge = RCTBridge(delegate: self.bridgeDelegate, launchOptions: launchOptions)
let bridge = RCTBridge(delegate: self.bridgeDelegate, launchOptions: developmentClientController.getLaunchOptions())
developmentClientController.appBridge = bridge

// swiftlint:disable force_unwrapping
let rootView = RCTRootView(bridge: bridge!, moduleName: self.rootViewModuleName!, initialProperties: self.rootViewInitialProperties)
// swiftlint:enable force_unwrapping
rootView.backgroundColor = self.deferredRootView?.backgroundColor ?? UIColor.white
let window = getWindow()

// NOTE: this order of assignment seems to actually have an effect on behaviour
// direct assignment of window.rootViewController.view = rootView does not work
let rootViewController = self.reactDelegate?.createRootViewController()
rootViewController!.view = rootView
guard let rootViewController = self.reactDelegate?.createRootViewController() else {
fatalError("Invalid rootViewController returned from ExpoReactDelegate")
}
rootViewController.view = rootView
window.rootViewController = rootViewController
window.makeKeyAndVisible()

Expand All @@ -112,9 +106,9 @@ public class ExpoDevLauncherReactDelegateHandler: ExpoReactDelegateHandler, RCTB
if (window == nil) {
window = UIApplication.shared.delegate?.window ?? nil
}
if (window == nil) {
guard let window = window else {
fatalError("Cannot find the current window.")
}
return window!
return window
}
}

0 comments on commit f7f790d

Please sign in to comment.