Este post explica cómo empezar con la replicación/sincronización de datos a través de dispositivos iOS usando Couchbase Mobile. Couchbase Mobile Stack se compone de Couchbase Server, Sync Gateway y Couchbase Lite embedded NoSQL Database. En un Correo electrónico:En el artículo anterior, discutimos cómo Couchbase Lite puede ser utilizado como una base de datos NoSQL independiente incrustada en aplicaciones iOS. Este post te guiará a través de un ejemplo de aplicación iOS en conjunto con un Sync Gateway que demostrará los conceptos básicos de Push & Pull Replication, Authentication & Access Control, Channels y Sync Functions.
Aunque vamos a ver la sincronización de datos en el contexto de una App iOS en Swift, todo lo que se discuta aquí es igualmente aplicable a apps móviles desarrolladas en cualquier otra plataforma (Android, iOS (ObjC), Xamarin). Las desviaciones se especificarán como tales.
NOTA: Estaremos discutiendo Couchbase Mobile v1.4 que es la versión de producción actual. Existe una versión Vista previa para desarrolladores versión 2.0 de Couchbase Mobile que tiene un montón de nuevas y emocionantes características.
Couchbase Móvil
Couchbase Mobile Stack está compuesto por Couchbase Server, Sync Gateway y Couchbase Lite embedded NoSQL Database. Este post tratará los conceptos básicos de NoSQL replicación y sincronización de datos usando Couchbase Mobile. Asumiré que estás familiarizado con el desarrollo de aplicaciones iOS, conceptos básicos de Swift, algunos conceptos básicos de NoSQL y que tienes algún conocimiento de Couchbase. Si quieres leer más sobre Couchbase Mobile, puedes encontrar un montón de recursos al final de este post.
Pasarela de sincronización Couchbase
Couchbase Sync Gateway es un mecanismo de sincronización orientado a Internet que sincroniza datos de forma segura entre dispositivos, así como entre dispositivos y la nube.
Expone una interfaz web que proporciona
- Sincronización de datos entre dispositivos y la nube
- Control de acceso
- Validación de datos
Puedes utilizar cualquier cliente HTTP para explorar más a fondo la interfaz. Eche un vistazo a Correo electrónico: sobre el uso de Postman para consultar la interfaz.
Hay tres conceptos principales relacionados con la replicación o sincronización de datos mediante Sync Gateway -
Canal
Un canal puede verse como una combinación de etiqueta y cola de mensajes. Cada documento puede asignarse a uno o varios canales. Los documentos se asignan a canales que especifican quién puede acceder a los documentos. Los usuarios tienen acceso a uno o varios canales y sólo pueden leer los documentos asignados a esos canales. Para más información, consulte la página documentación sobre Canales.
Función de sincronización
La función de sincronización es una función JavaScript que se ejecuta en Sync Gateway. Cada vez que se añade un nuevo documento, revisión o borrado a una base de datos, se llama a la función de sincronización. La función de sincronización es responsable de
- Validación del documento,
- Autorizar el cambio
- Asignación de documentos a canales y
- Conceder a los usuarios acceso a los canales.
Para más información, consulte documentación sobre la función de sincronización .
Replicación
La replicación, también conocida como sincronización, es el proceso de sincronizar los cambios entre la base de datos local y el Sync Gateway remoto. Existen dos tipos
- La replicación push se utiliza para transferir los cambios de la base de datos local a la remota.
- La replicación pull se utiliza para extraer cambios de la base de datos remota a la local.
Para más información, consulte documentación sobre réplicas.
Instalación de Couchbase Sync Gateway
Siga las guía de instalación para instalar el Sync Gateway.
Inicie su Sync Gateway con el siguiente archivo de configuración. La ubicación exacta del archivo de configuración dependerá de la plataforma. Consulte la guía de instalación.
Archivo de configuración de la pasarela de sincronización
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
{ "log": ["*"], "CORS": { "Origen":["*"] }, "bases de datos": { "demo": { "servidor": "morsa:", "cubo": "por defecto", "usuarios": { "INVITADO": { "desactivado": verdadero, "admin_canales": ["*"] } , "joe": {"contraseña":"contraseña" ,"desactivado": falso, "admin_canales":["_público","_joe"]} , "jane":{"contraseña":"contraseña" ,"desactivado": falso, "admin_canales":["_público","_jane"]} }, "sin soporte": { "vistas_usuario": { "activado":verdadero } }, "sync": ` function (doc, oldDoc){ // Comprobar si el documento está siendo borrado if (doc._deleted == undefined) { // Validar que la versión actual tiene las claves relevantes validarDocumento(doc); } si no { // Validar documento antiguo tiene claves relevantes validarDocumento(documentoantiguo); } var docOwner = (doc._deleted == undefined) ? doc.owner : oldDoc.owner; var publicChannel = "_public"; var privateChannel = "_"+docOwner; // Conceder al usuario acceso de lectura a los canales públicos y al canal del propio usuario access(docPropietario,[canalpúblico,canalprivado]); // Comprobar si se trata de una actualización de documento (en lugar de una creación o eliminación de documento) if (doc._deleted == undefined && oldDoc != null && oldDoc._deleted == undefined) { if (doc.tag != oldDoc.tag) { throw({prohibido: "No se puede cambiar la etiqueta del documento"}); } } // Comprobar si el documento nuevo/actualizado está etiquetado como "público" var docTag = (doc._deleted == undefined) ? doc.tag : oldDoc.tag; if (doc._deleted == undefined) { if (docTag == "public") { // Todos los documentos etiquetados como públicos van al canal "público" que se abre a todos canal(publicCanal); } si no { // Asegurarse de que el propietario del documento es el usuario que realiza la solicitud requireUser(docPropietario); // Todos los documentos etiquetados no públicos van a un canal específico del usuario canal(canalprivado); } } si no { channel(doc.channels); } function validateDocument (doc) { // Validación básica del documento if (!doc.tag ) { // Cada documento debe incluir una etiqueta throw({forbidden: "Tipo de documento no válido: Etiqueta no proporcionada" + doc.tag}); } if (!doc.owner) { // Cada documento debe incluir un propietario throw({forbidden: "Tipo de documento no válido: Propietario no proporcionado" + doc.owner}); } } } ` } } } |
Estos son algunos puntos clave que hay que tener en cuenta en el archivo de configuración:-
- Línea 8: El valor "walrus:" para "server" indica que el Sync Gateway debe persistir los datos en memoria y no está respaldado por un servidor Couchbase.
- Línea 11: El acceso de usuarios invitados está desactivado
- Líneas 12-13: Hay dos usuarios, "Jane" y "Joe" configurados en el sistema. Ambos usuarios tienen acceso a un canal "_público" y cada uno tiene acceso a su propio canal privado.
- Línea 22-100: Una simple función de sincronización que hace lo siguiente
- Líneas 29-36 : Validación del documento para garantizar que contiene las propiedades "tag" y "owner" definidas por el usuario.
- La propiedad "tag" se utiliza para especificar si el documento está disponible públicamente para cualquier usuario o si es privado para un usuario
- La propiedad "owner" se utiliza para especificar si el documento está disponible públicamente para cualquier usuario o si es privado para un usuario
- Línea 46: Dar acceso al usuario al canal "_public" y a un canal privado (identificado mediante el propietario del documento).
- Líneas 51-56 : Si se trata de una actualización del documento, compruebe que la propiedad "tag" no se modifica en las distintas revisiones.
- Línea 66: Asignar todos los documentos con etiqueta "public" al canal "_public".
- Línea 72: Asignar todos los documentos con una etiqueta distinta de "público" al canal privado.
- Línea 75: En el caso de los documentos de canal privado, compruebe en primer lugar que el titular del documento es quien realiza la solicitud
- Líneas 29-36 : Validación del documento para garantizar que contiene las propiedades "tag" y "owner" definidas por el usuario.
Couchbase Lite
Couchbase Lite es una base de datos NoSQL integrada que se ejecuta en dispositivos. Couchbase Lite se puede utilizar en varios modos de despliegue. Introducción a Couchbase Lite Correo electrónico: habla del modo de despliegue autónomo. Couchbase Lite puede ser usado en conjunto con un Sync Gateway remoto que le permitiría sincronizar datos a través de dispositivos. Este post trata sobre el modo de despliegue usando un Sync Gateway.
Hay muchas opciones para integrar el framework Couchbase Lite en tu aplicación iOS. Echa un vistazo a nuestro Couchbase Mobile Guía de iniciación para las distintas opciones de integración.
API nativa
Couchbase Lite expone una API nativa para iOS, Android y Windows que permite a las aplicaciones interactuar fácilmente con la plataforma Couchbase. Como desarrollador de aplicaciones, no tienes que preocuparte por el funcionamiento interno de la base de datos integrada de Couchbase Lite, sino que puedes centrarte en crear tu aplicación. La API nativa te permite interactuar con el framework de Couchbase Lite como lo harías con otros frameworks/subsistemas de la plataforma. De nuevo, hablaremos de Couchbase Mobile v1.4 en esta entrada del blog. Puedes obtener una lista completa de las APIs en nuestro Couchbase Desarrollador sitio.
Demo iOS App
Descargue el proyecto de demostración de Xcode desde Repo de Github y cambiar a la rama "soporte de sincronización". Usaremos esta app como ejemplo en el resto del blog. Esta aplicación utiliza Cocoapods para integrar el framework Couchbase Lite.
1 2 |
git clonar git@github.com:couchbaselabs/couchbase-lite-ios-independiente-sampleapp.git git checkout syncsupport |

Sincronización de documentos entre usuarios
- Cree y ejecute la aplicación. Debería aparecer una alerta de inicio de sesión
- Introduzca el usuario "jane" y la contraseña de "password" . Este usuario se configuró en el archivo de configuración de Sync Gateway
- Añada el primer documento pulsando el botón "+" en la esquina superior derecha.
- Dé un nombre al documento y una descripción de una línea.
- Utiliza la etiqueta "privado".
- Entre bastidores, el replicador push envía el documento a la pasarela de sincronización y es procesado por la función de sincronización. Basándose en la etiqueta, la función de sincronización asigna el documento al canal privado del usuario.
- Añada un segundo documento pulsando el botón "+" en la esquina superior derecha.
- Dar un nombre al documento y una descripción de una línea
- Utiliza la etiqueta "public".
- Entre bastidores, el replicador push envía el documento a la pasarela de sincronización y es procesado por la función de sincronización. Basándose en la etiqueta pública, la función Sync asigna el documento al canal público
- Ahora "cierra sesión" Jane . Aparecerá de nuevo la alerta de inicio de sesión
- Introduzca el usuario "joe" y la contraseña "password". Este usuario también se configuró en el archivo de configuración de Sync Gateway
- Aparecerá el documento público creado por Jane.
- Entre bastidores, el Pull Replicator extrae todos los documentos del canal privado de Joe y del canal público. Se extrae el documento público creado por Jane. Sin embargo, como Joe no tenía acceso al canal privado de Jane, el documento privado creado por Jane no se extrae.
Para verificar el estado de las cosas en Sync Gateway, puede utilizar la interfaz REST de administración mediante Postman o cualquier cliente HTTP.
Esta es la petición CURL a la pasarela de sincronización
1 2 3 4 5 |
rizo -X GET \ http://localhost:4985/demo/_all_docs?access=false&channels=false&include_docs=true \ -H 'accept: application/json' \ -H 'cache-control: no-cache' \ -H content-type: application/json' |
La respuesta de la pasarela de sincronización muestra los dos documentos asignados al canal público y privado de Jane, respectivamente
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
{ "filas": [ { "llave": "-6gCouN6jj0ScYgpMD7Qj1a", "id": "-6gCouN6jj0ScYgpMD7Qj1a", "valor": { "rev": "1-dfa6d453a1515ee3dd64012ccaf53046", "canales": [ "_jane" ] }, "doc": { "_id": "-6gCouN6jj0ScYgpMD7Qj1a", "_rev": "1-dfa6d453a1515ee3dd64012ccaf53046", "nombre": "doc101", "resumen": "Este es un documento privado de Jane", "propietario": "jane", "tag": "privado" } }, { "llave": "-A2wR44pAFCdu1Yufx14_1S", "id": "-A2wR44pAFCdu1Yufx14_1S", "valor": { "rev": "1-1a8cd0ea3b7574cf6f7ba4a10152a466", "canales": [ "_público" ] }, "doc": { "_id": "-A2wR44pAFCdu1Yufx14_1S", "_rev": "1-1a8cd0ea3b7574cf6f7ba4a10152a466", "nombre": "doc102", "resumen": "Este es un documento público compartido por Jane", "propietario": "jane", "tag": "público" } } ], "total_rows": 2, "actualizar_seq": 5 } |
Explorar el código
Ahora, vamos a examinar fragmentos de código relevantes de la Demo App iOS -
Abrir/crear una base de datos por usuario
Abrir DocListTableViewController.swift y localice openDatabaseForUser función.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
do { // 1: Configurar las opciones de la base de datos deje opciones = CBLDatabaseOptions() opciones.storageType = kCBLSQLiteStorage opciones.crear = verdadero // 2: Crear una DB para el usuario logueado si no existe o devolver el handle de una existente auto.db = pruebe cbManager.openDatabaseNamed(usuario.en minúsculas(), con: opciones) auto.showAlertWithTitle(NSLocalizedString("¡Éxito!", comentario: ""), mensaje: NSLocalizedString("Base de datos \(usuario) se abrió con éxito en path \(CBLManager.defaultDirectory())", comentario: "")) // 3. Iniciar la replicación con el Sync Gateway remoto startDatabaseReplicationForUser(usuario, contraseña: contraseña) devolver verdadero } captura { // gestionar error } |
- Especifica las opciones a asociar con la base de datos. Explore las demás opciones de la clase CBLDatabaseOptions.
- Crea una base de datos con el nombre del usuario actual. De esta forma, cada usuario de la aplicación tendrá su propia copia local de la base de datos. Si existe una base de datos con el nombre, se devolverá un "handle" a la base de datos existente, de lo contrario se creará una nueva. Los nombres de las bases de datos deben estar en minúsculas. Si tiene éxito, se creará una nueva base de datos local si no existe. Por defecto, la base de datos se creará en la ruta por defecto (/Library/Application Support). Puede especificar un directorio diferente al instanciar la aplicación CBLManager clase.
- Inicia el Proceso de Replicación de la Base de Datos para las credenciales de usuario dadas. Discutiremos el código de Replicación en detalle en las siguientes secciones.
Búsqueda de documentos
Abra el DocListTableViewController.swift y localice getAllDocumentForUserDatabase función.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// 1. Crear una consulta para obtener todos los documentos. Puede establecer una serie de propiedades en el objeto de consulta liveQuery = auto.db?.createAllDocumentsQuery().asLive() guardia deje liveQuery = liveQuery si no { devolver } // 2: Puede establecer opcionalmente una serie de propiedades en el objeto de consulta. // Explorar otras propiedades del objeto de consulta liveQuery.límite = UInt(UINT32_MAX) // Todos los documentos // query.postFilter = //3. Empezar a observar los cambios en la base de datos auto.addLiveQueryObserverAndStartObserving() // 4: Ejecutar la consulta para obtener documentos de forma asíncrona liveQuery.runAsync({ (enumerador, error) en interruptor error { caso nil: // 5: El "enumerador" es de tipo CBLQueryEnumerator y es un enumerador para los resultados auto.docsEnumerator = enumerador por defecto: auto.showAlertWithTitle(NSLocalizedString("¡Error en la obtención de datos!", comentario: ""), mensaje: error.localizedDescription) } }) } captura { // gestionar error } |
- Obtener el acceso a la base de datos con el nombre especificado
- Crear un objeto de consulta. Esta consulta se utiliza para obtener todos los documentos. La función de sincronización de la puerta de enlace de sincronización garantizará que los documentos se extraigan únicamente de los canales accesibles para el usuario. Puede crear un objeto de consulta normal o un objeto de consulta "en vivo". El objeto de consulta "en vivo" es de tipo CBLLiveQuery que se actualiza automáticamente cada vez que se producen cambios en la base de datos que afectan a los resultados de la consulta. La consulta tiene una serie de propiedades que se pueden modificar para personalizar los resultados. Pruebe a modificar las propiedades y vea el efecto en los resultados
- Tendrá que añadir explícitamente un observador al objeto Live Query para ser notificado de los cambios en la base de datos. Discutiremos esto más a fondo en la sección "Observación de cambios sincronizados locales y remotos en los documentos". No olvide eliminar el observador y dejar de observar los cambios cuando ya no lo necesite.
- Ejecute la consulta de forma asíncrona. También puede hacerlo de forma sincrónica si lo prefiere, pero probablemente sea recomendable hacerlo de forma asincrónica si los conjuntos de datos son grandes.
Una vez que la consulta se ejecuta correctamente, se obtiene un objeto CBLQueryEnumerator. El enumerador de consultas permite enumerar los resultados. Se presta muy bien como fuente de datos para la vista de tabla que muestra los resultados
Observación de cambios sincronizados locales y remotos en los documentos
Abra el DocListTableViewController.swift y localice la función addLiveQueryObserverAndStartObserving.
Los cambios en la base de datos pueden ser el resultado de las acciones del usuario en el dispositivo local o pueden ser el resultado de cambios sincronizados desde otros dispositivos.
1 2 3 4 5 |
// 1. Específico para iOS. Añadir observador al objeto Query en vivo. liveQuery.addObserver(auto, forKeyPath: "filas", opciones: NSKeyValueObservingOptions.nuevo, contexto: nil) // 2. Empezar a observar los cambios liveQuery.iniciar() |
- Para recibir notificaciones de los cambios en la base de datos que afectan a los resultados de la consulta, añada un observador al objeto Live Query. En su lugar, aprovecharemos el patrón Key-Value-Observer de iOS para ser notificados de los cambios. Añadir un observador KVO al objeto Live Query para empezar a observar los cambios en la propiedad "rows" del objeto Live Query Esto se gestiona a través de las APIs de Event Handler apropiadas en otras plataformas, como la plataforma addChangeListener en Android/Java.
- Empieza a observar los cambios .
Siempre que se produzca un cambio en la base de datos que afecte a la propiedad "rows" del objeto LiveQuery, tu aplicación recibirá una notificación de cambios. Cuando recibas la notificación de cambio, puedes actualizar tu UI, que en este caso sería recargar la tableview.
1 2 3 4 |
si keyPath == "filas" { auto.docsEnumerator = auto.liveQuery?.filas tableView.recargarDatos() } |
Autenticación de las solicitudes de réplica
Abrir Archivo DocListTableViewController.swift y localizar startDatabaseReplicationForUser función.
Todas las solicitudes de replicación deben estar autenticadas. En esta aplicación, utilizamos la autenticación básica HTTP.
1 |
deje auth = CBLAuthenticator.basicAuthenticator(withName: usuario, contraseña: contraseña) |
Existen varios tipos de autenticador: Basic, Facebook, OAuth1, Persona, SSL/TLS Cert.
Replicación Pull
Abrir Archivo DocListTableViewController.swift y localizar startPullReplicationWithAuthenticator función.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 1: Crear una replicación Pull para empezar a extraer de la fuente remota deje pullRepl = db?.createPullReplication(URL(cadena: kDbName, relativeTo: URL.init(cadena: kRemoteSyncUrl))!) // 2. Configurar Authenticator para la replicación pull pullRepl?.autentificador = auth // Buscar continuamente cambios pullRepl?.continuo = verdadero // Opcionalmente, establezca los canales de los que tirar // pullRepl?.channels = [...] // 4. Poner en marcha el replicador pull pullRepl?.iniciar() |
- Cree un replicador de extracción para extraer los cambios de la puerta de enlace de sincronización remota. La dirección kRemoteSyncUrl es la URL del punto final de la base de datos remota en Sync Gateway.
- Asociar Autenticador con la Replicación Pull. Opcionalmente se pueden establecer los canales de los que se extraerán los documentos
- Configurar la replicación como "continua" permitirá que las actualizaciones de cambios se extraigan indefinidamente a menos que se detenga explícitamente o se cierre la base de datos.
- Iniciar la replicación Pull
Replicación Push
Abrir Archivo DocListTableViewController.swift y localizar startPushReplicationWithAuthenticator función.
1 2 3 4 5 6 7 8 9 10 11 12 |
// 1: Crear una replicación push para empezar a enviar a la fuente remota deje pushRepl = db?.createPushReplication(URL(cadena: kDbName, relativeTo: URL.init(cadena:kRemoteSyncUrl))!) // 2. Configurar Authenticator para la replicación push pushRepl?.autentificador = auth // Introducir cambios continuamente pushRepl?.continuo = verdadero // 3. Poner en marcha el replicador push pushRepl?.iniciar() |
- Cree un replicador push para enviar los cambios a la puerta de enlace de sincronización remota. La dirección kRemoteSyncUrl es la URL del punto final de la base de datos remota en Sync Gateway.
- Asociar autenticador con la replicación push.
- Configurar la replicación como "continua" permitirá que las actualizaciones de cambios se envíen indefinidamente a menos que se detenga explícitamente o se cierre la base de datos.
- Iniciar la replicación push
Supervisión del estado de la replicación
Abra el DBListTableViewController.swift y localice la función addRemoteDatabaseChangesObserverAndStartObserving.
1 2 3 4 5 6 7 |
// 1. Específico para iOS. Añadir observador al Centro de Notificación para observar los cambios del replicador. Centro de notificaciones.por defecto.addObserver(forName: NSNotificación.Nombre.cblReplicationChange, objeto: db, cola: nil) { [sin dueño auto] (notificación) en // Manejar los cambios en el estado del replicador - Como mostrar el progreso // indicador cuando el estado es .running } |
Puede supervisar el estado de la replicación añadiendo un observador al Centro de notificaciones de iOS para recibir notificaciones de cblReplicationChange notificaciones . Usted podría utilizar el controlador de notificación, por ejemplo, para mostrar indicadores de progreso apropiados para el usuario. Esto se maneja a través de las APIs de manejadores de eventos apropiados en otras plataformas como el addChangeListener en Android/Java.
¿Y ahora qué?
Nos encantaría conocer su opinión. Así que si tienes preguntas o comentarios, no dudes en ponerte en contacto conmigo en Twitter @rajagp o envíeme un correo electrónico priya.rajagopal@couchbase.com. Si desea mejorar la aplicación de demostración, envíe una solicitud de extracción a la base de datos Repo de Github.
En Foros de desarrollo de Couchbase Mobile es otro gran lugar para obtener respuestas a sus preguntas relacionadas con los móviles. Consulte el portal de desarrollo para obtener más información sobre el Pasarela de sincronización y Couchbase Lite . Todo lo que se discutió aquí está en el contexto de Couchbase Mobile 1.4. Hay un montón de cambios nuevos y emocionantes que vienen en Couchbase Mobile 2.0. Asegúrate de revisar el Vista previa para desarrolladores versión 2.0 de Couchbase Mobile.
¡¡¡Hola Priya ..!!!
Eso fue un muy buen post para la sincronización de datos en Swift.If se puede proporcionar en C objetivo también, sería apreciada.
Gracias.
Hola Priya,
He descargado e instalado la aplicación UserProfileDemo para Xamarin y he intentado probarla ejecutándola en dos simuladores simultáneamente. Los datos no se sincronizan cuando se inicia sesión con las mismas credenciales en el otro simulador. se obtiene obtener los datos de la base de datos local cada vez, pero no funciona la sincronización global.
Tu comentario no parece estar relacionado con esta entrada del blog y el tutorial (que es, de hecho, para iOS nativo en Couchbase Mobile 1.4). Has seguido las instrucciones de este tutorial de Xamarin? https://docs.couchbase.com/userprofile-couchbase-mobile/sync/userprofile/xamarin/userprofile_sync.html. Si tiene problemas con este tutorial, publíquelo en nuestros foros de desarrollo (forums.couchbase.com) con los registros pertinentes.