Docs Menu
Docs Home
/ /
Interfaz de usuario rápida

Sincronizar datos en segundo plano con SwiftUI - Swift SDK

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.

Para habilitar tareas en segundo plano para tu aplicación:

1

Seleccione su aplicación de destino, vaya a la pestaña Signing & Capabilities y haga clic en + Capability para agregar la capacidad.

Captura de pantalla de Xcode con la aplicación Target seleccionada, la pestaña Firma y capacidades abierta y una flecha que apunta para agregar capacidades.
haga clic para ampliar

Busque “fondo” y seleccione Background Modes.

2

Ahora debería ver una sección Background Modes en su pestaña Signing & Capabilities. Expanda esta sección y haga clic en las casillas de verificación para habilitar Background fetch y Background processing.

3

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.

Después de habilitar los procesos en segundo plano para tu aplicación, puedes empezar a añadir el código para programar y ejecutar una tarea en segundo plano. Primero, importa BackgroundTasks en los archivos donde escribirás este código:

import SwiftUI
import RealmSwift
import BackgroundTasks

Ahora puedes agregar una tarea programada en segundo plano. Si sigues el proceso desde la aplicación de plantillas, puedes actualizar tu vista @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
}
}
}

Puede agregar una variable de entorno para almacenar un cambio en scenePhase: @Environment(\.scenePhase) private var phase.

Luego, puedes agregar el bloque .onChange(of: phase) que llama a la función scheduleAppRefresh() cuando la aplicación pasa a segundo plano.

Crea la función scheduleAppRefresh():

func scheduleAppRefresh() {
let backgroundTask = BGAppRefreshTaskRequest(identifier: "refreshTodoRealm")
backgroundTask.earliestBeginDate = .now.addingTimeInterval(10)
try? BGTaskScheduler.shared.submit(backgroundTask)
}

Esto programa el trabajo para ejecutar la tarea en segundo plano cuyo identificador agregó al archivo Info.plist anterior al habilitar los modos en segundo plano. En este ejemplo, el identificador refreshTodoRealm se refiere a esta tarea.

Ahora que ha programado la tarea en segundo plano, debe crear la tarea en segundo plano que se ejecutará para actualizar el reino sincronizado.

Si está siguiendo la aplicación de plantilla, puede agregar este backgroundTask a su vista @main, después del .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.

Esta es la misma configuración que se usa en la aplicación de ContentView plantilla. Sin embargo, para usarla aquí, necesita acceder a ella en un nivel superior de la jerarquía de vistas. Podría refactorizarla a una función que pueda llamarse desde cualquier vista y que tome un usuario como parámetro y devuelva un archivo Realm.configuration.

Finalmente, esta tarea espera el resultado de una función que realmente sincroniza el dominio. Agregue esta función:

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

No intente escribir directamente en el dominio en esta tarea en segundo plano. Podría experimentar problemas de subprocesos debido a la arquitectura limitada por subprocesos de Realm.

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.

1

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.

2

Comience estableciendo un punto de interrupción en su scheduleAppRefresh() función. Establezca el punto de interrupción después de la línea donde envía la tarea BGTaskScheduler a. Para este ejemplo, podría agregar una print línea y establecer el punto de interrupción en la línea de impresión:

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

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.

Luego, mientras la aplicación se ejecuta en Xcode, envíela a segundo plano en su dispositivo. Debería ver en la consola el mensaje "Tarea en segundo plano programada correctamente" y luego un mensaje de LLDB.

4

Mientras la aplicación está en segundo plano, pero aún se ejecuta en Xcode, inserte un nuevo documento en la colección de Atlas correspondiente que se sincronizará con el dispositivo. Como alternativa, cambie el valor de un documento existente creado desde el dispositivo. Tras ejecutar correctamente la tarea en segundo plano, debería ver estos datos sincronizados con el dispositivo desde el proceso en segundo plano.

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.

5

Utilice este comando para ejecutar manualmente la tarea en segundo plano en LLDB:

e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"refreshTodoRealm"]

Si usó un identificador diferente para su tarea en segundo plano, reemplace refreshTodoRealm con el identificador de su tarea. Esto hace que la tarea comience a ejecutarse inmediatamente.

Si tiene éxito, debería 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.

6

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.

7

Abre la aplicación en el dispositivo. Deberías ver los datos actualizados que modificaste en Atlas.

Para verificar que las actualizaciones llegaron a través de la tarea en segundo plano, confirme que haya deshabilitado exitosamente la red.

Crea una nueva tarea con la app. Deberías ver la tarea en la app, pero no debería sincronizarse con Atlas. También puedes crear o modificar datos en Atlas, pero no deberías verlos reflejados en el dispositivo.

Esto le indica que la red se ha deshabilitado correctamente y que los datos actualizados que ve provienen de la tarea en segundo plano.

Volver

Manejar errores de sincronización