其他
需要在 iOS 26+ 上通过系统编排实现 App…
适用于实现系统编排的跨平台一次性 App 数据迁移、构建 AppMigrationExtension,并在目标设备导入资源、上报进度和处理迁移结果。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 57/100 ×0.15
适用场景
需要在 iOS 26+ 上通过系统编排实特定
解决思路
- 确认版本要求:AppMigrationKit API 为 iOS 26.0+/iPadOS 26.0+,data-container entitlement 为 iOS 26.1+/iPadOS 26.1+/Mac Catalyst 26.1+,Swift 6.3;AppMigrationKit 在 iOS 26 为 beta,依赖具体 API 前重新查阅 Apple 当前文档。
- 按三层架构实现:1) 提供符合 AppMigrationExtension 的 App Extension,处理数据导出和导入;2) 系统负责设备到设备的会话、传输和调度,扩展不控制何时运行;3) 容器 App 在迁移完成后首次启动检查 MigrationStatus.importStatus 判断是否迁移及是否成功。
- 熟悉并选用关键类型:AppMigrationExtension 作为扩展入口协议,ResourcesExportingWithOptions 用于带选项导出,ResourcesExporting 用于简化导出,ResourcesImporting 用于目标端导入,ResourcesArchiver 流式写入导出归档,MigrationDataContainer 访问容器 App 数据目录,MigrationStatus 检查导入结果,MigrationPlatform 标识对端平台,MigrationAppIdentifier 标识来源 App,AppMigrationTester 用于测试。
- 在 Xcode 项目新增 App Extension target,并让扩展遵循一个或多个迁移协议:ResourcesExportingWithOptions、ResourcesExporting、ResourcesImporting。
- 为扩展添加 com.apple.developer.app-migration.data-container-access entitlement;其值为只包含容器 App bundle identifier 的单元素字符串数组,例如 com.example.myapp,不能放其他值;该 entitlement 使扩展导出时读、导入时写容器 App 数据容器。
- 导出时通过 appContainer/MigrationDataContainer 访问容器 App 文件:container.bundleIdentifier、container.containerRootDirectory、container.documentsDirectory、container.applicationSupportDirectory,它们是指向容器 App 沙盒的 URL。
- 导出扩展遵循 ResourcesExportingWithOptions;无自定义选项时用 ResourcesExporting。实现 resourcesSizeEstimate 返回估计导出总字节数(供系统进度 UI 和剩余空间检查),resourcesVersion 返回格式版本字符串(导入端据此处理版本化数据),resourcesCompressible 返回是否允许传输中压缩。
- 实现 exportResources(to:request:);在需要时读取 request.destinationPlatform 判断目标平台,例如 .android 时执行平台特定导出;MigrationPlatform 提供 .android 静态常量,也可用 MigrationPlatform("customPlatform") 创建自定义平台。
- 用 ResourcesArchiver 增量导出:反复调用 archiver.appendItem(at:) 逐个追加资源;用 archiver.appendItem(at:pathInArchive:) 指定归档内路径,例如 settings.plist 到 preferences/settings.plist;用 archiver.appendItem(at:pathInArchive:) 追加目录,例如 photos 到 media/photos。
- 避免导出过程中长时间没有 appendItem 调用:系统可能认为扩展挂起并终止;应按已知文件路径循环,将文件准备与归档交错进行,确保持续进展。
- 不要捕获 ResourcesArchiver 的取消错误:让它作为 CancellationError 自动抛出并传播;吞掉取消错误会导致系统杀掉扩展。
- 导出侧按原文件导出,不要先转换成中间格式(如 JSON)再归档,以免创建临时副本并耗尽磁盘空间;需要转换时在导入侧进行。
- 导入扩展遵循 ResourcesImporting,实现 importResources(at:request:);系统会在 App 安装后、可启动前调用,将 importedDataURL 中的文件复制到 appContainer,例如 documentsDirectory。
- 导入时读取 request.sourceVersion 处理版本化数据格式;读取 request.sourceAppIdentifier 获取 sourceApp.platform(如 .android)、sourceApp.bundleIdentifier(来源 App bundle ID)、sourceApp.storeIdentifier(如 .googlePlay)。
- 导入错误恢复时先清空 app group 容器再写入:系统在导入出错时会清空容器 App 数据容器以防部分状态,但不会清空 app group 容器;用 FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.example.myapp") 找到 group 后删除如 shared_data 的内容。
- 通过 resourcesImportProgress 暴露 Progress 对象给系统显示传输进度;在导入过程中按处理文件或其他工作单元逐步增加 completedUnitCount,例如按文件数计算增量,最后设为 totalUnitCount/100。
- 容器 App 在首次启动(如 application(_:didFinishLaunchingWithOptions:))检查 MigrationStatus.importStatus:nil 表示未发生迁移;.success 显示成功 UI 并调用 MigrationStatus.clearImportStatus();.failure(error) 显示失败 UI 并调用 MigrationStatus.clearImportStatus()。
- 处理完迁移结果后调用 MigrationStatus.clearImportStatus(),防止后续启动重复显示迁移通知。
- 测试时在容器 App 宿主的单元测试中使用 test-only actor AppMigrationTester,不要用于生产;例如 let tester = try await AppMigrationTester(platform: .android),用 tester.exportController.exportResources(request: nil, progress: nil) 导出,再用 tester.importController.importResources(from: result.extractedResourcesURL, importRequest: nil, progress: nil) 导入,并调用 tester.importController.registerImportCompletion(with: .success)。
- 测试中检查 DeviceToDeviceExportProperties:uncompressedBytes、compressedBytes(不可压缩时为 nil)、sizeEstimate、version;可参考 references/appmigrationkit-patterns.md 获取更多测试模式(组合扩展、版本化迁移、文件枚举、错误恢复)。
- 按 review checklist 自查:Extension target 与 entitlement 已添加;entitlement 数组只含容器 App bundle ID;导出遵循 ResourcesExportingWithOptions 或 ResourcesExporting;导入遵循 ResourcesImporting;resourcesSizeEstimate 合理;resourcesVersion 已设置且导入端检查兼容性;导出增量 appendItem 且无长暂停;不捕获 ResourcesArchiver 取消错误;导入前清空 app group;容器 App 首次启动检查 MigrationStatus.importStatus;处理后 clearImportStatus();单元测试用 AppMigrationTester 验证;导出侧不转换中间格式;导入端使用 sourceVersion 处理版本化格式。
适用边界 · 注意事项
- 不适用于非 iOS 26.0+/iPadOS 26.0+ 或 Mac Catalyst 26.1+ 的环境,也不适用于需要完全自定义传输层或自管理设备间网络连接的场景。
- 不适用于需要持续同步、多次迁移或后台增量同步的场景;AppMigrationKit 面向系统编排的一次性迁移。
- AppMigrationTester 仅用于测试,不应在正式生产代码中使用。