Aeronave urbana é um serviço popular de mensagens e notificações. Na parte 1 desta postagem, veremos como configurar as notificações push do Urban Airship. Na parte 2 da postagem, usaremos essas notificações para acionam replicações em Couchbase Mobile.
O que você precisará
Você pode usar o Urban Airship (UA) gratuitamente. (Consulte o site da UA para obter detalhes sobre os preços atuais.) É necessário registrar uma conta.
- Relato de um dirigível urbano
- Uma conta do Firebase (requer uma conta de login do Google)
- Android Studio (ou Xcode)
Parte 1 - Configurando o Urban Airship
Abra um projeto Android ou iOS existente em seu IDE (ou crie um novo). Aqui, ilustrarei o uso do Android.
Faça login na sua conta da UA. Navegue até a página Novo aplicativo. Preencha o nome do aplicativo. Selecione as plataformas que você deseja usar. (Escolheremos Android e iOS para este exemplo.) Ao clicar em "Save", você será levado ao guia de início rápido. (Se você já tiver passado pelo início rápido e precisar relembrar a configuração, poderá encontrar as etapas para Android aqui e para iOS aqui.)
Início rápido da UA
Aqui é oferecida uma guia para cada plataforma selecionada. Conforme mencionado, vamos nos concentrar na criação para Android desta vez.
Siga as etapas de início rápido do Urban Airship. Tenho algumas dicas para os problemas que encontrei.
Etapas 1 e 2 do início rápido do Urban Airship
O guia UA refere-se ao script build.gradle do projeto, mas mostra a modificação do script build.gradle do módulo. Adicionei o repositório do UA ao script gradle do meu projeto e a dependência do UA ao script gradle do módulo. Isso funcionou bem.
Procure o ID do aplicativo no script gradle do módulo.
Etapa 5 do início rápido do Urban Airship
Para criar sua própria classe de aplicativo, clique com o botão direito do mouse na área do aplicativo do painel de navegação do projeto e selecione Novo > Classe Java. Na janela pop-up, defina o nome da classe. Em seguida, para a superclasse, digite android.app.Application.
Não se esqueça de atualizar seu arquivo de manifesto. Você pode usar o nome totalmente qualificado de sua classe ou a forma abreviada que o UA mostra. O formulário totalmente qualificado tem a seguinte aparência:
1 2 |
<aplicativo androide:nome="com.couchbase.cblite.android.cbpushsync.MyApplication" |
Etapa 6 do início rápido do Urban Airship
A UA usa o Firebase Cloud Messaging (FCM). A sexta etapa tem um link para a documentação adicional da UA. Essa nova página tem instruções detalhadas sobre como criar uma chave de API para seu aplicativo.
As instruções nessa página sob o título "Configurar o serviço FCM/GCM com o Urban Airship" estão um pouco desatualizadas. Você encontrará a área para inserir a chave Api e o pacote no final do guia de início rápido agora, em vez de onde os documentos dizem para procurar.
Em um lugar, os documentos do UA se referem ao "Número do projeto da API do Google". Isso é o que o FCM chama de ID do remetente.
Testes
O início rápido termina com uma área de teste, sem muitas instruções. Se você observar o código incluído na subclasse Application, verá que ele está ativando as notificações do usuário. Para testar, crie seu aplicativo e instale-o em um emulador ou dispositivo. (Tentei em ambos e funcionaram bem).
Digite algo no campo de texto e clique em "Send Test" (Enviar teste). Você verá um ícone aparecer na área de notificação do Android. Estranhamente, isso não inclui o texto inserido na área de teste.
Para a solução de problemas, a UA o direciona para um link obscuro "Error Console" no canto inferior direito da página de documentação. Infelizmente, o link só me levou de volta ao guia de início rápido.
Concluindo a parte 1
Como você viu nas etapas anteriores, a configuração do Urban Airship foi bastante rápida. O início rápido mostra como enviar uma notificação de alerta. Para acionar a sincronização de dados em um cliente do Couchbase Lite, é necessário enviar um alerta silencioso; a parte 2 desta publicação abordará esse assunto.
Parte 2 - Acionando a sincronização de dados a partir da nuvem
Na parte 1 desta postagem, você configurou o Urban Airship; na parte 2, mostrarei um aplicativo Android de amostra criado com Couchbase Lite que usa uma notificação push do Urban Airship para acionar a sincronização de dados da nuvem para um dispositivo móvel. Aqui, "a nuvem" será um Gateway de sincronização em uma configuração de teste. (O Couchbase Lite e o Sync Gateway fazem parte da pilha do Couchbase Mobile. Você pode ler sobre o Couchbase Mobile aqui.)
Histórico
O Couchbase Mobile sincroniza os dados usando replicações unidirecionais. Você pode definir as replicações para serem executadas e encerradas imediatamente quando os dados locais estiverem atualizados ("one-shot") ou para ouvir indefinidamente novas alterações ("continuous").
Há alguns motivos pelos quais você pode querer usar um serviço como o Urban Airship para acionar a sincronização em vez de configurar uma replicação contínua. Por exemplo, uma replicação contínua "pull" (que recupera dados da nuvem) precisa manter uma conexão de rede aberta. Uma conexão aberta necessariamente causará algum consumo na bateria do dispositivo, mesmo quando estiver inativa. O ideal é que um aplicativo abra uma conexão somente quando houver alterações a serem transferidas.
Além disso, os serviços de notificação por push, como o Urban Airship, costumam ter vários recursos avançados para lidar com grupos de dispositivos. A UA pode lhe proporcionar grande flexibilidade no gerenciamento de quando as operações acontecem. Além disso, se o seu aplicativo já usa um serviço push, ele já requer sua própria conexão de rede aberta. Faz sentido usar isso para acionar o Couchbase Lite em vez de duplicar a rede.
Este exemplo mostrará como integrar o Urban Airship. Examinarei todas as peças necessárias para que você possa criar um aplicativo totalmente funcional.
O aplicativo
Aqui está uma olhada no aplicativo em ação. A parte superior da imagem mostra o aplicativo em execução. A parte inferior mostra uma notificação push enviada pela linha de comando. Quando o aplicativo recebe a notificação por push, ele exibe um botão giratório de progresso, dispara uma replicação pull de uma só vez e exibe as alterações do documento recebidas em uma exibição de texto.
Para entender esse exemplo, daremos uma olhada em quatro classes, um pouco da "cola" que as une e mostraremos como testar os resultados.
Classes exigidas pela Urban Airship
Para usar o Urban Airship (UA), precisamos implementar duas classes, uma subclasse do Autopilot e uma subclasse do AirshipReceiver.
Piloto automático
UA precisa ser inicializado antes do uso. Você pode fazer isso de duas maneiras: ou chamar decolagem
na seção onCreate
ou criando uma subclasse do Autopilot. Optei pela segunda opção. Como veremos, o UA tem uma maneira interessante de usar automaticamente nossa subclasse.
A classe é simples. Não quero exibir nada na barra de notificação. Uso essa classe para desativar as notificações do usuário, e isso é tudo.
Aqui está a listagem completa do CBAutoPilot.java.
1 2 3 4 5 6 7 8 9 10 11 |
pacote com.couchbase.cblite.androide.cbpushsync; importação com.urbanairship.Piloto automático; importação com.urbanairship.UAirship; público classe CBAutoPiloto se estende Piloto automático { @Override público vazio onAirshipReady(UAirship aeronave) { aeronave.getPushManager().setUserNotificationsEnabled(falso); } } |
Para usar essa classe, o UA emprega uma técnica exclusiva do Android. Você indica qual classe usar com uma entrada em seu arquivo de manifesto do Android. No meu caso, a entrada tem a seguinte aparência (colocada dentro do arquivo aplicativo
seção):
1 2 |
<meta-dados androide:nome="com.urbanairship.autopilot" androide:valor="com.couchbase.cblite.android.cbpushsync.CBAutoPilot"/> |
É aqui que acontece um pouco da mágica do Android. O UA inclui uma classe de provedor de conteúdo para automatizar a inicialização. É garantido que os provedores de conteúdo sejam instanciados antes que o aplicativo onCreate
é chamado. O UA usa isso para incluir código para ler essa entrada de metadados, instanciar a subclasse e chamar o método onAirshipReady
método.
AirshipReceiver
Com o UA inicializado e pronto para funcionar, precisamos fornecer os ganchos para capturar e processar as notificações. Para fazer isso, implemente uma subclasse de AirshipReceiver. Novamente, a classe é simples.
Aqui está a listagem completa do CBAirshipReceiver.java.
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 |
pacote com.couchbase.cblite.androide.cbpushsync; importação androide.conteúdo.Contexto; importação androide.suporte.anotação.Não nulo; importação androide.util.Registro; importação com.urbanairship.AirshipReceiver; importação com.urbanairship.empurrar.PushMessage; público classe CBAirshipReceiver se estende AirshipReceiver { privado estático final Cordas TAG = "CBAirshipReceiver"; @Override protegida vazio onPushReceived(Contexto contexto, PushMessage mensagem, booleano notificaçãoPublicado) { Registro.i(TAG, "Mensagem push recebida. Alerta: " + mensagem.getAlert() + ". notificação postada: " + notificaçãoPublicado); interruptor(mensagem.getAlert()) { caso "start": CBLHelper.getInstance().startReplication(); quebra; caso "stop" (parar): CBLHelper.getInstance().stopReplication(); quebra; caso "reset": CBLHelper.getInstance().redefinir(); quebra; padrão: quebra; } } @Override protegida vazio onChannelCreated(@NonNull Contexto contexto, @NonNull Cordas channelId) { Registro.i(TAG, "Canal criado. Id do canal:" + channelId + "."); } @Override protegida vazio onChannelUpdated(@NonNull Contexto contexto, @NonNull Cordas channelId) { Registro.i(TAG, "Canal atualizado. Id do canal:" + channelId + "."); } @Override protegida vazio onChannelRegistrationFailed(Contexto contexto) { Registro.i(TAG, "Falha no registro do canal".); } } |
Quando começarmos a testar o aplicativo, veremos como o UA permite que você defina o texto do alerta. Usei isso aqui para fornecer algumas operações remotas diferentes. Um alerta pode iniciar e interromper replicações. Também incluí a possibilidade de, enviando "reset", excluir o banco de dados. Fiz isso porque, uma vez que você replica os dados, eles são persistentes no dispositivo. O desligamento do aplicativo não redefine o banco de dados local. Em vez de sempre ter de adicionar novos documentos por meio do Sync Gateway para mostrar que a replicação está funcionando, adicionei a capacidade de limpar o banco de dados do dispositivo e começar de novo.
Você notará alguns outros métodos substituídos acima. Esses métodos são todos declarados abstratos na classe AirshipReceiver, portanto, temos de incluir pelo menos uma implementação mínima. Acontece, porém, que precisamos saber a ID do canal do dispositivo para enviar uma mensagem a ele. Essa ID de canal muda com frequência. Em um post futuro, mostrarei como registrar a ID para que um aplicativo do lado do servidor possa enviar para o dispositivo. Por enquanto, é útil registrar a ID para que possamos extraí-la e usá-la nos testes.
As classes de aplicativos
Os ganchos acima colocam o UA em funcionamento, capturam notificações e acionam ações com base em seu conteúdo. Agora vamos dar uma olhada no aplicativo em si.
O aplicativo consiste em uma Activity configurada para que possamos ver o conteúdo dos documentos à medida que eles são extraídos. A outra classe envolve algumas das funcionalidades do Couchbase Lite em um auxiliar.
A atividade principal
Na atividade principal, quero mostrar uma barra de progresso enquanto as replicações acontecem e, em seguida, exibir o conjunto de documentos enviados.
Aqui está a listagem completa do MainActivity.java
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 |
pacote com.couchbase.cblite.androide.cbpushsync; importação androide.os.Pacote; importação androide.suporte.v7.aplicativo.AppCompatActivity; importação androide.suporte.v7.widget.Barra de ferramentas; importação androide.util.Registro; importação androide.visualização.Ver; importação androide.widget.Barra de progresso; importação androide.widget.TextView; importação com.couchbase.leve.Banco de dados; importação com.couchbase.leve.Documento; importação com.couchbase.leve.DocumentChange; importação com.couchbase.leve.replicador.Replicação; importação com.couchbase.leve.replicador.Estado da Replicação; importação com.xml mais rápido.jackson.vinculação de dados.Mapeador de objetos; importação java.io.IOException; público classe Atividade principal se estende AppCompatActivity { privado estático Cordas TAG = Atividade principal.classe.getSimpleName(); privado estático final Mapeador de objetos mapeador = novo Mapeador de objetos(); privado CBLHelper cblHelper = CBLHelper.getInstance(); privado TextView documentView; privado Barra de progresso barra de progresso; @Override protegida vazio onCreate(Pacote savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Barra de ferramentas barra de ferramentas = (Barra de ferramentas) findViewById(R.id.barra de ferramentas); setSupportActionBar(barra de ferramentas); documentView = (TextView) findViewById(R.id.documentView); barra de progresso = (Barra de progresso) findViewById(R.id.barra de progresso); cblHelper.inicializar( novo Banco de dados.ChangeListener() { @Override público vazio alterado(Banco de dados.ChangeEvent evento) { Registro.i(TAG, "Database change called: count - " + evento.getChanges().tamanho()); se (!evento.isExternal()) { retorno; } Cordas json = ""; para (final DocumentChange mudança : evento.getChanges()) { se (!mudança.isCurrentRevision()) { continuar; } Documento changedDoc = cblHelper.getExistingDocument(mudança.getDocumentId()); se (changedDoc == nulo) continuar; tentar { json += mapeador.writeValueAsString(changedDoc.getProperties()); } captura (IOException e) { e.printStackTrace(); } } final Cordas texto = json; runOnUiThread(novo Executável() { @Override público vazio executar() { documentView.setText(texto); } }); } }, novo Replicação.ChangeListener() { @Override público vazio alterado(Replicação.ChangeEvent evento) { Registro.i(TAG, "Alteração de replicação chamada: " + evento.toString()); se (evento.getError() != nulo) retorno; se (evento.getTransition() == nulo) retorno; Estado da Replicação dest = evento.getTransition().getDestination(); final int replicationProgress = ((dest == Estado da Replicação.PARAR || dest == Estado da Replicação.PARADO) ? Ver.INVISÍVEL : Ver.VISÍVEL); runOnUiThread(novo Executável() { @Override público vazio executar() { barra de progresso.setVisibility(replicationProgress); } }); } } ); } } |
O núcleo do código aqui consiste em dois ouvintes de alterações, um para o banco de dados e outro para as replicações. Cada interface de ouvinte define um único método alterado
.
O ouvinte de alterações de documento nos permite rastrear as atualizações reais do documento. Uma replicação pode alterar mais de um documento ao mesmo tempo. O evento de alteração retorna uma lista de IDs de documentos. Percorrendo as IDs dos documentos, recuperamos cada documento diretamente, traduzimos o conteúdo do JSON em uma cadeia de caracteres e o anexamos ao texto a ser exibido. Os ouvintes de alteração são chamados em um thread em segundo plano. Para finalizar, precisamos manipular os elementos da interface do usuário no thread principal. Isso é feito facilmente com a função runOnUiThread
do Activity.
O outro ouvinte nos permite exibir um spinner de espera ocupada (barra de progresso indefinida), dependendo do estado da replicação. Você pode ler mais sobre o monitoramento do estado da replicação aqui.
A classe auxiliar de banco de dados
Costumo envolver as funções do banco de dados em uma classe auxiliar. Como precisamos apenas de uma instância do auxiliar, uso um padrão singleton. Assim como no UA, quero que o auxiliar esteja disponível antes do início do aplicativo principal. Uso a mesma técnica de colocar o código em um provedor de conteúdo.
Aqui está a listagem completa do CBLHelper.java.
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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
pacote com.couchbase.cblite.androide.cbpushsync; importação androide.conteúdo.Provedor de conteúdo; importação androide.conteúdo.Valores de conteúdo; importação androide.banco de dados.Cursor; importação androide.rede.Uri; importação androide.os.Manipulador; importação androide.os.Looper; importação androide.suporte.anotação.Não nulo; importação androide.suporte.anotação.Nulável; importação androide.util.Registro; importação com.couchbase.leve.CouchbaseLiteException; importação com.couchbase.leve.Banco de dados; importação com.couchbase.leve.Documento; importação com.couchbase.leve.Gerente; importação com.couchbase.leve.androide.AndroidContext; importação com.couchbase.leve.replicador.Replicação; importação java.io.IOException; importação java.rede.URL; público classe CBLHelper se estende Provedor de conteúdo { público estático final Cordas TAG = "Push Sync"; privado estático Cordas BD = "db"; //private static String syncGateway = "http://localhost:4984"; privado estático Cordas syncGateway = "http://10.0.2.2:4984"; privado estático URL syncGatewayURL; privado Gerente gerente; privado Banco de dados banco de dados; privado Replicação extrator; privado Banco de dados.ChangeListener ouvinte de mudança de banco de dados; privado Replicação.ChangeListener replicationChangeListener; privado estático CBLHelper instância; público estático CBLHelper getInstance() { retorno instância; } @Override público booleano onCreate() { instância = este; enableLogging(); tentar { syncGatewayURL = novo URL(syncGateway + "/" + BD); gerente = novo Gerente(novo AndroidContext(getContext()), Gerente.DEFAULT_OPTIONS); } captura (IOException ex) { ex.printStackTrace(); } retorno verdadeiro; } público vazio closeDatabase() { banco de dados.próximo(); } público vazio startReplication() { extrator.iniciar(); } público vazio stopReplication() { extrator.parar(); } público vazio redefinir() { stopReplication(); tentar { banco de dados.excluir(); } captura (CouchbaseLiteException ex) { ex.printStackTrace(); } inicializar(ouvinte de mudança de banco de dados, replicationChangeListener); } público vazio inicializar(Banco de dados.ChangeListener dbl, Replicação.ChangeListener rl) { tentar { banco de dados = gerente.getDatabase(BD); } captura (CouchbaseLiteException ex) { ex.printStackTrace(); } banco de dados.addChangeListener(dbl); ouvinte de mudança de banco de dados = dbl; extrator = banco de dados.createPullReplication(syncGatewayURL); extrator.addChangeListener(rl); replicationChangeListener = rl; } público Documento getExistingDocument(Cordas ID do documento) { retorno banco de dados.getExistingDocument(ID do documento); } // Registro em log privado vazio enableLogging() { Gerente.enableLogging(TAG, Registro.VERBOSE); Gerente.enableLogging(com.couchbase.leve.util.Registro.TAG, Registro.VERBOSE); Gerente.enableLogging(com.couchbase.leve.util.Registro.TAG_SYNC_ASYNC_TASK, Registro.VERBOSE); Gerente.enableLogging(com.couchbase.leve.util.Registro.TAG_SYNC, Registro.VERBOSE); Gerente.enableLogging(com.couchbase.leve.util.Registro.TAG_QUERY, Registro.VERBOSE); Gerente.enableLogging(com.couchbase.leve.util.Registro.TAG_VIEW, Registro.VERBOSE); Gerente.enableLogging(com.couchbase.leve.util.Registro.TAG_DATABASE, Registro.VERBOSE); } // Função auxiliar para despachar no thread da interface do usuário privado vazio runOnUiThread(Executável executável) { novo Manipulador(Looper.getMainLooper()).postagem(executável); } // Substituições necessárias @Nullable @Override público Cursor consulta(@NonNull Uri uri, @Nullable Cordas[] projeção, @Nullable Cordas seleção, @Nullable Cordas[] selectionArgs, @Nullable Cordas sortOrder) { retorno nulo; } @Nullable @Override público Cordas getType(@NonNull Uri uri) { retorno nulo; } @Nullable @Override público Uri inserir(@NonNull Uri uri, @Nullable Valores de conteúdo valores) { retorno nulo; } @Override público int excluir(@NonNull Uri uri, @Nullable Cordas seleção, @Nullable Cordas[] selectionArgs) { retorno 0; } @Override público int atualização(@NonNull Uri uri, @Nullable Valores de conteúdo valores, @Nullable Cordas seleção, @Nullable Cordas[] selectionArgs) { retorno 0; } } |
Você pode ver que essa classe forma apenas um invólucro fino. Mantemos uma instância da classe durante onCreate
que se torna nosso singleton. Algumas outras configurações básicas acontecem, como ativar o registro e criar um gerenciador de banco de dados. Eu escrevi um inicializar
usado para realmente abrir o banco de dados, preparar a replicação pull e anexar os dois ouvintes de alteração. Lembre-se de que ele é chamado a partir da nossa classe Activity. (Observação: você pode ter mais de um ouvinte de alterações para cada tipo. O Couchbase mantém uma lista de todos os ouvintes adicionados, não apenas o mais recente). Os outros métodos do banco de dados fornecem apenas atalhos simples.
Um provedor de conteúdo tem vários métodos obrigatórios a serem implementados. Precisamos fornecer esboços para eles, que você vê nos últimos cinco métodos.
O manifesto do Android
Por fim, apenas para mostrar como tudo isso se encaixa e como as várias partes são expostas, incluí o arquivo de manifesto do Android para o projeto.
Aqui está a listagem completa do AndroidManifest.xml.
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 |
<?xml versão="1.0" codificação="utf-8"?> <manifesto xmlns:androide="http://schemas.android.com/apk/res/android" pacote="com.couchbase.cblite.android.cbpushsync"> <aplicativo androide:allowBackup="true" (verdadeiro) androide:ícone="@mipmap/ic_launcher" androide:rótulo="@string/app_name" androide:suportaRtl="true" (verdadeiro) androide:tema="@style/AppTheme"> <meta-dados androide:nome="com.urbanairship.autopilot" androide:valor="com.couchbase.cblite.android.cbpushsync.CBAutoPilot"/> <atividade androide:nome=".MainActivity" androide:rótulo="@string/app_name" androide:tema="@style/AppTheme.NoActionBar"> <intenção-filtro> <ação androide:nome="android.intent.action.MAIN" /> <categoria androide:nome="android.intent.category.LAUNCHER" /> </intenção-filtro> </atividade> <receptor androide:nome=".CBAirshipReceiver" androide:exportado="false" (falso)> <intenção-filtro> <ação androide:nome="com.urbanairship.push.CHANNEL_UPDATED" /> <ação androide:nome="com.urbanairship.push.OPENED" /> <ação androide:nome="com.urbanairship.push.RECEIVED" /> <ação androide:nome="com.urbanairship.push.DISMISSED" /> <categoria androide:nome="${applicationId}" /> </intenção-filtro> </receptor> <provedor androide:autoridades="${applicationId}.dbhelper" androide:exportado="false" (falso) androide:habilitado="true" (verdadeiro) androide:nome=".CBLHelper" /> </aplicativo> </manifesto> |
A biblioteca UA vem com seu próprio arquivo de manifesto. O sistema de compilação do Android integra todos os diferentes arquivos de manifesto para criar o arquivo final. O arquivo de manifesto da biblioteca UA é onde você encontrará as entradas para o provedor de conteúdo que inicializa a biblioteca.
Gateway de sincronização
Para testar o aplicativo, usei o Sync Gateway com o banco de dados Walrus integrado. O Walrus é um banco de dados banco de dados na memória geralmente usado apenas para testes. Isso evita o trabalho de configurar uma instância back-end do Couchbase Server.
Aqui está a listagem completa do arquivo de configuração do Sync Gateway.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "log": ["HTTP+"], "adminInterface": "127.0.0.1:4985", "interface": "127.0.0.1:4984", "CORS": { "origem":["*"], "loginorigin":["*"], "cabeçalhos":["Content-Type"], "maxAge": 1728000 }, "bancos de dados": { "db": { "servidor": "walrus:", "usuários": { "CONVIDADO": {"desativado": falso, "admin_channels": ["*"] } } } } } |
Isso diz ao Sync Gateway para escutar apenas no localhost
aceita todas as solicitações de origem cruzada e habilita o GUEST especial com acesso a todos os canais. É uma configuração de propósito geral muito boa para começar, a fim de garantir que tudo esteja funcionando.
Você deve ter notado que usamos 10.0.2.2 como o endereço IP do Sync Gateway no aplicativo Android. O emulador padrão que vem com o Android Studio mapeia isso automaticamente para o endereço IP do computador de hospedagem localhost
. Se você usar um emulador diferente (o Genymotion é outro popular), não deixe de pesquisar qual endereço IP usar, pois eles são diferentes.
Se quiser saber mais sobre como configurar o Sync Gateway em sua máquina de desenvolvimento ou como trabalhar com ele a partir da linha de comando, dê uma olhada em série de blogs.
Testes
Para testar tudo e gravar a animação mostrada no início do blog, executo o emulador de Android e o Sync Gateway em uma máquina. Em seguida, publico notificações por push no UA por meio de sua API REST.
Para preparar algo interessante, primeiro adiciono um documento ao Sync Gateway. Aqui está um comando do shell para fazer isso.
1 |
$ enrolar -X PUT -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{ "test" : "UA", "channels": "public" }' http://localhost:4984/db/doc |
(Leia mais sobre isso aqui).
Com um novo documento no banco de dados no Sync Gateway e o aplicativo em funcionamento, tudo o que resta é acionar uma replicação pull para ver a ação.
Aqui está o enrolar
para enviar um sinal de "início". Lembre-se de que eu extraio o valor da parte "alert" da notificação para acionar ações.
1 |
$ enrolar https://ir.urbanoirship.com/API/empurrar -u 'appKey:appMasterSecret' -X POST -H 'Content-Type: application/json' -H 'Accept: application/vnd.urbanairship+json; version=3;' -d '{"audience": { "android_channel": "3110bc81-1c7b-4ef8-a7a3-7c56aab19f08" }, "notification" : { "alert": "start" }, "device_types": "all" }' |
Você precisará fornecer sua própria chave de aplicativo e o segredo mestre do aplicativo acima. Também é necessário examinar os arquivos de registro para ver o valor do canal a ser inserido para "android_channel". Isso muda com bastante regularidade. Infelizmente, o UA não faz muito para indicar isso. Se você achar que as notificações por push não parecem estar surtindo efeito, verifique o valor do canal.
Depois de postar na UA, você verá uma resposta como esta.
1 |
{"ok":verdadeiro,"operation_id":"2a6c0edf-e5d0-4b4d-b762-ad5c4478c291","push_ids":["1951019a-2b7f-4f1b-8888-e87047a1feec"],"message_ids":[],"content_urls":[]} |
E, finalmente, para redefinir um banco de dados em branco e tentar novamente, você pode postar isso.
1 |
$ enrolar https://ir.urbanoirship.com/API/empurrar -u 'appKey:appMasterSecret' -X POST -H 'Content-Type: application/json' -H 'Accept: application/vnd.urbanairship+json; version=3;' -d '{"audience": { "android_channel": "3110bc81-1c7b-4ef8-a7a3-7c56aab19f08" }, "notification" : { "alert": "reset" }, "device_types": "all" }' |
Conclusão
Isso é tudo para preparar nosso aplicativo Android para executar replicações com base em notificações push. Não deixe de conferir esta postagem sobre o monitoramento do feed de alterações do Sync Gateway.
Pós-escrito
Download do Couchbase e do Sync Gateway aqui. Veja nosso documentação para saber como adicionar o Couchbase Lite a um projeto.
Confira mais recursos em nosso portal do desenvolvedor e nos siga no Twitter @CouchbaseDev.
Você pode postar perguntas em nosso fóruns. E participamos ativamente de Estouro de pilha.
Entre em contato comigo pelo Twitter com perguntas, comentários, tópicos que você gostaria de ver etc. @HodGreeley.
[...] Observação: você pode ler sobre a configuração do Urban Airship nesta postagem do blog. [...]