Overview
Puedes utilizar una SwiftUI Tarea de fondo Para actualizar un dominio sincronizado cuando la aplicación está en segundo plano. Este ejemplo muestra cómo configurar y realizar la sincronización en segundo plano en una aplicación iOS.
Puede seguir el ejemplo de esta página utilizando la aplicación de plantilla de sincronización de dispositivos SwiftUI. Para obtener su propia copia de la aplicación de plantilla de sincronización de dispositivos SwiftUI, consulte el tutorial de sincronización de dispositivos SwiftUI y siga las instrucciones. Prerequisites y Start with the Template secciones.
Enable Background Modes for Your App
Para habilitar tareas en segundo plano para tu aplicación:
Actualizar el Info.plist
Vaya al Info.plist de su proyecto y agregue una nueva fila para
Permitted background task scheduler identifiersSi está viendo claves y valores sin procesar, la clave es BGTaskSchedulerPermittedIdentifiers. Este campo es una matriz. Añada un nuevo elemento para el identificador de su tarea en segundo plano. Establezca el valor del nuevo elemento en la cadena que desea usar como identificador para su tarea en segundo plano. Por ejemplo: refreshTodoRealm.
Programa una Tarea en Segundo Plano
After enabling background processes for your app, you can start adding the code to the app to schedule and execute a background task. First, import BackgroundTasks in the files where you will write this code:
import SwiftUI import RealmSwift import BackgroundTasks
Now you can add a scheduled background task. If you're following along via the Template App, you can update your @main view:
@main struct realmSwiftUIApp: SwiftUI.App { (\.scenePhase) private var phase var body: some Scene { WindowGroup { ContentView(app: realmApp) } .onChange(of: phase) { newPhase in switch newPhase { case .background: scheduleAppRefresh() default: break } } }
You can add an environment variable to store a change to the scenePhase: @Environment(\.scenePhase) private var phase.
Then, you can add the .onChange(of: phase) block that calls the scheduleAppRefresh() function when the app goes into the background.
Create the scheduleAppRefresh() function:
func scheduleAppRefresh() { let backgroundTask = BGAppRefreshTaskRequest(identifier: "refreshTodoRealm") backgroundTask.earliestBeginDate = .now.addingTimeInterval(10) try? BGTaskScheduler.shared.submit(backgroundTask) }
Esto cronograma el trabajo para ejecutar la tarea en segundo plano cuyo identificador agregaste al Info.plist anteriormente cuando habilitaste Modos en segundo plano. En este ejemplo, el identificador refreshTodoRealm se refiere a esta tarea.
Crear la tarea en segundo plano
Ahora que ha programado la tarea en segundo plano, debe crear la tarea en segundo plano que se ejecutará para actualizar el reino sincronizado.
If you're following along with the Template App, you can add this backgroundTask to your @main view, after the .onChange(of: phase):
.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) }
Esta tarea en segundo plano primero comprueba si un usuario ha iniciado sesión en la aplicación. De ser así, establece una configuración flexibleSyncConfiguration con una suscripción que la aplicación puede usar para sincronizar el dominio.
This is the same configuration used in the Template App's ContentView. However, to use it here you need access to it farther up the view hierarchy. You could refactor this to a function you can call from either view that takes a User as a parameter and returns a Realm.configuration.
Finally, this task awaits the result of a function that actually syncs the realm. Add this function:
func refreshSyncedRealm(config: Realm.Configuration) async { do { try await Realm(configuration: config, downloadBeforeOpen: .always) } catch { print("Error opening the Synced realm: \(error.localizedDescription)") } }
Al abrir este dominio sincronizado y usar el parámetro downloadBeforeOpen para especificar que desea descargar actualizaciones, carga los datos actualizados en el dominio en segundo plano. Al volver a abrir la aplicación, ya tendrá los datos actualizados en el dispositivo.
Importante
Do not try to write to the realm directly in this background task. You may encounter threading-related issues due to Realm's thread-confined architecture.
Test Your Background Task
Cuando cronograma una tarea en segundo plano, está estableciendo el tiempo más temprano en el que el sistema podría ejecutar la tarea. Sin embargo, el sistema operativo considera otros muchos factores que pueden retrasar la ejecución de la tarea en segundo plano mucho después de la earliestBeginDate programada. En lugar de esperar a que un dispositivo ejecute la tarea en segundo plano para verificar que hace lo que desea, puede establecer un punto de interrupción y usar LLDB para invocar la tarea.
Configure a Device to Run Your App
Para comprobar que tu tarea en segundo plano actualiza el dominio sincronizado, necesitarás un dispositivo físico con iOS como 16 mínimo. Tu dispositivo debe estar configurado para ejecutarse en modo desarrollador. Si recibes una Untrusted Developer notificación,Settings veGeneral a,VPN & Device Management y. Aquí puedes verificar que quieres ejecutar la aplicación que estás desarrollando.
Una vez que pueda ejecutar correctamente su aplicación en su dispositivo, puede probar la tarea en segundo plano.
Set a Breakpoint
Start by setting a breakpoint in your scheduleAppRefresh() function. Set the breakpoint after the line where you submit the task to BGTaskScheduler. For this example, you might add a print line and set the breakpoint at the print line:
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 }
Ejecutar la aplicación
Ahora, ejecuta la aplicación en el dispositivo conectado. Crea o inicia sesión en una cuenta en la aplicación. Si estás usando la aplicación plantilla de SwiftUI, crea algunos ítems. Deberías ver que los elementos se sincronizan con la colección Item vinculada a tu aplicación de Atlas App Services.
Then, while leaving the app running in Xcode, send the app to the background on your device. You should see the console print "Successfully scheduled a background task" and then get an LLDB prompt.
Add or Change Data in Atlas
While the app is in the background but still running in Xcode, Insert a new document in the relevant Atlas collection that should sync to the device. Alternately, change a value of an existing document that you created from the device. After successfully running the background task, you should see this data synced to the device from the background process.
Si usa la aplicación de plantillas SwiftUI, puede encontrar documentos relevantes en la colección de su clúster Item Atlas. Para obtener más información sobre cómo agregar o modificar documentos en Atlas, consulte: MongoDB Atlas: Crear, ver, actualizar y eliminar documentos.
Invocar la tarea en segundo plano en LLDB
Utilice este comando para ejecutar manualmente la tarea en segundo plano en LLDB:
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"refreshTodoRealm"]
If you have used a different identifier for your background task, replace refreshTodoRealm with your task's identifier. This causes the task to immediately begin executing.
Si es exitoso, deberías ver algo como:
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
Después de iniciar la tarea, utilice el botón Continue program execution en el panel de depuración de Xcode para reanudar la ejecución de la aplicación.
Turn on Airplane Mode on the Device
Después de esperar a que la tarea en segundo plano se complete, pero antes de abrir la aplicación nuevamente, activa el Modo Avión en el dispositivo. Asegúrate de que hayas apagado la WiFi. Esto garantiza que, al abrir la aplicación nuevamente, no inicie una nueva sincronización y solo se vean los valores que ahora están en el realm del dispositivo.
Abre la aplicación
Open the app on the device. You should see the updated data that you changed in Atlas.
To verify the updates came through the background task, confirm you have successfully disabled the network.
Crea una nueva tarea usando la aplicación. Deberías ver la tarea en la aplicación, pero no debería sincronizarse con Atlas. Alternativamente, puedes crear o modificar datos en Atlas, pero no deberías verlos reflejados en el dispositivo.
This tells you that the network has successfully been disabled, and the updated data that you see came through the background task.
