使用 SwiftUI 在后台同步数据 - Swift SDK
在此页面上
概述
You can use a SwiftUI BackgroundTask to update a Synced realm when your app is in the background. This example demonstrates how to configure and perform background Syncing in an iOS app.
您可以使用 SwiftUI Device Sync 模板应用程序按照此页面上的示例进行操作。 要获取您自己的SwiftUIDevice Sync Device SyncSwiftUIGoPrerequisitesStart with the Template模板应用程序副本,请查看 Device Sync 通读 和 部分。
为应用启用后台模式
要为您的应用启用后台任务,则执行以下操作:
安排后台任务
为您的应用启用后台进程后,您可以开始向应用添加代码,以安排和执行后台任务。首先,在您要编写此代码的文件中导入 BackgroundTasks
:
import SwiftUI import RealmSwift import BackgroundTasks
现在,您可以添加已计划后台任务。如果您正在通过模板应用跟进,可以更新您的 @main
视图:
@main struct realmSwiftUIApp: SwiftUI.App { private var phase (\.scenePhase) var body: some Scene { WindowGroup { ContentView(app: realmApp) } .onChange(of: phase) { newPhase in switch newPhase { case .background: scheduleAppRefresh() default: break } } }
您可以添加环境变量来存储对 scenePhase
: @Environment(\.scenePhase) private var phase
的更改。
然后,您可以添加.onChange(of: phase)
区块,以便在应用程序进入背景时调用scheduleAppRefresh()
功能。
创建 scheduleAppRefresh()
函数:
func scheduleAppRefresh() { let backgroundTask = BGAppRefreshTaskRequest(identifier: "refreshTodoRealm") backgroundTask.earliestBeginDate = .now.addingTimeInterval(10) try? BGTaskScheduler.shared.submit(backgroundTask) }
这会安排执行后台任务的工作,该任务的标识符在启用后台模式时添加到上述 Info.plist 中。在此示例中,标识符 refreshTodoRealm
系指该任务。
创建后台任务
既然已经安排了后台任务,就需要创建运行以更新同步 Realm 的后台任务。
如果您是按模板应用进行操作,则可在 .onChange(of: phase)
之后将此 backgroundTask
添加到 @main
视图:
.onChange(of: phase) { newPhase in switch newPhase { case .background: scheduleAppRefresh() default: break } } .backgroundTask(.appRefresh("refreshTodoRealm")) { guard let user = realmApp.currentUser else { return } let config = user.flexibleSyncConfiguration(initialSubscriptions: { subs in if let foundSubscription = subs.first(named: "user_tasks") { foundSubscription.updateQuery(toType: Item.self, where: { $0.owner_id == user.id }) } else { subs.append(QuerySubscription<Item>(name: "user_tasks") { $0.owner_id == user.id }) } }, rerunOnOpen: true) await refreshSyncedRealm(config: config) }
此后台任务首先会检查您的应用是否有已登录用户。 如果是这样,它会设置.FlexibleSyncConfiguration 具有订阅,应用程序可以使用它来同步 Realm。
这与模板应用的ContentView
中使用的配置相同。 但是,要在这里使用它,您需要在视图层次结构的更高层访问它。 您可以将其重构为一个函数,您可以从任一视图调用该函数,该函数将User作为参数并返回Realm.configuration。
最后,此任务等待实际同步 realm 的函数的结果。添加此函数:
func refreshSyncedRealm(config: Realm.Configuration) async { do { try await Realm(configuration: config, downloadBeforeOpen: .always) } catch { print("Error opening the Synced realm: \(error.localizedDescription)") } }
通过打开此同步 realm 并使用 downloadBeforeOpen
参数指定您要下载更新,您可以在后台将新数据加载到该 realm 中。然后,当您的应用再次打开时,它已经在设备上拥有更新的数据。
重要
不要尝试在此后台任务中直接写入 realm。由于 Realm 的线程限制架构,您可能会遇到与线程相关的问题。
测试您的后台任务
安排后台任务时,您需要设置系统可以执行任务的最早时间。但是,操作系统会考虑许多其他因素,这些因素可能会在已计划的 earliestBeginDate
之后很长时间内延迟后台任务的执行。您可以设置断点并使用 LLDB 调用任务,而不是等待设备运行后台任务来验证其是否执行了您想要的操作。
配置设备以运行您的应用
要测试您的后台任务是否正在后台更新同步 Realm,您需要一台至少运行 iOS 16的物理设备。 您的设备必须配置为在 开发者模式下 运行 。如果收到Untrusted Developer
通知,请Go Settings、General和VPN & Device Management。 在这里,您可以验证是否要运行正在开发的应用程序。
可在设备上成功运行该应用后,便可测试后台任务。
设置断点
首先在 scheduleAppRefresh()
函数中设置断点。在将任务提交给 BGTaskScheduler
之后设置断点。在本例中,您可以添加 print
行,并在打印行处设置断点:
func scheduleAppRefresh() { let backgroundTask = BGAppRefreshTaskRequest(identifier: "refreshTodoRealm") backgroundTask.earliestBeginDate = .now.addingTimeInterval(10) try? BGTaskScheduler.shared.submit(backgroundTask) print("Successfully scheduled a background task") // Set a breakpoint here }
在 Atlas 中添加或更改数据
当应用处于背景但仍在 Xcode 中运行时,在相关 Atlas 集合中插入一个应同步到设备的新文档。或者,更改从设备创建的现有文档的值。成功运行背景任务后,应会看到这些数据从背景进程同步到该设备。
如果您使用的是 SwiftUI 模板应用,则可以在 Atlas 集群的Item
集合中找到相关文档。 有关如何在 Atlas 中添加或更改文档的更多信息,请参阅: MongoDB Atlas:创建、查看、更新和删除文档。
在 LLDB 中调用后台任务
使用此命令在 LLDB 中手动执行后台任务:
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"refreshTodoRealm"]
如果您为后台任务使用不同的标识符,则将 refreshTodoRealm
替换为您的任务的标识符。这会导致任务立即开始执行。
如果成功,则应看到如下所示内容:
2022-11-11 15:09:10.403242-0500 App[1268:196548] Simulating launch for task with identifier refreshTodoRealm 2022-11-11 15:09:16.530201-0500 App[1268:196811] Starting simulated task
启动该任务后,使用 Xcode 调试面板中的 Continue program execution(继续执行程序)按钮以继续运行该应用。