如何在处理通用链接之前等待 didFinishLaunchingWithOptions 完成?
Posted
技术标签:
【中文标题】如何在处理通用链接之前等待 didFinishLaunchingWithOptions 完成?【英文标题】:How to wait for didFinishLaunchingWithOptions to finish before handling universal link? 【发布时间】:2021-08-26 20:50:48 【问题描述】:在我的 Swift ios 应用程序中,我在 AppDelegate
内部的 didFinishLaunchingWithOptions
中异步设置了初始视图控制器。现在我正在添加一个通用链接,这样如果您转到手机上的相应 URL,它将自动在应用程序中打开正确的页面(在这种情况下,它是一个密码重置 URL,如果正确,将打开密码重置表单应用内)。
我正在处理我的AppDelegate
中的application(_:continue:restorationHandler:)
(continueUserActivity
) 内的链接。
如果应用程序已经在运行,它可以工作,但链接处理发生在我的应用程序完成初始视图控制器设置之前,并且当didFinishLaunchingWithOptions
返回时,深层链接的视图控制器被关闭。
在我从continueUserActivity
展示视图控制器之前,如何确保应用程序已完成设置?在设置视图控制器之前,我不能/不应该阻止 didFinishLaunching
返回,因此该方法在初始视图控制器出现之前返回。
我知道我可以检查didFinishLaunchingWithOptions
中的用户活动字典,但continueUserActivity
仍然被调用(如果仅在应用程序运行时调用它会简单得多,就像didReceiveRemoteNotification
的工作原理一样)。是否有条件检查此方法内部以将链接处理推迟到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) 时,区别似乎略有不同。
【问题讨论】:
【参考方案1】: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
将执行用户活动代码;所以只有在你的视图控制器出现之后。
如果您的应用已经启动,调度组将为空,因为didFinishLaunching
未被调用,因此notify
将立即执行
【讨论】:
【参考方案2】:您可以为此使用串行队列。例如:
serialQueue.async
self.presentSomeViewController()
和
serialQueue.async
self.handleUniversalLink(params)
【讨论】:
任务 2 将仅在didFinishLaunching
之后启动,因此这将是解决该问题的最简单方法。
认为您刚刚遗漏了一个引用 serialQueue
的实例变量,例如 let serialQueue = DispatchQueue(label: "someLabel")
不幸的是它在这里并不能真正工作,因为它需要等待异步工作在doSomeAsyncSetup
中完成以上是关于如何在处理通用链接之前等待 didFinishLaunchingWithOptions 完成?的主要内容,如果未能解决你的问题,请参考以下文章