Docs 菜单
Docs 主页
/ /
Atlas Device SDKs
/ /

使用 SwiftUI 在后台同步数据 - Swift SDK

在此页面上

  • 概述
  • 为应用启用后台模式
  • 添加背景模式功能
  • 选择后台模式
  • 更新 Info.plist
  • 安排后台任务
  • 创建后台任务
  • 测试您的后台任务
  • 配置设备以运行您的应用
  • 设置断点
  • 运行应用
  • 在 Atlas 中添加或更改数据
  • 在 LLDB 中调用后台任务
  • 在设备上打开飞行模式
  • 打开应用

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 通读 和 部分。

要为您的应用启用后台任务,则执行以下操作:

1

选择应用目标,然后转到 Signing & Capabilities(签名和功能)标签页并单击 + Capability(+ 功能)以添加此功能。

Xcode 截图,其中选择了应用程序“目标”,打开了“签名和功能”选项卡,箭头指向“添加功能”。
点击放大

搜索“后台”,然后选择 Background Modes

2

现在您应该在 Signing & Capabilities 标签页中看到 Background Modes 部分。展开此部分,并单击复选框以启用 Background fetchBackground processing

3

转到项目的 Info.plist,然后为 Permitted background task scheduler identifiers 添加一个新行。如果您正在查看原始键和值,则键为 BGTaskSchedulerPermittedIdentifiers。该字段是一个数组。向其添加一个新项作为后台任务标识符。将新项的值设置为您计划用作后台任务标识符的字符串。例如:refreshTodoRealm

为您的应用启用后台进程后,您可以开始向应用添加代码,以安排和执行后台任务。首先,在您要编写此代码的文件中导入 BackgroundTasks

import SwiftUI
import RealmSwift
import BackgroundTasks

现在,您可以添加已计划后台任务。如果您正在通过模板应用跟进,可以更新您的 @main 视图:

@main
struct realmSwiftUIApp: SwiftUI.App {
@Environment(\.scenePhase) private var phase
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 调用任务,而不是等待设备运行后台任务来验证其是否执行了您想要的操作。

1

要测试您的后台任务是否正在后台更新同步 Realm,您需要一台至少运行 iOS 16的物理设备。 您的设备必须配置为在 开发者模式下 运行 。如果收到Untrusted Developer通知,请Go SettingsGeneralVPN & Device Management。 在这里,您可以验证是否要运行正在开发的应用程序。

可在设备上成功运行该应用后,便可测试后台任务。

2

首先在 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
}
3

现在,在连接的设备上运行该应用。在应用中创建或登录帐户。如果正在使用 SwiftUI 模板应用,则创建一些项目。您应该会看到这些项目会同步到链接至 Atlas App Services 应用的 Item 集合中。

然后让应用程序在 Xcode 中运行,在设备上将应用程序发送到后台。您应该会看到控制台打印出“成功调度后台任务”,然后出现 LLDB 提示。

4

当应用处于背景但仍在 Xcode 中运行时,在相关 Atlas 集合中插入一个应同步到设备的新文档。或者,更改从设备创建的现有文档的值。成功运行背景任务后,应会看到这些数据从背景进程同步到该设备。

如果您使用的是 SwiftUI 模板应用,则可以在 Atlas 集群的Item集合中找到相关文档。 有关如何在 Atlas 中添加或更改文档的更多信息,请参阅: MongoDB Atlas:创建、查看、更新和删除文档。

5

使用此命令在 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(继续执行程序)按钮以继续运行该应用。

6

等待背景任务完成后,再次打开应用程序之前,请打开设备上的飞行模式。确保已关闭 WiFi。 这可确保当您再次打开应用程序时,不会启动新的同步,并且您只能看到设备上 Realm 中的当前值。

7

在设备上打开应用。您应该可以看到在 Atlas 中更改的更新数据。

若要验证这些更新源自后台任务,则请确认已成功禁用该网络。

使用应用创建新任务。您应该在应用中看到任务,但它不应同步到 Atlas。或者,您可以在 Atlas 中创建或更改数据,但不应看到它反映在设备上。

此举可告知您已成功禁用网络,且您看到的更新后数据源自后台任务。

后退

处理同步错误

来年

使用 Realm 和 SwiftUI 预览