TN3187:迁移至基于 UIKit 场景的生命周期

21 阅读1分钟

概述

许多较旧的 iOS 应用使用一个 UIApplicationDelegate 对象作为其应用的主要入口点,并管理应用的生命周期。使用场景的应用则不同,它们使用一个 UISceneDelegate 对象来分别管理每个场景窗口。从基于 UIApplicationDelegate 的应用生命周期迁移到基于场景的生命周期,可以让你的应用支持多窗口等现代功能。本文档阐述了如何将应用迁移到基于场景的生命周期。

迁移路径

将应用迁移到基于场景的生命周期有两种路径:

  • 分阶段迁移:应用在继续使用 UIApplicationDelegate 的同时,逐步采用 UISceneDelegate。
  • 直接迁移:应用一次性直接迁移到 UISceneDelegate。

在分阶段迁移中,你可以在应用的不同部分逐步实现场景支持,而应用的其余部分继续通过现有的 UIApplicationDelegate 进行管理。这种方式对于大型应用或者需要逐步验证场景兼容性的团队很有用。然而,分阶段迁移会增加临时复杂性,并且应用在完全迁移之前无法使用多窗口等需要完全基于场景生命周期的功能。

直接迁移意味着一次性将整个应用切换到 UISceneDelegate。对于尚未使用 UIApplicationDelegate 管理界面的新应用,或者那些规模较小、易于整体更新的现有应用,推荐采用这种方式。直接迁移可以更快地启用多窗口等现代功能,并简化代码库。

如何判断应用是否使用了场景?

如果你的应用使用了场景,其 Info.plist 文件中会包含一个 UIApplicationSceneManifest 字典。当系统在 Info.plist 中检测到此字典时,它会使用基于场景的生命周期来启动你的应用。对于直接迁移,你需要添加此清单。对于分阶段迁移,你将在准备好启用场景时添加它。


分阶段迁移

分阶段迁移允许你逐步采用 UISceneDelegate。在这种方法下,应用将继续使用 UIApplicationDelegate 作为主要入口点,但你可以为某些界面逐步引入场景支持。当你想为应用的特定部分启用多窗口等功能,同时保持其他部分的原有行为时,这种方式很有用。

要进行分阶段迁移,你需要:

  1. 创建一个实现 UIWindowSceneDelegate 协议的新类。
  2. 在 UIApplicationDelegate 中实现 application(_:configurationForConnecting:options:) 方法,为特定会话返回一个 UISceneConfiguration 实例。此配置告诉系统为连接的场景会话使用哪个场景代理类。
  3. 在应用的 Info.plist 中配置 UIApplicationSceneManifest 字典,并为场景配置指定你的场景代理类名。

当系统请求新场景时,它会调用 UIApplicationDelegate 的 application(_:configurationForConnecting:options:) 方法。你可以检查连接选项(例如 UIApplication.OpenURLOptions 或 UIApplication.ActivityOptions)来决定返回哪种场景配置。这允许你根据用户的操作(例如点击 URL 或进行拖放操作)来创建不同类型的场景。

分阶段迁移期间,UIApplicationDelegate 仍然负责管理应用级事件(例如应用启动和进入后台),而 UISceneDelegate 则管理特定场景的生命周期事件(例如场景激活或失活)。这种分离使得你可以逐步将界面管理从 UIApplicationDelegate 转移到 UISceneDelegate。

直接迁移

直接迁移涉及一次性将整个应用从 UIApplicationDelegate 迁移到 UISceneDelegate。这种方式适用于新应用,或者那些愿意为启用多窗口等现代功能而进行全面更新的现有应用。

要直接迁移,你需要:

  1. 将应用生命周期管理从 UIApplicationDelegate 移动到 UISceneDelegate。这包括将代码从 application(:didFinishLaunchingWithOptions:) 移动到 scene(:willConnectTo:options:),以及将其他生命周期方法(例如 applicationWillResignActive 和 applicationDidBecomeActive)迁移到对应的场景代理方法(例如 sceneWillResignActive 和 sceneDidBecomeActive)。
  2. 移除 UIApplicationDelegate 中与窗口管理相关的代码,因为每个场景现在都会管理自己的 UIWindow。
  3. 在 Info.plist 中添加 UIApplicationSceneManifest 字典,并配置默认的场景配置,指定你的 UISceneDelegate 类。

直接迁移后,应用的每个窗口都由一个独立的 UIScene 实例管理,UISceneDelegate 负责该场景的生命周期。这为每个窗口提供了更好的隔离,并启用了多窗口支持。


通用迁移步骤

无论选择分阶段迁移还是直接迁移,都需要遵循一些通用步骤:

1. 创建场景代理类

创建一个实现 UIWindowSceneDelegate 协议的新类。这个类将管理特定场景的生命周期。你可以在其中创建窗口、设置根视图控制器,并响应场景生命周期事件。

2. 配置 Info.plist

在 Info.plist 中添加一个 UIApplicationSceneManifest 字典。此字典告诉系统你的应用支持场景。它包含一个 UISceneConfigurations 字典,你可以在其中定义应用支持的不同场景配置。每个配置指定了场景代理类名和故事板名称(如果使用的话)。

<key>UIApplicationSceneManifest</key> <dict> <key>UIApplicationSupportsMultipleScenes</key> <true/> <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. 更新应用代理

对于直接迁移,移除 UIApplicationDelegate 中与窗口管理相关的代码,并将应用生命周期事件的处理移动到场景代理中。对于分阶段迁移,在 UIApplicationDelegate 中实现 application(_:configurationForConnecting:options:) 方法来返回适当的场景配置。

4. 更新生命周期事件处理

将应用级生命周期事件的处理迁移到相应的场景级事件。例如:

  • application(:didFinishLaunchingWithOptions:) 迁移到 scene(:willConnectTo:options:)
  • applicationWillResignActive 迁移到 sceneWillResignActive
  • applicationDidBecomeActive 迁移到 sceneDidBecomeActive
  • 等等...

5. 测试

在支持场景的设备(例如 iPad)上彻底测试你的应用。验证场景是否正确创建、生命周期事件是否正常触发,以及多窗口等功能是否按预期工作。对于分阶段迁移,确保现有功能在启用场景的部分和未启用的部分都能正常工作。

场景与后台任务

当使用基于场景的生命周期时,后台任务的处理方式有所不同。在基于 UIApplicationDelegate 的应用中,后台任务通常在应用级别管理。而在基于场景的应用中,后台任务可以与特定场景关联。

如果你的应用使用 UIApplication.beginBackgroundTask(withName:expirationHandler:) 来管理长时间运行的任务,在迁移到场景后,你可能需要考虑使用每个场景的后台任务管理。然而,UIApplication 级别的后台任务 API 在基于场景的应用中仍然可用,并且可以在应用级别的任务中使用。

对于直接与特定场景关联的任务(例如,该场景正在进行的网络请求),考虑使用与该场景关联的后台任务。这有助于系统更有效地管理资源,并在场景关闭时提供更清晰的任务清理机制。


结论

迁移到基于 UIKit 场景的生命周期可以使你的应用支持多窗口等现代 iOS 功能。无论选择分阶段迁移还是直接迁移,关键步骤都是创建一个 UISceneDelegate 类,配置 Info.plist,并将生命周期事件处理从 UIApplicationDelegate 移动到 UISceneDelegate。迁移后,每个窗口将由独立的场景管理,从而提高模块化并为用户提供更强大的多任务处理体验。