Esta postagem mostra como você pode começar a replicar/sincronizar dados em dispositivos iOS usando o Couchbase Mobile. O Couchbase Mobile Stack é composto pelo Couchbase Server, pelo Sync Gateway e pelo banco de dados NoSQL incorporado Couchbase Lite. Em um artigo anterior postagemNa postagem anterior, discutimos como o Couchbase Lite pode ser usado como um banco de dados NoSQL autônomo incorporado em aplicativos iOS. Esta postagem o guiará por um aplicativo iOS de amostra em conjunto com um Sync Gateway que demonstrará os principais conceitos de replicação push e pull, autenticação e controle de acesso, canais e funções de sincronização.
Embora estejamos analisando a sincronização de dados no contexto de um aplicativo iOS em Swift, tudo o que for discutido aqui se aplica igualmente a aplicativos móveis desenvolvidos em qualquer outra plataforma (Android, iOS (ObjC), Xamarin). Os desvios serão especificados como tal.
OBSERVAÇÃO: discutiremos o Couchbase Mobile v1.4, que é a versão de produção atual. Há uma versão mais recente Visualização do desenvolvedor versão 2.0 do Couchbase Mobile, que tem muitos recursos novos e interessantes.
Couchbase Mobile
O Couchbase Mobile Stack inclui o Couchbase Server, o Sync Gateway e o banco de dados NoSQL incorporado Couchbase Lite. Esta postagem abordará os conceitos básicos do NoSQL replicação e sincronização de dados usando o Couchbase Mobile. Presumo que você esteja familiarizado com o desenvolvimento de aplicativos iOS, noções básicas de Swift, algumas noções básicas de NoSQL e tenha algum conhecimento do Couchbase. Se você quiser ler mais sobre o Couchbase Mobile, poderá encontrar muitos recursos no final deste post.
Gateway de sincronização do Couchbase
O Couchbase Sync Gateway é um mecanismo de sincronização voltado para a Internet que sincroniza com segurança os dados entre dispositivos, bem como entre dispositivos e a nuvem.
Ele expõe uma interface da Web que fornece
- Sincronização de dados entre dispositivos e na nuvem
- Controle de acesso
- Validação de dados
Você pode usar qualquer cliente HTTP para explorar melhor a interface. Dê uma olhada neste postagem sobre o uso do Postman para consultar a interface.
Há três conceitos principais relacionados à replicação ou sincronização de dados usando o Sync Gateway
Canal
Um canal pode ser visto como uma combinação de uma tag e uma fila de mensagens. Cada documento pode ser atribuído a um ou mais canais. Os documentos são atribuídos a canais que especificam quem pode acessar os documentos. Os usuários recebem acesso a um ou mais canais e só podem ler os documentos atribuídos a esses canais. Para obter detalhes, consulte a seção documentação sobre canais.
Função de sincronização
A função de sincronização é uma função JavaScript que é executada no Sync Gateway. Toda vez que um novo documento, revisão ou exclusão é adicionado a um banco de dados, a função de sincronização é chamada. A função de sincronização é responsável por
- Validação do documento,
- Autorização da mudança
- Atribuição de documentos a canais e
- Concessão de acesso dos usuários aos canais.
Para obter detalhes, consulte Documentação sobre a função Sync .
Replicação
A replicação, também conhecida como sincronização, é o processo de sincronização de alterações entre o banco de dados local e o Sync Gateway remoto. Há dois tipos: a replicação e a sincronização.
- A replicação push é usada para enviar alterações do banco de dados local para o remoto
- A replicação pull é usada para extrair alterações do banco de dados remoto para o local
Para obter detalhes, consulte documentação sobre réplicas.
Instalação do Couchbase Sync Gateway
Siga a Guia de instalação para instalar o Sync Gateway.
Inicie o Sync Gateway com o seguinte arquivo de configuração. O local exato do arquivo de configuração dependerá da plataforma. Consulte o guia de instalação para obter mais informações.
Arquivo de configuração do gateway de sincronização
|
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": { "Origin":["*"] }, "databases": { "demo": { "server": "walrus:", "bucket": "default", "users": { "GUEST": { "disabled": true, "admin_channels": ["*"] } , "joe": {"password":"password" ,"disabled": false, "admin_channels":["_public","_joe"]} , "jane":{"password":"password" ,"disabled": false, "admin_channels":["_public","_jane"]} }, "unsupported": { "user_views": { "enabled":true } }, "sync": ` function (doc, oldDoc){ // Check if doc is being deleted if (doc._deleted == undefined) { // Validate current version has relevant keys validateDocument(doc); } else { // Validate old document has relevant keys validateDocument(oldDoc); } var docOwner = (doc._deleted == undefined) ? doc.owner : oldDoc.owner; var publicChannel = "_public"; var privateChannel = "_"+docOwner; // Grant user read access to public channels and user's own channel access(docOwner,[publicChannel,privateChannel]); // Check if this was a doc update (as opposed to a doc create or delete) if (doc._deleted == undefined && oldDoc != null && oldDoc._deleted == undefined) { if (doc.tag != oldDoc.tag) { throw({forbidden: "Cannot change tag of document"}); } } // Check if new/updated document is tagged as "public" var docTag = (doc._deleted == undefined) ? doc.tag : oldDoc.tag; if (doc._deleted == undefined) { if (docTag == "public") { // All documents tagged public go into "public" channel which to open to all channel(publicChannel); } else { // Ensure that the owner of document is the user making the request requireUser(docOwner); // All non-public tagged docs go into a user user specific channel channel(privateChannel); } } else { channel(doc.channels); } function validateDocument (doc) { // Basic validation of document if (!doc.tag ) { // Every doc must include a tag throw({forbidden: "Invalid document type: Tag not provided" + doc.tag}); } if (!doc.owner) { // Every doc must include a owner throw({forbidden: "Invalid document type: Owner not provided" + doc.owner}); } } } ` } } } |
Aqui estão alguns pontos importantes a serem observados no arquivo de configuração
- Linha 8: O valor "walrus:" para "server" indica que o Sync Gateway deve manter os dados na memória e não tem o suporte de um servidor Couchbase.
- Linha 11: O acesso do usuário convidado está desativado
- Linha 12-13: Há dois usuários, "Jane" e "Joe", configurados no sistema. Ambos os usuários têm acesso a um canal "_public" e cada um tem acesso a seu próprio canal privado.
- Linha 22-100: Uma função de sincronização simples que faz o seguinte
- Linha 29-36: Validação de documento para garantir que o documento contenha as propriedades "tag" e "owner" definidas pelo usuário
- A propriedade "tag" é usada para especificar se o documento está disponível publicamente para qualquer usuário ou se é privado para um usuário
- A propriedade "owner" é usada para especificar se o documento está disponível publicamente para qualquer usuário ou se é privado para um usuário
- Linha 46: Dê ao usuário acesso ao "_public" e a um canal privado (identificado usando o proprietário do documento)
- Linhas 51-56: Se for uma atualização de documento, verifique se a propriedade "tag" não foi alterada nas revisões
- Linha 66: Atribuir todos os documentos com a tag "public" ao canal "_public"
- Linha 72: Atribuir todos os documentos com uma tag diferente de "public" ao canal privado
- Linha 75: Para documentos de canal privado, primeiro verifique se o proprietário do documento é a pessoa que está fazendo a solicitação
- Linha 29-36: Validação de documento para garantir que o documento contenha as propriedades "tag" e "owner" definidas pelo usuário
Couchbase Lite
O Couchbase Lite é um banco de dados NoSQL incorporado que é executado em dispositivos. O Couchbase Lite pode ser usado em vários modos de implantação. Primeiros passos com o Couchbase Lite postagem discute o modo de implantação autônomo. O Couchbase Lite pode ser usado em conjunto com um Sync Gateway remoto que permita a sincronização de dados entre dispositivos. Esta postagem discute o modo de implementação usando um Sync Gateway.
Há muitas opções para integrar a estrutura do Couchbase Lite em seu aplicativo iOS. Confira nosso Couchbase Mobile Guia de introdução para as várias opções de integração.
API nativa
O Couchbase Lite expõe uma API nativa para iOS, Android e Windows que permite que os aplicativos interajam facilmente com a plataforma Couchbase. Como desenvolvedor de aplicativos, você não precisa se preocupar com os aspectos internos do banco de dados incorporado do Couchbase Lite, mas pode se concentrar na criação de seu aplicativo incrível. A API nativa permite que você interaja com a estrutura do Couchbase Lite da mesma forma que faria com outras estruturas/subsistemas da plataforma. Novamente, discutiremos o Couchbase Mobile v1.4 nesta postagem do blog. Você pode obter uma lista completa das APIs em nosso site do Couchbase Desenvolvedor local.
Aplicativo de demonstração para iOS
Faça o download do projeto de demonstração do Xcode a partir deste Repositório do Github e mude para a ramificação "sync support". Usaremos esse aplicativo como exemplo no restante do blog. Esse aplicativo usa o Cocoapods para integrar a estrutura do Couchbase Lite.
|
1 2 |
git clone git@github.com:couchbaselabs/couchbase-lite-ios-standalone-sampleapp.git git checkout syncsupport |

Sincronização de documentos entre usuários
- Crie e inicie o aplicativo. Você deverá receber um alerta de login
- Digite o usuário "jane" e a senha de "password". Esse usuário foi configurado no arquivo de configuração do Sync Gateway
- Adicione o primeiro documento tocando no botão "+" no canto superior direito.
- Dê um nome ao documento e uma descrição de uma linha.
- Use a tag "private".
- Nos bastidores, o Replicador Push envia o documento para o Gateway de sincronização e é processado pela Função de sincronização. Com base na tag, a função Sync atribui o documento ao canal privado do usuário.
- Adicione um segundo documento tocando no botão "+" no canto superior direito.
- Dê um nome ao documento e uma descrição de uma linha
- Use a tag "public".
- Nos bastidores, o Replicador Push envia o documento para o Gateway de sincronização e é processado pela Função de sincronização. Com base na tag pública, a função Sync atribui o documento ao canal público
- Agora, faça o "logoff" da Jane. Você verá o alerta de login novamente
- Digite o usuário "joe" e a senha de "password". Esse usuário também foi configurado no arquivo de configuração do Sync Gateway
- O documento público que foi criado por Jane será listado.
- Nos bastidores, o Pull Replicator extrai todos os documentos do canal privado e do canal público de Joe. O documento público que foi criado por Jane é extraído. No entanto, como Joe não tinha acesso ao canal privado de Jane, o documento privado criado por Jane não é extraído.
Para verificar o estado das coisas no Sync Gateway, você pode consultar a interface Admin REST usando o Postman ou qualquer cliente HTTP.
Esta é a solicitação CURL para o Sync Gateway
|
1 2 3 4 5 |
curl -X GET \ 'https://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' |
A resposta do Sync Gateway mostra os dois documentos atribuídos ao canal público e ao canal privado da 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 |
{ "rows": [ { "key": "-6gCouN6jj0ScYgpMD7Qj1a", "id": "-6gCouN6jj0ScYgpMD7Qj1a", "value": { "rev": "1-dfa6d453a1515ee3dd64012ccaf53046", "channels": [ "_jane" ] }, "doc": { "_id": "-6gCouN6jj0ScYgpMD7Qj1a", "_rev": "1-dfa6d453a1515ee3dd64012ccaf53046", "name": "doc101", "overview": "This is a private doc from Jane", "owner": "jane", "tag": "private" } }, { "key": "-A2wR44pAFCdu1Yufx14_1S", "id": "-A2wR44pAFCdu1Yufx14_1S", "value": { "rev": "1-1a8cd0ea3b7574cf6f7ba4a10152a466", "channels": [ "_public" ] }, "doc": { "_id": "-A2wR44pAFCdu1Yufx14_1S", "_rev": "1-1a8cd0ea3b7574cf6f7ba4a10152a466", "name": "doc102", "overview": "This is a public doc shared by Jane", "owner": "jane", "tag": "public" } } ], "total_rows": 2, "update_seq": 5 } |
Explorando o código
Agora, vamos examinar os trechos de código relevantes do aplicativo de demonstração do iOS
Abertura/criação de um banco de dados por usuário
Aberto DocListTableViewController.swift e localize o arquivo openDatabaseForUser função.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
do { // 1: Set Database Options let options = CBLDatabaseOptions() options.storageType = kCBLSQLiteStorage options.create = true // 2: Create a DB for logged in user if it does not exist else return handle to existing one self.db = try cbManager.openDatabaseNamed(user.lowercased(), with: options) self.showAlertWithTitle(NSLocalizedString("Success!", comment: ""), message: NSLocalizedString("Database \(user) was opened succesfully at path \(CBLManager.defaultDirectory())", comment: "")) // 3. Start replication with remote Sync Gateway startDatabaseReplicationForUser(user, password: password) return true } catch { // handle error } |
- Especifique as opções a serem associadas ao banco de dados. Explore as outras opções na classe CBLDatabaseOptions.
- Crie um banco de dados com o nome do usuário atual. Dessa forma, cada usuário do aplicativo terá sua própria cópia local do banco de dados. Se já existir um banco de dados com o nome, será retornado um identificador para o banco de dados existente; caso contrário, será criado um novo. Os nomes dos bancos de dados devem estar em letras minúsculas. Se for bem-sucedido, será criado um novo banco de dados local, caso ele não exista. Por padrão, o banco de dados será criado no caminho padrão (/Library/Application Support). Você pode especificar um diretório diferente ao instanciar o Gerenciador de CBL classe.
- Iniciar o processo de replicação do banco de dados para as credenciais de usuário fornecidas. Discutiremos o código de replicação em detalhes nas seções a seguir.
Obtenção de documentos
Abra o DocListTableViewController.swift e localize o arquivo getAllDocumentForUserDatabase função.
|
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. Create Query to fetch all documents. You can set a number of properties on the query object liveQuery = self.db?.createAllDocumentsQuery().asLive() guard let liveQuery = liveQuery else { return } // 2: You can optionally set a number of properties on the query object. // Explore other properties on the query object liveQuery.limit = UInt(UINT32_MAX) // All documents // query.postFilter = //3. Start observing for changes to the database self.addLiveQueryObserverAndStartObserving() // 4: Run the query to fetch documents asynchronously liveQuery.runAsync({ (enumerator, error) in switch error { case nil: // 5: The "enumerator" is of type CBLQueryEnumerator and is an enumerator for the results self.docsEnumerator = enumerator default: self.showAlertWithTitle(NSLocalizedString("Data Fetch Error!", comment: ""), message: error.localizedDescription) } }) } catch { // handle error } |
- Obter o identificador do banco de dados com o nome especificado
- Crie um objeto de consulta. Essa consulta é usada para buscar todos os documentos. A função Sync no Sync Gateway garantirá que os documentos sejam extraídos apenas dos canais acessíveis ao usuário. Você pode criar um objeto de consulta regular ou um objeto de consulta "ao vivo". O objeto de consulta "ao vivo" é do tipo CBLLiveQuery que se atualiza automaticamente toda vez que o banco de dados é alterado de forma a afetar os resultados da consulta. A consulta tem várias propriedades que podem ser ajustadas para personalizar os resultados. Tente modificar as propriedades e veja o efeito nos resultados
- Você terá de adicionar explicitamente um observador ao objeto Live Query para ser notificado das alterações no banco de dados. Falaremos mais sobre isso na seção "Observação de alterações sincronizadas locais e remotas em documentos". Não se esqueça de remover o observador e parar de observar as alterações quando não precisar mais dele!
- Execute a consulta de forma assíncrona. Você também pode fazer isso de forma síncrona, se preferir, mas provavelmente é recomendável fazê-lo de forma assíncrona se os conjuntos de dados forem grandes.
Quando a consulta é executada com êxito, você obtém um objeto CBLQueryEnumerator. O enumerador de consultas permite enumerar os resultados. Ele se presta muito bem como fonte de dados para a Table View que exibe os resultados
Observação de alterações sincronizadas locais e remotas em documentos
Abra o DocListTableViewController.swift e localize a função addLiveQueryObserverAndStartObserving.
As alterações no banco de dados podem ser resultado das ações do usuário no dispositivo local ou podem ser resultado de alterações sincronizadas de outros dispositivos.
|
1 2 3 4 5 |
// 1. iOS Specific. Add observer to the live Query object liveQuery.addObserver(self, forKeyPath: "rows", options: NSKeyValueObservingOptions.new, context: nil) // 2. Start observing changes liveQuery.start() |
- Para ser notificado sobre as alterações no banco de dados que afetam os resultados da consulta, adicione um observador ao objeto Live Query. Em vez disso, aproveitaremos o padrão Key-Value-Observer do iOS para sermos notificados das alterações. Adicione um observador KVO ao objeto Live Query para começar a observar as alterações na propriedade "rows" do objeto Live Query Isso é tratado por meio de APIs de manipulador de eventos apropriadas em outras plataformas, como o addChangeListener no Android/Java.
- Comece a observar as mudanças.
Sempre que houver uma alteração no banco de dados que afete a propriedade "rows" do objeto LiveQuery, seu aplicativo será notificado das alterações. Ao receber a notificação de alteração, você pode atualizar a interface do usuário, que, nesse caso, seria recarregar a exibição da tabela.
|
1 2 3 4 |
if keyPath == "rows" { self.docsEnumerator = self.liveQuery?.rows tableView.reloadData() } |
Autenticação de solicitações de replicação
Aberto Arquivo DocListTableViewController.swift e localizar startDatabaseReplicationForUser função.
Todas as solicitações de replicação devem ser autenticadas. Neste aplicativo, usamos a autenticação básica HTTP.
|
1 |
let auth = CBLAuthenticator.basicAuthenticator(withName: user, password: password) |
Há vários tipos de autenticadores, a saber: Básico, Facebook, OAuth1, Persona, SSL/TLS Cert.
Replicação pull
Aberto Arquivo DocListTableViewController.swift e localizar startPullReplicationWithAuthenticator função.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 1: Create a Pull replication to start pulling from remote source let pullRepl = db?.createPullReplication(URL(string: kDbName, relativeTo: URL.init(string: kRemoteSyncUrl))!) // 2. Set Authenticator for pull replication pullRepl?.authenticator = auth // Continuously look for changes pullRepl?.continuous = true // Optionally, Set channels from which to pull // pullRepl?.channels = [...] // 4. Start the pull replicator pullRepl?.start() |
- Crie um Pull Replicator para extrair alterações do Sync Gateway remoto. O kRemoteSyncUrl é o URL do ponto de extremidade do banco de dados remoto no Sync Gateway.
- Associar o Authenticator à replicação pull. Opcionalmente, é possível definir os canais dos quais os documentos devem ser extraídos
- A configuração da replicação como "contínua" permitirá que as atualizações de alterações sejam extraídas indefinidamente, a menos que sejam explicitamente interrompidas ou que o banco de dados seja fechado.
- Iniciar a replicação pull
Replicação por push
Aberto Arquivo DocListTableViewController.swift e localizar startPushReplicationWithAuthenticator função.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
// 1: Create a push replication to start pushing to remote source let pushRepl = db?.createPushReplication(URL(string: kDbName, relativeTo: URL.init(string:kRemoteSyncUrl))!) // 2. Set Authenticator for push replication pushRepl?.authenticator = auth // Continuously push changes pushRepl?.continuous = true // 3. Start the push replicator pushRepl?.start() |
- Crie um Replicador Push para enviar alterações para o Sync Gateway remoto. O kRemoteSyncUrl é o URL do ponto de extremidade do banco de dados remoto no Sync Gateway.
- Associe o Authenticator à replicação push.
- A configuração da replicação como "contínua" permitirá que as atualizações de alterações sejam enviadas indefinidamente, a menos que sejam explicitamente interrompidas ou que o banco de dados seja fechado.
- Iniciar a replicação push
Monitoramento do status da replicação
Abra o DBListTableViewController.swift e localize a função addRemoteDatabaseChangesObserverAndStartObserving.
|
1 2 3 4 5 6 7 |
// 1. iOS Specific. Add observer to the NOtification Center to observe replicator changes NotificationCenter.default.addObserver(forName: NSNotification.Name.cblReplicationChange, object: db, queue: nil) { [unowned self] (notification) in // Handle changes to the replicator status - Such as displaying progress // indicator when status is .running } |
Você pode monitorar o status da replicação adicionando um observador à Central de Notificações do iOS para ser notificado sobre cblReplicationChange notificações . Você pode usar o manipulador de notificações, por exemplo, para exibir indicadores de progresso apropriados para o usuário. Isso é tratado por meio de APIs de manipulador de eventos apropriadas em outras plataformas, como o addChangeListener no Android/Java.
E agora?
Gostaríamos muito de ouvir sua opinião. Portanto, se tiver dúvidas ou comentários, sinta-se à vontade para entrar em contato comigo pelo Twitter @rajagp ou envie-me um e-mail priya.rajagopal@couchbase.com. Se você quiser aprimorar o aplicativo de demonstração, envie uma solicitação pull para o diretório Github Repo.
O Fóruns de desenvolvimento do Couchbase Mobile Outro ótimo lugar para obter respostas para suas perguntas relacionadas a dispositivos móveis é o portal de desenvolvimento, que oferece detalhes sobre o Gateway de sincronização e Couchbase Lite . Tudo o que foi discutido aqui está no contexto do Couchbase Mobile 1.4. Há muitas mudanças novas e empolgantes a caminho do Couchbase Mobile 2.0. Não deixe de conferir o Visualização do desenvolvedor versão 2.0 do Couchbase Mobile.
Olá, Priya!!!!
Essa foi uma postagem muito boa sobre sincronização de dados em Swift. Se você puder fornecer também em objective C, agradeceria.
Obrigado!
Olá, Priya,
Baixei e instalei o aplicativo UserProfileDemo para Xamarin. Tentei testá-lo executando-o em dois simuladores simultaneamente, mas lamento dizer que o aplicativo não funciona como esperado. Os dados não são sincronizados quando se faz login com as mesmas credenciais no outro simulador. Ele sempre busca os dados do banco de dados local, mas nenhuma sincronização global funciona.
Seu comentário parece não estar relacionado a esta postagem do blog e ao tutorial (que, na verdade, é para iOS nativo no Couchbase Mobile 1.4). Você seguiu as instruções deste tutorial do Xamarin? https://docs.couchbase.com/userprofile-couchbase-mobile/sync/userprofile/xamarin/userprofile_sync.html. Se estiver tendo problemas com esse tutorial, publique em nossos fóruns de desenvolvimento (forums.couchbase.com) com os registros relevantes