从 Capacitor 8.4 升级到 Capacitor 8.5
Capacitor 8.5 采用了 iOS UIScene 生命周期。Xcode 27 需要它,因此这作为破坏性小版本发布,而不是等待 Capacitor 9。这些更改仅影响 iOS。
核心库仍然支持 AppDelegate 路径,因此仅更新依赖本身不会破坏你的应用。不过,要使用 Xcode 27 构建,你的应用项目需要采用场景生命周期:一个新文件、一个 Info.plist 条目,以及 AppDelegate 中的一个方法。
@capacitor/ios 中的变更
- 新的
SceneDelegateProxy(位于CAPSceneDelegateProxy.swift)镜像了现有的ApplicationDelegateProxy。它转发 URL 打开、通用链接和场景连接相关的场景回调。 - 旧的
.capacitorOpenURL和.capacitorOpenUniversalLink通知仍会从场景路径以相同的数据载荷发出,因此使用它们的插件无需更改即可继续工作。Cordova 的CDVPluginHandleOpenURL通知也会照常发出。 - 新增场景作用域的通知:
.capacitorSceneWillConnect、.capacitorSceneOpenURL和.capacitorSceneOpenUniversalLink。它们将来源UIScene作为通知的object携带;URL 通知则将其数据载荷携带在userInfo中。它们的存在是为了在多窗口支持到来时让监听器可以按场景过滤。请注意,它们仅在 8.5 及更高版本中发出,因此同时支持更早 Capacitor 8 版本的插件应继续使用旧通知。 - JS 的
resume和pausedocument 事件现在由UIScene.willEnterForegroundNotification和UIScene.didEnterBackgroundNotification驱动,并已过滤到桥接器自身的场景。未采用场景清单的应用仍会收到这些事件;iOS 会为旧版应用创建的兼容场景发出场景通知。 WebViewDelegationHandler现在在决定将导航交给系统时检查 Web 视图的windowScene.activationState,而不是UIApplication.shared.applicationState。ApplicationDelegateProxy.lastURL会从场景路径填充,因此App.getLaunchUrl()继续正常工作。- 已移除:
TmpViewController以及早已弃用的CapacitorBridge.tmpWindow属性和tmpViewControllerAppeared通知。
更新你的 iOS 项目
首先更新 Capacitor 包:
npm i @capacitor/core@^8.5.0 @capacitor/ios@^8.5.0
npm i -D @capacitor/cli@^8.5.0
1. 添加 SceneDelegate.swift
创建 App/App/SceneDelegate.swift。同一个文件适用于 SPM 和 CocoaPods 项目,并与随附的模板一致:
import UIKit
import Capacitor
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = CAPBridgeViewController()
window?.makeKeyAndVisible()
SceneDelegateProxy.shared.scene(scene, willConnectTo: session, options: connectionOptions)
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
SceneDelegateProxy.shared.scene(scene, openURLContexts: URLContexts)
}
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
SceneDelegateProxy.shared.scene(scene, continue: userActivity)
}
}
该委托在代码中创建窗口和根视图控制器;Main.storyboard 不再提供它们。如果你使用自定义的 CAPBridgeViewController 子类,请在这里实例化它,而不是在 storyboard 中设置。
2. 将场景清单添加到 Info.plist
<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>
3. 在 AppDelegate.swift 中添加场景配置钩子
func application(_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions) -> UISceneConfiguration {
let config = UISceneConfiguration(name: "Default Configuration",
sessionRole: connectingSceneSession.role)
config.delegateClass = SceneDelegate.self
return config
}
一旦场景清单就位,iOS 将不再在 AppDelegate 上调用 application(_:open:options:) 和 application(_:continue:restorationHandler:),而是将这些事件交付给场景委托。你可以删除旧方法或保留它们;它们不再运行。应用级回调仍然保留:didFinishLaunchingWithOptions、applicationWillTerminate 以及远程通知回调(推送令牌注册和送达)会像以前一样继续工作。前后台生命周期方法也不再被调用;请参阅下面的审查部分。