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

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

在此页面上

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

您可以使用SwiftUI BackgroundTask 以在您的应用处于背景时更新同步域 。此示例演示了如何在iOS应用中配置和执行背景同步。

您可以使用 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 中创建或更改数据,但不应看到它反映在设备上。

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

后退

处理同步错误