自定义URL Scheme处理时,scene(_:willConnectTo:)中rootVC为空如何启动视图控制器?
解决冷启动时Widget Deep Link跳转失败的问题
冷启动时scene(_:willConnectTo:)的调用时机早于根视图控制器初始化,导致window?.rootViewController为空,无法执行跳转。可以通过延迟处理Deep Link的方式解决,具体步骤如下:
步骤1:在SceneDelegate中添加待处理URL属性
在SceneDelegate类中新增可选URL属性,用于暂存冷启动时收到的Deep Link:
class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? // 暂存冷启动时的Deep Link private var pendingDeepLinkURL: URL? // ... 其他已有方法 }
步骤2:修改冷启动时的URL处理逻辑
在scene(_:willConnectTo:)中,不再直接调用handleIncomingURL,而是将URL存入待处理属性:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = scene as? UIWindowScene else { return } // 手动初始化窗口和根视图控制器(若项目依赖Storyboard自动加载,可跳过此段) window = UIWindow(windowScene: windowScene) let rootVC = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() window?.rootViewController = rootVC window?.makeKeyAndVisible() // 暂存Deep Link URL if let url = connectionOptions.urlContexts.first?.url { pendingDeepLinkURL = url } }
步骤3:在应用激活后处理待跳转URL
实现sceneDidBecomeActive方法,在应用完全激活、根视图控制器就绪时,处理暂存的Deep Link:
func sceneDidBecomeActive(_ scene: UIScene) { if let url = pendingDeepLinkURL { handleIncomingURL(url) // 处理完成后清空属性,避免重复跳转 pendingDeepLinkURL = nil } }
补充:确保handleIncomingURL逻辑兼容两种场景
原有handleIncomingURL逻辑无需修改,后台恢复时scene(_:openURLContexts:)会直接调用它,冷启动时则在sceneDidBecomeActive中延迟调用(此时rootViewController已存在):
private func handleIncomingURL(_ url: URL) { guard url.scheme == "widget" else { return } guard let rootViewController = window?.rootViewController else { print("no rootViewController") return } // 关闭所有弹出的视图控制器 rootViewController.dismiss(animated: false) let greenViewController = GreenViewController.instanceFromMainStoryBoard() rootViewController.present(greenViewController, animated: true) }
额外说明
若项目通过Storyboard自动初始化窗口和根视图控制器(即Info.plist中配置了UISceneStoryboardFile),无需手动创建window和rootVC,只需在sceneDidBecomeActive中检查pendingDeepLinkURL即可,系统已完成根视图控制器的初始化。
内容的提问来源于stack exchange,提问作者Cheok Yan Cheng
相关产品推荐
相关产品推荐

