SwiftUI迁移UIKit后无SceneDelegate调用黑屏,求替代私有API方案
问题场景
从SwiftUI应用重构为UIKit应用后,曾安装过旧版SwiftUI应用的设备升级新版UIKit应用时出现黑屏。排查发现:
- SceneDelegate的所有方法均未被调用
- AppDelegate中的
application(_:configurationForConnecting:options:)方法未触发 - 删除旧版后重新安装新版则无问题,推测是iOS 13+的Scene会话缓存机制导致,但无法要求用户手动删除旧版。
目前仅能通过私有API临时解决,但无法用于正式版本:
application.openSessions.forEach { session in application.perform(Selector(("_removeSessionFromSessionSet:")), with: session) }
替代私有API的可行方案
1. 强制返回UIKit场景配置,忽略缓存
在AppDelegate的场景配置方法中,直接返回指定的UIKit场景配置,不依赖系统缓存的旧配置:
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // 强制生成UIKit场景配置,覆盖缓存的旧SwiftUI配置 let sceneConfig = UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) sceneConfig.delegateClass = SceneDelegate.self // 如果使用Storyboard,指定对应的Storyboard文件 sceneConfig.storyboard = UIStoryboard(name: "Main", bundle: Bundle.main) return sceneConfig }
原理:系统缓存的旧会话可能关联了SwiftUI的场景配置,此方法强制为所有连接的会话分配新的UIKit配置,绕过缓存。
2. 清理Info.plist中的冗余场景配置
确保UIApplicationSceneManifest配置仅保留UIKit相关项,删除旧的SwiftUI配置:
<key>UIApplicationSceneManifest</key> <dict> <key>UIApplicationSupportsMultipleScenes</key> <false/> <key>UISceneConfigurations</key> <dict> <key>UIWindowSceneSessionRoleApplication</key> <array> <dict> <key>UISceneConfigurationName</key> <string>Default Configuration</string> <key>UISceneDelegateClassName</key> <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string> <key>UISceneStoryboardFile</key> <string>Main</string> </dict> </array> </dict> </dict>
原理:移除旧配置后,系统无法找到缓存会话对应的配置,会自动使用新的UIKit配置初始化场景。
3. 异步销毁旧会话并重建新场景
在didFinishLaunchingWithOptions中异步销毁所有缓存的旧会话,然后手动创建新的UIKit场景:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { guard !application.openSessions.isEmpty else { return true } for session in application.openSessions { application.requestSceneSessionDestruction(session, options: nil) { [weak self] _ in guard let self = self else { return } // 销毁旧会话后,创建新的UIKit场景 let newConfig = UISceneConfiguration(name: "Default Configuration", sessionRole: .application) newConfig.delegateClass = SceneDelegate.self application.requestSceneSessionCreation(configuration: newConfig, options: nil) } } return true }
注意:此方法依赖异步回调,需确保场景创建的时机正确,避免重复创建。
内容的提问来源于stack exchange,提问作者daspianist
相关产品推荐
相关产品推荐

