Sincronizar cambios offline con Mobile Sync
Objetivos de aprendizaje
Después de completar esta unidad, podrá:
- Comprender los conceptos básicos de Mobile Sync.
- Usar la biblioteca de Mobile Sync para sincronizar datos entre el dispositivo local del usuario y el servidor de Salesforce.
Uso de Mobile Sync para sincronizar cambios sin conexión
Mobile Sync es una biblioteca de Mobile SDK que funciona con SmartStore para garantizar la integridad y la coherencia de los registros de Salesforce. Mobile Sync permite a los clientes que usan aplicaciones de Mobile SDK que continúen editando los registros de Salesforce de forma local cuando sus dispositivos móviles pierden conectividad. Cuando se restablece la conectividad, la aplicación de Mobile SDK utiliza el marco para sincronizar los cambios locales en SmartStore con los registros correspondientes en el servidor de Salesforce.
Acerca de solicitudes de red
Todas las solicitudes de datos en aplicaciones de Mobile Sync son asíncronas. Los métodos de sincronización aplican formatos a la solicitud y la envían a la nube de Salesforce. Su aplicación recibe la respuesta del servidor en un método de devolución de llamada, un bloque de actualización o una promesa, según la plataforma. Las respuestas incluyen un objeto de estado de sincronización que describe el estado y la configuración de la operación de sincronización.
Los métodos de Mobile Sync automatizan las tareas de red habituales, como la obtención de metadatos de sObject y de una lista de objetos usados recientemente, y la generación de consultas SOQL y SOSL. Su aplicación puede llamar a los métodos del gestor de sincronización en cualquier momento, pero, sin duda, solo tendrán éxito cuando el dispositivo esté conectado a Internet. Su aplicación determina el estado de conexión del dispositivo.
Configuración de aplicaciones para que utilicen Mobile Sync
Las aplicaciones de Mobile SDK utilizan un objeto de gestor de SDK central para aplicar los protocolos de autenticación e inicio de aplicación correctos. El gestor que su aplicación utiliza también determina el ámbito de funciones de SDK incluido en la aplicación. Las aplicaciones inicializan el objeto MobileSyncSDKManager
durante la inicialización de arranque.
Los SDK de Android e iOS nativos implementan tres objetos de gestor.
SalesforceSDKManager
Para las aplicaciones más básicas. Estas aplicaciones no utilizan las funciones sin conexión de Mobile SDK.
SmartStoreSDKManager
Para aplicaciones que utilizan SmartStore, pero no Mobile Sync.
MobileSyncSDKManager
Para aplicaciones que utilizan SmartStore y Mobile Sync.
Cuando crea una aplicación nativa con forcedroid o forceios, su nueva aplicación se configura automáticamente para utilizar MobileSyncSDKManager
. Este gestor importa SmartStore, Mobile Sync y todas las otras bibliotecas de Mobile SDK.
Configuración de sincronización
Tanto si sincroniza de forma ascendente de SmartStore a Salesforce como si lo hace de forma descendente de Salesforce a SmartStore, debe proporcionar detalles de la configuración de sincronización. Puede configurar una operación de sincronización en código o en un archivo de configuración de JSON. En cualquier caso, en el momento de la ejecución, Mobile SDK devuelve la configuración a su aplicación como un objeto de estado de sincronización.
En el nivel más básico, proporciona:
- almacén (store): Indica si el almacén que está utilizando es un almacén global o un almacén de usuario. Si está utilizando un almacén denominado, también especifica su nombre.
- nombre de sopa (soup name): Nombre de la sopa que es la fuente para una operación de sincronización ascendente o el receptor para una operación de sincronización descendente. Esta sopa debe admitir un campo de cadena indexado llamado
__local__
.
Dos parámetros adicionales definen lo que hace la operación de sincronización:
- destino (target): Describe qué registros está sincronizando. El destino es el valor de configuración central para cualquier operación de sincronización. Piense en un destino como describir el ámbito de datos que requiere su operación.
- opciones (options): Controla de qué forma la operación combina datos. En algunos casos, puede utilizar opciones en vez de un destino para proporcionar una lista de nombres de campo para la sincronización.
El uso de los parámetros destino y opciones difiere entre la sincronización ascendente y la sincronización descendente, como se describe en las siguientes secciones. En algunos casos, uno o el otro parámetro puede ser opcional. Si omite el destino o las opciones, que son optativos, Mobile Sync asume un valor predeterminado.
Después de que se completa una operación de sincronización, su aplicación recibe notificaciones asíncronas que le permiten realizar tareas de seguimiento. Estas tareas podrían incluir el envío de notificaciones de eventos, el éxito de la operación de registro y el uso de los datos de tal forma que mejoren la aplicación.
Opciones y destino de sincronización descendente
- destino (target): Especifica el tipo de sObject de origen y los campos para descargar en la sopa. Puede utilizar cualquiera de las siguientes cadenas:
- Para consultas SOQL:
{type:"soql", query:"<soql_query>"}
Descarga los sObjects que muestra la consulta SOQL. - Para consultas SOSL:
{type:"sosl", query:"<sosl_query>"}
Descarga los sObjects que muestra la consulta SOSL. - Para consultas MRU:
{type:"mru", sobjectType:"<sobject_type>", fieldlist:"<fields_to_fetch>"}
Descarga los campos especificados de los sObjects del tipo de sObject especificado usados más recientemente. Mobile SDK envía la solicitud a Salesforce, recibe la respuesta y utiliza su configuración para rellenar su sopa.
- Para consultas SOQL:
- opciones (options): (Optativo) Mapa con la clave que se indica a continuación:
mergeMode
: Con el fin de controlar la forma en que Mobile Sync combina datos en las sopas locales, establezca uno de los siguientes modos para esta clave:
Sobrescribir
(Predeterminado) Sobrescribe los registros que fueron modificados. Si no especifica un modo de combinación, Mobile Sync sobrescribe los datos locales.
Dejar si se cambia
Conserva registros que se modificaron. Este modo requiere recorridos adicionales al servidor, por lo que utilícelo con cuidado.
Opciones y destino de sincronización ascendente
- destino (target): Mapa con una de las claves que se indican a continuación o ambas:
createFieldlist
: Nombres de campos de sopa separados por coma cuyos valores se deben insertar en registros de Salesforce recién creados. Puede incluir campos (solo lectura) bloqueados.updateFieldlist
: Nombres de campos de sopa separados por coma que se utilizan para actualizar campos que admiten escritura en registros de Salesforce existentes. No puede incluir campos (solo lectura) bloqueados.
- El destino no es obligatorio en algunos métodos de sincronización ascendente. En estos casos, utiliza la clave
fieldlist
enoptions
para especificar qué campos sincronizar. - opciones (options): (Optativo) Mapa con una o más de las claves que se indican a continuación:
fieldlist
: Lista de nombres de campo de sopa que está enviando al servidor separados por coma. Puede utilizar esta clave en vez de las listas de campotarget
o concreateFieldList
de su destino. Asegúrese de que su operación de sincronización ascendente no intenta actualizar los campos de solo lectura en el servidor.mergeMode
: Con el fin de controlar la forma en que Mobile Sync combina datos locales en la organización de Salesforce, establezca uno de los siguientes modos para esta clave:
Sobrescribir
(Configuración predeterminada) Sobrescribe registros del servidor que fueron modificados.
Dejar si se cambia
Conserva registros que se modificaron. Este modo requiere recorridos adicionales al servidor, por lo que utilícelo con cuidado.
Parámetro de almacén
Las aplicaciones React Native e híbridas indican el almacén que están utilizando a través de un parámetro storeConfig opcional. Este parámetro se aplica a operaciones de sincronización ascendente y sincronización descendente. Puede especificarlo en cualquiera de las dos formas.
Como un mapa de los siguientes pares clave-valor:
- isGlobalStore: (Opcional) Booleano indicando si está utilizando un almacén global (
true
) o un almacén de usuario (false
). El valor predeterminado esfalse
. - storeName: (Opcional) Nombre del almacén. El valor predeterminado es el nombre del almacén predeterminado.
Por ejemplo:
{"isGlobalStore" : false, "storeName" : "MyStore"}
Como un booleano:
Puede en su lugar pasar un valor Booleano sencillo. En este caso, Mobile SDK le asigna el valor a la clave isGlobalStore.
Si omite el parámetro almacén, Mobile Sync realiza las operaciones en el almacén de usuario actual.
Uso de sincronizaciones denominadas y archivos de configuración de sincronización
Los métodos de sincronización ascendente y sincronización descendente estándar requieren que pase cada parámetro de sincronización como un argumento separado. Mobile SDK proporciona dos nuevas funciones que ayudan a organizar y simplificar estos esfuerzos de sincronización. Estas funciones son nombres de sincronización y archivos de configuración de sincronización, y le proporcionan un interesante beneficio por un esfuerzo mínimo. Aunque no es obligatorio utilizar archivos de configuración, los utilizamos mucho en esta ruta.
Para volver a ejecutar una sincronización, se utiliza el método reSync
de la plataforma. Los métodos de resincronización utilizan uno de estos identificadores para buscar su configuración.
- Id. de sincronización: Cada método de sincronización muestra un Id. del tiempo de ejecución como parte de un objeto de estado. Puede pasar este Id. a
reSync
para volver a ejecutar una sincronización que ya utilizó en la sesión actual. - Nombre de la sincronización (opcional): Puede asignarle un nombre a la configuración de sincronización en la memoria la primera vez que la ejecuta, o puede importar el nombre y su configuración de sincronización de un archivo JSON externo.
Nombres de sincronización
Las operaciones de sincronización pueden ser complicadas para configurar y tienden a ser reutilizadas a menudo. Los nombres de sincronización resultan convenientes porque le permiten ejecutar nuevamente las sincronizaciones sin volver a codificarlas. Por ejemplo, puede utilizar nombres de sincronización para
- Configurar operaciones de sincronización en un archivo JSON externo en lugar de hacerlo en código
- Volver a ejecutar una operación de sincronización que ya se usó sin la necesidad de volver a configurarla
- Obtener el estado de una operación de sincronización en curso
- Comprobar la existencia de una configuración de sincronización
- Eliminar una configuración de sincronización
Puede crear sincronizaciones denominadas ya sea con las API o en archivos de configuración de sincronización. Mobile SDK admite sincronizaciones denominadas en todas las plataformas para todos los tipos de aplicaciones.
Archivos de configuración de sincronización
Gracias a los archivos de configuración de sincronización, puede redactar definiciones estáticas de sincronización ascendente y descendente solo una vez en un archivo JSON, y luego importarlas en todas las versiones de sus aplicaciones. Mobile SDK admite archivos de configuración de sincronización en aplicaciones híbridas y nativas. Echemos un vistazo a la estructura y las reglas para estos archivos.
Nombres de archivo
Mobile SDK admite archivos de configuración únicamente para el almacén global y el almacén de usuario predeterminados.
- Para el almacén global predeterminado, proporcione un archivo con el nombre globalsyncs.json.
- Para el almacén de usuario predeterminado, proporcione un archivo con el nombre usersyncs.json.
Ubicaciones de los archivos
Coloque sus archivos de configuración en las siguientes ubicaciones.
iOS:
- Aplicaciones nativas y React Native: / en el paquete Recursos
- Aplicaciones híbridas: /www en el paquete Recursos
Android:
- Aplicaciones nativas y React Native: /res/raw
- Aplicaciones híbridas: /assets/www
Formato de archivo
El formato de archivo es el mismo independientemente del tipo de aplicación o la plataforma de destino. Una definición de sincronización requiere cinco campos:
- Nombre de sincronización
- Tipo de sincronización
- Nombre de sopa
- Destino
- Opciones
El siguiente archivo de configuración define operaciones de sincronización ascendente y descendente. Ambas configuraciones utilizan los mismos campos: Id., Name y LastModifiedDate. Sin embargo, observe dos reglas significativas para la ubicación de los valores:
- La configuración de sincronización descendente especifica los campos en el miembro “destino”, utilizando una consulta de SOQL, mientras que la sincronización ascendente los especifica bajo “opciones” como una lista.
- La operación de sincronización descendente especifica su modo e combinación en “iones” mientras que la sincronización ascendente hace lo mismo en "merge_mode".
Los modos de combinación opuestos, como “OVERWRITE” para la sincronización descendente frente a “LEAVE_IF_CHANGED” para sincronización ascendente, garantizan una fuente de la verdad única. En este caso, permiten a los datos del servidor sobrescribir datos de sopa, pero no a la inversa.
{ "syncs": [ { "syncName": "sync1", "syncType": "syncDown", "soupName": "accounts", "target": {"type":"soql", "query":"SELECT Id, Name, LastModifiedDate FROM Account"}, "options": {"mergeMode":"OVERWRITE"} }, { "syncName": "sync2", "syncType": "syncUp", "soupName": "accounts", "target": {"createFieldlist":["Name"]}, "options": {"fieldlist":["Id", "Name", "LastModifiedDate"], "mergeMode":"LEAVE_IF_CHANGED"} } ] }
Uso de Mobile Sync con maletines
Un maletín es un conjunto de consultas que permiten seleccionar una recopilación coherente de registros relacionados, optimizados para sus necesidades. Puede usar maletines a fin de seleccionar registros para la inicialización de datos antes de desconectarse y para otros fines generales de carga de datos.
Configuración de sincronización
En la aplicación de plantillas del explorador de Mobile Sync, puede actualizar el archivo JSON de sincronización del usuario a fin de configurar las operaciones de sincronización descendente y ascendente.
Para la propiedad "target", especifique los siguientes valores.
Propiedades de destino
"type":"briefcase"
"infos": matriz de elementos de <BriefcaseObjectInfo>
Una matriz de objetos que describe los sObjects y campos específicos para recuperar, junto con la sopa donde se los colocará.
Propiedades de BriefcaseObjectInfo
"soupName": <string>
Nombre de la sopa o tabla donde se almacenan los registros de este tipo de objeto durante la sincronización.
"sobjectType": <string>
Nombre de un objeto de Salesforce que se sincronizará.
"fieldlist": matriz de <string>
Lista de campos para sincronizar de este objeto.
"idFieldName": <string>
(Opcional) Nombre de un campo de identificación personalizado. Si proporciona "idFieldName", Mobile Sync usa el campo con el nombre dado para obtener la identificación del registro. Por ejemplo, si especifica "idFieldName":"AcmeId", Mobile Sync obtiene la identificación del registro a partir del campo AcmeId y no del campo ID predeterminado.
"modificationDateFieldName": <string>
(Opcional) Nombre del campo que contiene la fecha de la última modificación del registro. Si proporciona modificationDateFieldName, Mobile Sync usa el campo con este nombre para computar el valor de maxTimestamp que startFetch utiliza para volver a sincronizar los registros. El nombre de campo predeterminado es lastModifiedDate.
Obligatorio: “soupName”, “sobjectType”, “fieldlist”
Sincronización descendente
Veamos un ejemplo de un archivo de maletín configurado para la sincronización descendente.
{ "syncs": [ { "syncName": "syncDownContacts", "syncType": "syncDown", "soupName": "contacts", "target": { "type": "briefcase", "infos": [ { "sobjectType": "Account", "fieldlist": [ "Name", "Description" ], "soupName": "accounts" }, { "sobjectType": "Contact", "fieldlist": [ “FistName”, "LastName", “Title”, “Email” ], "soupName": "contacts" } ] }, "options": { "mergeMode": "OVERWRITE" } } ] }
Para realizar ese tipo de sincronización, defina “syncType
” como “syncDown”
. Se activará la operación de sincronización descendente, que sincroniza los datos en el sentido del servidor hacia el cliente. Puede asignarle un nombre a la operación en “syncName”
. En este caso, se denomina “syncDownContacts”
.
Junto a “soupName”
, defina la tabla o sopa que desea actualizar cuando se lleve a cabo la operación de sincronización descendente. En este caso, se actualiza la sopa de contactos denominada “contacts”
.
Debajo de “target”
, defina “briefcase”
como el tipo de destino. Debajo del objeto JSON “infos”
, puede definir las entidades que desea sincronizar, que en este caso son las siguientes: “Account”
(cuenta) y “Contact”
(contacto). Para cada entidad, asigne los campos que desea sincronizar en “fieldlist”
.
Para cada entidad, asigne la tabla correspondiente que desea actualizar en el cliente junto a “soupName”
.
En “options”
, puede definir la opción “mergeMode”
, que en este caso se establece en “OVERWRITE”
(sobrescribir). Si dos usuarios intentan actualizar el mismo registro, esta opción asigna la prioridad de sobrescritura al último usuario que lo actualizó.
Sincronización ascendente
Ahora veamos la configuración de una sincronización ascendente.
{ “syncName: “syncUpContacts”, “syncType”: “syncUp”, “soupÑame”: “contacts”, “target”: { “createFieldlist”: [ “FirstName”, “LastName”, “Title”, “Email” ] }, “options”: { “fieldlist”: [ “FirstName”, “LastName”, “Title”, “Email” ], “mergeMode”: “LEAVE_IF_CHANGED” } }
Para realizar la operación de sincronización ascendente, configure una tabla mediante “soupName”
, que en este caso se denomina “contacts”
. Use “target”
y “options”
para asignar los campos que desea sincronizar. En este caso, “mergeMode”
se establece en “LEAVE_IF_CHANGED”
. Si se modificó algún registro del servidor desde la sincronización descendente para ese cliente, los registros tanto del servidor como del cliente se conservan en su estado actual.
Uso de Mobile Sync en aplicaciones iOS nativas
Sincronización descendente
Para la descarga de registros de Salesforce en su sopa de SmartStore, Mobile Sync le ofrece varias opciones.
Puede crear una configuración de sincronización descendente sin ejecutarla:
var syncState = syncManager.createSyncDown(target: target, options: options, soupName: CONTACTS_SOUP, syncName: syncState.syncName)
O bien puede crear y ejecutar una operación de sincronización descendente sin nombre sin opciones, pero se advierte de que sobrescribe cualquier cambio local:
var syncState = syncManager.syncDown(target: target, soupName: CONTACTS_SOUP, onUpdate:updateFunc)
Para más control, puede crear y ejecutar una configuración de sincronización descendente sin nombre que utiliza sus opciones.
var syncState = syncManager.syncDown(target: target, options: options, soupName: CONTACTS_SOUP, onUpdate:updateFunc)
O bien puede crear, asignar un nombre y ejecutar una configuración de sincronización descendente:
var syncState = try syncManager.syncDown(target: target, options: options, soupName: CONTACTS_SOUP, syncName: syncState.syncName, onUpdate:updateFunc)
La clase SyncTarget
proporciona métodos de fábrica para la creación de objetos de destino a partir de una cadena de consultas SOQL, SOSL o MRU. Usted especifica los objetos para descargar con una cadena de consulta SOQL o SOSL. Si utiliza un destino de consulta MRU, especifica únicamente una lista de nombres de campo. Mobile SDK informa el progreso de la operación de sincronización mediante el método de devolución de llamada o el bloque de actualización que implemente.
Para aplicaciones iOS nativas, la opción mergeMode
puede ser uno de los siguientes valores:
SFSyncStateMergeModeOverwrite
: Sobrescribir los registros locales modificados y perder todos los cambios locales.SFSyncStateMergeModeLeaveIfChanged
: Conservar todos los cambios locales y registros modificados localmente.
Sincronización ascendente
Durante la sincronización ascendente, Mobile Sync copia registros de sopa creados, actualizados y eliminados en el servidor. Mobile SDK proporciona un destino predeterminado que puede utilizar en vez de definir uno propio. El destino predeterminado es sencillo y directo: mediante el uso de la API de Salesforce, simplemente, sincroniza los registros modificados desde la sopa al servidor.
Si tiene un destino, puede crear una operación de sincronización ascendente sin ejecutarla:
let syncState = syncManager.createSyncUp(target: target, options: options, soupName: CONTACTS_SOUP, syncName: syncState.syncName)
Puede utilizar el destino predeterminado con el siguiente método MobileSyncManager
:
let syncState = syncManager.syncUp(options: options, soupName: CONTACTS_SOUP, onUpdate: updateFunc)
Si tiene un destino de sincronización ascendente personalizado, puede ejecutarlo al llamar a este método:
let syncState = syncManager.syncUp(target: target, options: options, soupName: CONTACTS_SOUP, onUpdate: updateFunc)
O bien puede crear, asignar un nombre y ejecutar una operación de sincronización:
let syncState = try syncManager.syncUp(target: target, options: options, soupName: CONTACTS_SOUP, syncName: syncState.syncName, onUpdate: updateFunc)
Volver a sincronizar
Los métodos de resincronización son versátiles y fáciles de codificar. Aunque son importantes, a veces se los pasa por alto. Estos métodos ejecutan configuraciones de sincronización que definió previamente en otra ubicación. A pesar del nombre, puede utilizar estos métodos para ejecutar una sincronización con nombre por primera vez. Los métodos de resincronización sincronizan únicamente registros que se crearon y se actualizaron desde la última sincronización. Si la sincronización nunca se ejecutó, la resincronización copia todos los registros nuevos o modificados. De lo contrario, realiza una sincronización incremental.
Para utilizar los métodos de resincronización, proporcione un Id. de sincronización desde una sincronización anterior o un nombre de sincronización predefinido. Para ejecutar una sincronización con nombre existente:
var syncState = try syncManager.reSync(named: syncState.syncName, onUpdate: updateFunc)
Si almacenó en caché el valor SFSyncState.syncId
, obtenido de una operación de sincronización sin nombre anterior, puede utilizarlo para volver a ejecutar esa sincronización:
var syncState = try syncManager.reSync(id: syncState.syncId, onUpdate: updateFunc)
Los métodos reSync
admiten tanto configuraciones de sincronización ascendente como descendente.
Ejemplo
Las aplicaciones Swift nativas creadas con forceios utilizan una plantilla que demuestra las funciones básicas de SmartStore y Mobile Sync. Esta plantilla utiliza publicadores de Combine para que SmartStore y Mobile Sync simplifiquen su código. Estos publicadores están disponibles en Mobile SDK como extensiones de las clases de SmartStore y MobileSync. Veamos cómo se llevó a cabo esta implementación en el proyecto iOSNativeSwiftTemplate.
Lo primero que debe hacer es crear una aplicación para la exploración.
- En una ventana de terminal, cree una aplicación con forceios.
- Utilice el tipo de aplicación
native_swift
. - Resulta conveniente que asigne el nombre
offlineSwift
a la aplicación.
- Utilice el tipo de aplicación
- Cuando forceios finalice, abra el nuevo espacio de trabajo en Xcode.
Allí, consulte la configuración de las funciones sin conexión.
- En el navegador de proyectos (⌘1), expanda offlineSwift > offlineSwift > Supporting Files. Aquí, encontrará los archivos
userstore.json
yusersyncs.json
. Si los abre en la ventana Editor, verá que definen las configuraciones básicas para acceder a los registros de cuentas y sincronizarlos. - La plantilla agrega los archivos
userstore.json
yusersyncs.json
al paquete de la aplicación en la configuración Project Build Phases (Fases de compilación del proyecto).- En el navegador de proyectos de Xcode, seleccione el nodo del proyecto.
- En la ventana Editor, seleccione Build Phases (Construir fases).
- Amplíe Copy Bundle Resources (Copiar recursos de paquete). Tenga en cuenta que aparecerán los archivos
userstore.json
yusersyncs.json
, lo que significa que se agregan al paquete de la aplicación al compilarla.
Ahora, examinemos el código.
- En el navegador de proyectos, expanda offlineSwift > offlineSwift > Classes > SwiftUI.
- En
SceneDelegate.swift
, la plantilla agrega una funciónsetupRootViewController()
que carga las configuraciones sin conexión a la memoria. Intencionalmente, se llama a esta función solo una vez por sesión de usuario. Es importante recordar que no se puede llamar a estos métodos de configuración más de una vez por sesión ni es posible utilizarlos para cargar un conjunto diferente de configuraciones.// Set up store based on config userstore.json MobileSyncSDKManager.shared.setupUserStoreFromDefaultConfig() // Set up syncs based on config usersyncs.json MobileSyncSDKManager.shared.setupUserSyncsFromDefaultConfig()
- En el navegador de proyectos, expanda offlineSwift > offlineSwift > Classes > Models.
- En
AccountsListModel.swift
, observe la primera línea de la claseAccountsListModel
. Esta línea define una matriz publicada vacía de objetos de cuentas. Los objetos SwiftUI de la aplicación se suscriben aAccountsListModel
con el fin de recibir actualizaciones cuando la matriz publicada cambia./** ViewModel for Account List */ class AccountsListModel: ObservableObject { @Published var accounts: [Account] = [] ...
- Busque la función
fetchAccounts()
.func fetchAccounts(){ syncTaskCancellable = syncManager?.publisher(for: "syncDownAccounts") .receive(on: RunLoop.main) .sink(receiveCompletion: { _ in }, receiveValue: { _ in self.loadFromSmartStore() }) self.loadFromSmartStore() }
En este caso, el publicador de Mobile Sync toma una operación de sincronización denominada “syncDownAccounts”, definida en el archivousersyncs.json
, y vuelve a sincronizarla. Luego, copia los datos obtenidos en sopas en el almacén de SmartStore predeterminado. CuandofetchAccounts()
recibe la respuesta del publicador, llama aloadFromSmartStore()
para copiar de manera asíncrona los datos actualizados desde SmartStore a la matriz publicadaaccounts
. Mientras espera que llegue la respuesta,fetchAccounts()
también llama aloadFromSmartStore()
para garantizar que la matrizaccounts
se haya actualizado con los cambios locales. Veamos cómoloadFromSmartStore()
realiza estas actualizaciones. - La función
loadFromSmartStore()
utiliza el publicador de SmartStore para generar una consulta Smart SQL y obtener la respuesta asíncrona. Si la respuesta indica que la operación se completó con éxito, la función publica el conjunto de datos resultantes para el emisor de la llamada. En este punto, el emisor de la llamada copia la respuesta analizada en la matrizaccounts
del objetoAccountsListModel
.import MobileSync
...
private func loadFromSmartStore() { storeTaskCancellable = self.store?.publisher(for: "select {Account:Name}, {Account:Industry}, {Account:Id} from {Account}") .receive(on: RunLoop.main) .tryMap { $0.map { (row) -> Account in let r = row as! [String?] return Account(id: r[2] ?? "", name: r[0] ?? "", industry: r[1] ?? "Unknown Industry" ) } } .catch { error -> Just<[Account]> in print(error) return Just([Account]()) } .assign(to: \AccountsListModel.accounts, on:self) }
Cuando se rellena la matriz de cuentas, la aplicación puede proceder con su lógica principal que, en este caso, consiste en realizar las siguientes acciones:
- Mostrar las cuentas consultadas y sus detalles
- Hacer una consulta y, luego, mostrar los contactos y sus detalles en cualquier cuenta que el cliente seleccione
Uso de Mobile Sync en aplicaciones Android nativas
Sincronización descendente
Para descargar sObjects desde el servidor en una sopa de Mobile Sync local, use uno de los siguientes métodos SyncManager
:
Puede crear una configuración de sincronización descendente sin ejecutarla:
public SyncState createSyncDown(SyncDownTarget target, SyncOptions options, String soupName, String syncName) throws JSONException;
O bien puede crear y ejecutar una operación de sincronización descendente sin nombre sin opciones, pero se advierte de que sobrescribe cualquier cambio local:
public SyncState syncDown(SyncDownTarget target, String soupName, SyncUpdateCallback callback) throws JSONException;
Para más control, puede crear y ejecutar una operación de sincronización descendente sin nombre que utiliza sus propias opciones de combinación.
public SyncState syncDown(SyncDownTarget target, SyncOptions options,
String soupName, SyncUpdateCallback callback)
throws JSONException;
O bien puede asignar un nombre a esa configuración de sincronización descendente cuando la cree y luego ejecutarla:
public SyncState syncDown(SyncDownTarget target, SyncOptions options, String soupName, SyncUpdateCallback callback) throws JSONException;
Sincronización ascendente
Para aplicar cambios locales en el servidor, use uno de los siguientes métodos SyncManager
.
- Puede crear una configuración de sincronización ascendente con nombre sin ejecutarla:
public SyncState createSyncUp(SyncUpTarget target, SyncOptions options, String soupName, String syncName) throws JSONException;
- Puede crear y ejecutar una configuración de sincronización sin nombre en una sola llamada:
public SyncState syncUp(SyncUpTarget target, SyncOptions options, String soupName, SyncUpdateCallback callback) throws JSONException;
- O bien puede crear y ejecutar una configuración de sincronización ascendente con nombre en una sola llamada:
public SyncState syncUp(SyncUpTarget target, SyncOptions options, String soupName, String syncName, SyncUpdateCallback callback) throws JSONException;
Los métodos syncUp
actualizan el servidor con datos desde la sopa de SmartStore proporcionada. Buscan registros creados, actualizados o eliminados en la sopa y replican estos cambios en el servidor. El destino
o el parámetro opciones
, o ambos, especifica una lista de campos para cargar. Un destino le permite diferenciar entre una createFieldlist
para la creación de registros y una updateFieldlist
para la actualización de registros existentes. Estos parámetros le permiten sincronizar nuevos registros a la vez que evita los intentos de actualizar campos de solo lectura en registros existentes. Si define listas de campo de destino y listas de campo de opciones, se ignora la configuración de opciones
.
Volver a sincronizar
Importante pero a veces se pasa por alto, el par de métodos de resincronización es versátil y fácil de codificar. Estos métodos ejecutan configuraciones de sincronización que definió previamente en otra ubicación. A pesar del nombre, también puede utilizar estos métodos para ejecutar una sincronización denominada por primera vez. En ejecuciones posteriores, los métodos de resincronización solo sincronizan registros que se crearon y se actualizaron desde la última sincronización. Si la sincronización nunca se ejecutó, la resincronización copia todos los registros nuevos o modificados. De lo contrario, realiza una sincronización incremental.
Para utilizar los métodos de resincronización, proporcione un Id. de sincronización desde una sincronización anterior o un nombre de sincronización predefinido. Para ejecutar una sincronización con nombre:
public SyncState reSync(String syncName, SyncUpdateCallback callback) throws JSONException;
Si incluyó el valor SFSyncState.syncId
devuelto de una operación de sincronización anterior en caché, puede volver a ejecutar esa sincronización utilizando reSync:updateBlock:
:
public SyncState reSync(long syncId, SyncUpdateCallback callback) throws JSONException;
Los métodos reSync
admiten tanto configuraciones de sincronización ascendente como descendente.
Ejemplo
Para Android, la aplicación nativa de ejemplo MobileSyncExplorer demuestra cómo usar sincronizaciones denominadas y archivos de configuración de sincronización con registros de contactos. Define una clase ContactObject
que representa un registro de contacto de Salesforce como un objeto en Java. Para sincronizar los datos de contacto de forma descendente en la sopa de SmartStore, el método syncDown()
vuelve a sincronizar una configuración de sincronización descendente denominada que define una consulta SOQL.
Esta aplicación almacena los archivos userstore.json
y usersyncs.json
en la carpeta de proyectos /res/raw
. A continuación, encontrará userstore.json
:
{ "soups": [ { "soupName": "contacts", "indexes": [ { "path": "Id", "type": "string"}, { "path": "FirstName", "type": "string"}, { "path": "LastName", "type": "string"}, { "path": "__local__", "type": "string"}, { "path": "__locally_created__", "type": "string"}, { "path": "__locally_updated__", "type": "string"}, { "path": "__locally_deleted__", "type": "string"}, { "path": "__sync_id__", "type": "integer"} ] } ] }
Y usersyncs.json
:
{ "syncs": [ { "syncName": "syncDownContacts", "syncType": "syncDown", "soupName": "contacts", "target": {"type":"soql", "query":"SELECT FirstName, LastName, Title, MobilePhone, Email, Department, HomePhone FROM Contact LIMIT 10000"}, "options": {"mergeMode":"OVERWRITE"} }, { "syncName": "syncUpContacts", "syncType": "syncUp", "soupName": "contacts", "target": {"createFieldlist":["FirstName", "LastName", "Title", "MobilePhone", "Email", "Department", "HomePhone"]}, "options": {"fieldlist":["Id", "FirstName", "LastName", "Title", "MobilePhone", "Email", "Department", "HomePhone"], "mergeMode":"LEAVE_IF_CHANGED"} } ] }
Esta aplicación de ejemplo carga estos archivos en la memoria en su constructor ContactListLoader
.
public ContactListLoader(Context context, UserAccount account) { super(context); MobileSyncSDKManager sdkManager = MobileSyncSDKManager.getInstance(); smartStore = sdkManager.getSmartStore(account); syncMgr = SyncManager.getInstance(account); // Setup schema if needed sdkManager.setupUserStoreFromDefaultConfig(); // Setup syncs if needed sdkManager.setupUserSyncsFromDefaultConfig(); }
En el siguiente método de la clase ContactListLoader
, el método local syncDown()
ejecuta reSync()
con la configuración syncDownContacts
:
public synchronized void syncDown() { try { syncMgr.reSync(SYNC_DOWN_NAME /* see usersyncs.json */, new SyncUpdateCallback() { @Override public void onUpdate(SyncState sync) { if (Status.DONE.equals(sync.getStatus())) { fireLoadCompleteIntent(); } } }); } catch (JSONException e) { Log.e(TAG, "JSONException occurred while parsing", e); } catch (MobileSyncException e) { Log.e(TAG, "MobileSyncException occurred while attempting to sync down", e); } }
Si la operación de sincronización descendente es correcta (es decir, si sync.getStatus()
equivale a Status.DONE
), los datos recibidos se incluyen en el grupo especificado. El método de devolución de llamada desencadena a continuación un intento que vuelve a cargar los datos en la lista de contactos.
Del mismo modo, el método local syncUp()
de ContactListLoader
ejecuta reSync()
con la configuración syncUpContacts
:
public synchronized void syncUp() {
try {
syncMgr.reSync(SYNC_UP_NAME /* see usersyncs.json */, new SyncUpdateCallback() {
new SyncUpdateCallback() {
@Override
public void onUpdate(SyncState sync) {
if (Status.DONE.equals(sync.getStatus())) {
syncDown();
}
}
});
} catch (JSONException e) {
Log.e(TAG, "JSONException occurred while parsing", e);
} catch (MobileSyncException e) {
Log.e(TAG, "MobileSyncException occurred while attempting to sync up", e);
}
}
Cuando la respuesta asíncrona muestra Status.DONE
, la implementación SyncUpdateCallback
aquí suma el paso de llamar a syncDown()
. Este paso recomendado garantiza que la sopa de SmartStore permanezca actualizada con los cambios recientes realizados en los contactos del servidor.
Uso de Mobile Sync en aplicaciones híbridas
Mobile Sync proporciona dos enfoques diferentes para aplicaciones híbridas.
com.salesforce.plugin.mobilesync
: Este complemento de Cordova proporciona acceso de JavaScript a las funciones nativas “sincronización descendente” y “sincronización ascendente” de Mobile Sync. Por lo tanto, las operaciones que requieren un alto nivel de desempeño (negociaciones en red, análisis, gestión de SmartStore) se ejecutan en subprocesos nativos que no afectan a las operaciones web. Use el complemento en escenarios más sencillos como, por ejemplo, para sincronizar numerosos registros rápidamente en cadenas nativas en lugar de en la vista web.mobilesync.js
: Esta biblioteca de JavaScript proporciona un marco de datos Force SObject para operaciones de sincronización más complejas. La biblioteca se basa en Backbone.js, un marco de JavaScript de código abierto que define un mecanismo de modelado de datos extensible. Si usamobilesync.js
, puede crear modelos de objetos de Salesforce y manipular los registros subyacentes con tan solo cambiar los datos de los modelos. Si realiza una consulta SOQL o SOSL, recibe los registros resultantes en una colección de modelos en lugar de como una cadena JSON.
Puede combinar estos enfoques en la misma aplicación para un buen resultado. Por ejemplo, el complemento expone dos métodos: syncDown()
y syncUp()
. Cuando utiliza estos métodos, las siguientes directrices pueden facilitarle las cosas.
- Para crear, actualizar o eliminar registros en sopas de SmartStore, utilice
Force.SObject
desdemobilesync.js
. La bibliotecamobilesync.js
crea automáticamente campos especiales en registros de sopa que el complemento espera. A continuación puede llamarsyncUp()
en el complemento para actualizar el servidor. - De forma similar, si desea crear la sopa para sus operaciones de sincronización, use
Force.StoreCache
desdemobilesync.js
. - Si ha cambiado los objetos de la sopa, llame siempre a
syncUp()
antes de llamar asyncDown()
.
Las aplicaciones híbridas creadas con forcehybrid incluyen automáticamente el complemento de Mobile Sync.
Sincronización descendente
A continuación, encontrará el método syncDown()
del complemento de Mobile Sync.
cordova.require("com.salesforce.plugin.mobilesync").syncDown ([storeConfig,] target, soupName, options, [syncName,] success, error);
Si definió el nombre de sincronización de esta configuración, puede proporcionarlo. Los nombres de sincronizaciones se definen en un archivo de configuración usersyncs.json
que debe incluir en el nivel superior de su aplicación web.
Para la opción del modo de combinación, las aplicaciones híbridas utilizan estos identificadores.
{mergeMode:Force.MERGE_MODE_DOWNLOAD.OVERWRITE}
(predeterminado){mergeMode:Force.MERGE_MODE_DOWNLOAD.LEAVE_IF_CHANGED}
El parámetro success
especifica una función de devolución de llamadas que se llama varias veces durante la operación de sincronización:
- Cuando la operación de sincronización se inicia.
- Cuando la solicitud REST interna se completa.
- Después de la descarga de cada página de resultados hasta la recepción de todos los resultados.
Mientras se ejecuta la operación de sincronización, las actualizaciones de estado llegan a través de eventos del navegador. Para escuchar estas actualizaciones, implemente el siguiente proceso de escucha de eventos:
document.addEventListener("sync", function(event) { // event.detail contains the status of the sync operation } );
El miembro event.detail le proporciona metadatos de sincronización y (lo más importante) información acerca del estado y el progreso actual de la operación:
syncId
: Id. de la operación de sincronización.type
: syncDown.target
: el destino que proporcionó.soupName
: el nombre de sopa que proporcionó.options
: matriz de opciones que especificóstatus
: el estado de sincronización, que puede ser uno de los que se describen a continuación.NEW
(Nuevo)RUNNING
(En ejecución)DONE
(Listo)FAILED
(Con error)
progress
: el porcentaje de registros totales procesados hasta el momento (entero entre 0 y 100).totalSize
: el número de registros procesados hasta el momento.
Es buena idea almacenar el Id. de sincronización. Puede utilizar este valor más adelante para volver a ejecutar la operación de sincronización.
Sincronización ascendente
El método syncUp()
del complemento de Mobile Sync copia registros creados, eliminados o actualizados desde una sopa de SmartStore al servidor de Salesforce.
cordova.require("com.salesforce.plugin.mobilesync").syncUp ([storeConfig,] [target,] soupName, options, [syncName,] successCb, errorCb);
Usted proporciona parámetros de configuración para la operación, incluyendo
target
: si definió un destino de sincronización nativo personalizado, use este parámetro para identificar su clase.syncName
: si definió el nombre de sincronización de esta configuración, puede proporcionarlo. Los nombres de sincronizaciones se definen en un archivo de configuraciónusersyncs.json
que debe incluir en el nivel superior de su aplicación web.options
: proporciona un mapa con la clave que se indica a continuación:fieldlist
: lista de campos enviados al servidor.
successCb
,errorCb
: funciones de devolución de llamada en caso de éxito o error.
Las actualizaciones de estado en la operación de sincronización llegan a través del mismo controlador de eventos que implementó para syncDown:
document.addEventListener("sync", function(event) { // event.detail contains the status of the sync operation } );
Como en operaciones de sincronización descendente, el miembro event.detail le proporciona metadatos de sincronización y crea reportes del estado y el progreso actual de la operación.
Volver a sincronizar
Como sucede en las aplicaciones nativas, el método reSync
ofrece una flexibilidad y un desempeño superiores, y promueve una codificación sencilla. Si el nombre de sincronización que proporciona no se sincronizó con anterioridad, reSync()
lleva a cabo una sincronización completa. De lo contrario, solo realiza sincronizaciones incrementales de registros nuevos, modificados o eliminados.
cordova.require("com.salesforce.plugin.mobilesync").reSync([storeConfig], syncIdOrName, successCB, errorCB)
Usted proporciona parámetros de configuración para la operación, incluyendo
syncIdOrName
: el Id. de esta operación de sincronización o un nombre de sincronización del archivousersyncs.json
.successCb
,errorCb
: funciones de devolución de llamada en caso de éxito o error.
Ejemplo
Este ejemplo utiliza las sincronizaciones con nombre definidas en siguiente archivo usersyncs.json
. Encontrará el código fuente completo en el repositorio de GitHub SalesforceMobileSDK-Shared.
{ "syncs": [ { "syncName": "syncDownContacts", "syncType": "syncDown", "soupName": "contacts", "target": {"type":"soql", "query":"SELECT FirstName, LastName, Title, MobilePhone, Email, Department, HomePhone FROM Contact LIMIT 10000"}, "options": {"mergeMode":"OVERWRITE"} }, { "syncName": "syncUpContacts", "syncType": "syncUp", "soupName": "contacts", "target": { "createFieldlist":["FirstName", "LastName", "Title", "MobilePhone", "Email", "Department", "HomePhone"]}, "options": { "fieldlist":["Id", "FirstName", "LastName", "Title", "MobilePhone", "Email", "Department", "HomePhone"], "mergeMode":"LEAVE_IF_CHANGED"} } ] }
En los siguientes ejemplos, ambas operaciones de sincronización ascendente y descendente llaman a reSync()
en el complemento Cordova de Mobile Sync y pasan un nombre de sincronización. Todas las operaciones de sincronización utilizan la función handleSyncUpdate()
para lograr devoluciones de llamadas correctas. Tenga en cuenta que esta función llama syncDown()
tras la finalización de una ejecución de syncUp
correcta. Siempre conviene llamar a syncDown()
después de syncUp()
para asegurarse de que sus sopas reflejen los cambios más recientes que se hicieron en el servidor.
En su forma actual, la devolución de llamada correcta para syncDown()
restablece la interfaz de usuario y su contenido.
handleSyncUpdate: function(sync) { // Called after sync operations succeed if (sync.type === "syncDown") { // Reset UI buttons, then search (fetch) from SmartStore this.syncInFlight = false; $(".sync").disabled = false; this.search(); } if (sync.type === "syncUp") { this.syncDown(); } } }, syncDown: function() { cordova.require("com.salesforce.plugin.mobilesync"). reSync("syncDownContacts" /* see usersyncs.json */, this.handleSyncUpdate.bind(this)); }, syncUp: function() { cordova.require("com.salesforce.plugin.mobilesync"). reSync("syncUpContacts" /* see usersyncs.json */, this.handleSyncUpdate.bind(this)); }
Uso de Mobile Sync en aplicaciones React nativas
En React Native, Mobile Sync proporciona su función a través de un módulo mobilesync
. En sus archivos JavaScript, puede importar este módulo y sus dependencias desde la biblioteca react-native-force
del siguiente modo:
import {oauth, net, smartstore, mobilesync} from 'react-native-force';
Las aplicaciones creadas con forcereact incluyen una declaración de import
similar, pero sin smartstore
ni mobilesync
. Asegúrese de agregar estos módulos si está cubriendo funciones de Mobile SDK sin conexión.
Configuración de sincronización
Como probablemente esperaba, usted proporciona los mismos metadatos de configuración para aplicaciones React Native que para aplicaciones híbridas. A continuación encontrará un ejemplo de una declaración de destino.
const fieldlist = ["Id", "FirstName", "LastName", "Title", "Email", "MobilePhone","Department", "HomePhone", "LastModifiedDate"]; const target = {type:"soql", query: `SELECT ${fieldlist.join(",")} FROM Contact LIMIT 10000`};
Para el modo de combinación en opciones, utiliza uno de los siguientes valores.
- Para sobrescribir registros que se hayan modificado:
Si no define la clave{mergeMode:mobilesync.MERGE_MODE.OVERWRITE}
mergeMode
, Mobile Sync utiliza este modo como el predeterminado. - Para conservar, en vez de sobrescribir, registros que se hayan modificado:
{mergeMode:mobilesync.MERGE_MODE.LEAVE_IF_CHANGED}
Sincronización descendente
La función syncDown()
para React Native es idéntica a la función híbrida, excepto que se llama en el módulo mobilesync
. Descarga registros específicos de Salesforce en una sopa de SmartStore.
mobilesync.syncDown ([storeConfig,] target, soupName, options, [syncName,] success, error);
Si los registros existentes en la sopa tienen el mismo Id. que los registros devueltos por la consulta, Mobile Sync sobrescribe de forma predeterminada los registros de sopa duplicados. Para controlar cómo se combinan los datos descargados con registros modificados en la sopa, especifique un modo de combinación en el parámetro opciones.
El parámetro success
especifica una función de devolución de llamada que el gestor de sincronización interna llama cuando la operación de sincronización finaliza con éxito. A diferencia de la implementación híbrida, la biblioteca de React Native llama esta función solo una vez, cuando haya finalizado la operación.
Mobile SDK pasa un argumento único a la devolución de llamadas de éxito. Este argumento devuelve los siguientes metadatos de sincronización que incluyen el Id. de sincronización:
syncId
: Id. de la operación de sincronización.type
: syncDown.target
: el destino que proporcionó.options
: (Opcional) Una matriz especificando uno o ambos de los siguientes: modo de combinación, lista de campossoupName
: el nombre de sopa que proporcionó.syncName
: El nombre de sincronización que proporcionó, si existe alguno
Aunque no realice ninguna otra acción para lograr una devolución de llamada correcta, es aconsejable implementarla con el fin de almacenar el Id. de sincronización. Puede utilizar este valor más adelante, si es necesario, en una operación de resincronización. A continuación, encontrará un ejemplo de sincronización descendente.
const syncDown = forceUtil.promiserNoRejection(mobilesync.syncDown); ... const fieldlist = ["Id", "FirstName", "LastName", "Title", "Email", "MobilePhone","Department", "HomePhone", "LastModifiedDate"]; const target = {type:"soql", query:`SELECT ${fieldlist.join(",")} FROM Contact LIMIT 10000`}; syncDown(false, target, "contacts", {mergeMode:mobilesync.MERGE_MODE.OVERWRITE}, syncName, (sync) => {/* Do something meaningful or omit this member */}, (error) => {/* Do something meaningful or omit this member */} );
Sincronización ascendente
La función syncUp()
del complemento de Mobile Sync copia los registros creados, eliminados o actualizados desde una sopa de SmartStore al servidor de Salesforce.
mobilesync.syncUp ([storeConfig,] target, soupName, options, [syncName,] successCb, errorCb);
Como en operaciones de sincronización descendente, el argumento de entrada de la función de devolución de llamada de éxito le proporciona metadatos de sincronización incluyendo el Id. de sincronización.
Éste es un ejemplo de sincronización ascendente.
const syncUp = forceUtil.promiserNoRejection(mobilesync.syncUp); ... const fieldlist = ["FirstName", "LastName", "Title", "Email", "MobilePhone","Department"]; syncUp(false, {}, "contacts", {mergeMode:mobilesync.MERGE_MODE.OVERWRITE, fieldlist}, (sync) => {/* Do something meaningful or omit this callback */}, (error) => {/* Do something meaningful or omit this callback */} );
Volver a sincronizar
Como sucede en las aplicaciones nativas, el método reSync()
ofrece una flexibilidad y un desempeño superiores, y promueve una codificación sencilla. Si el nombre de sincronización que proporciona no se sincronizó con anterioridad, reSync()
lleva a cabo una sincronización completa. De lo contrario, solo realiza sincronizaciones incrementales de registros creados, actualizados o eliminados.
mobilesync.reSync ([storeConfig,] syncIdOrName, successCB, errorCB);
Usted proporciona parámetros de configuración para la operación, incluyendo
syncIdOrName
: el Id. de esta operación de sincronización o un nombre de sincronización del archivousersyncs.json
.successCb
,errorCb
: funciones de devolución de llamada en caso de éxito o error.
Recursos
- Uso de Mobile Sync en aplicaciones React Native e híbridas
- Uso de Mobile Sync en aplicaciones nativas
- El ejemplo MobileSyncExplorer está disponible de las siguientes formas. Para obtener instrucciones sobre el uso, consulte la sección sobre la instalación de aplicaciones de ejemplo.
- Aplicación de ejemplo híbrida de NoteSync
- Sitio web de React Native
- Usar el destino de sincronización descendente de maletines