如何在处理通用 link 之前等待 didFinishLaunchingWithOptions 完成?

How to wait for didFinishLaunchingWithOptions to finish before handling universal link?

在我的 Swift iOS 应用程序中,我在 didFinishLaunchingWithOptions 内的 AppDelegate 中异步设置了初始视图控制器。现在我要添加一个通用 Link,这样如果您在 phone 上转到相应的 URL,它将自动打开应用程序中的正确页面(在本例中是密码重置URL 如果正确,将在应用内打开密码重设表单。

我正在 AppDelegate.

中处理 application(_:continue:restorationHandler:) (continueUserActivity) 中的 linking

如果应用程序已经 运行 则它可以工作,否则 link 处理发生在我的应用程序完成设置初始视图控制器和深层视图控制器之前 link在 didFinishLaunchingWithOptions returns.

时被解雇

如何确保应用程序在我从 continueUserActivity 显示视图控制器之前完成设置?我不能't/shouldn阻止didFinishLaunching返回,直到视图控制器被设置,所以方法returns出现在初始视图控制器之前。

我知道我可以检查 didFinishLaunchingWithOptions 中的用户 activity 字典,但 continueUserActivity 仍然被调用(如果仅在应用程序是 运行,就像 didReceiveRemoteNotification 的工作原理一样)。是否有条件检查此方法内部以将 link 处理推迟到 didFinishLaunching?

一些简化的UIApplicationDelegate代码来帮助解释:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    doSomeAsyncSetup(
        completion: {
            presentSomeViewController()
        }
    )
    return true
}

func application(_: UIApplication, continue userActivity: NSUserActivity, restorationHandler _: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
        let url = userActivity.webpageURL,
        let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true),
        let params = components.queryItems,
        components.path == pathThatIExpect
    {
            handleUniversalLink(params)
    }
    return true
}

请注意,当应用程序选择 Scenes 但我的应用程序未使用它时,区别似乎略有不同 (https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app)。

您可以为此使用串行队列。例如:

serialQueue.async {
    self.presentSomeViewController()
}

serialQueue.async {
    self.handleUniversalLink(params)
}

DispatchGroup 应该可以为您处理。

private let dispatchGroup = DispatchGroup()

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    self.dispatchGroup.enter()
    doSomeAsyncSetup(
        completion: {
            presentSomeViewController()
            self.dispatchGroup.leave()
        }
    )
    return true
}

func application(_: UIApplication, continue userActivity: NSUserActivity, restorationHandler _: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
        let url = userActivity.webpageURL,
        let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true),
        let params = components.queryItems,
        components.path == pathThatIExpect
    {
            self.dispatchGroup.notify {
                handleUniversalLink(params)
            }
    }
    return true
}

在启动您的应用程序的情况下,在 didFinishLaunching 中输入调度组,并在呈现视图控制器后将其保留。 一旦调度组为空,notify将执行用户activity代码;所以只有在你的视图控制器出现之后。

如果您的应用已经启动,调度组将为空,因为 didFinishLaunching 未被调用,因此 notify 将立即执行