Ao desenvolver um aplicativo, é muito útil usar a replicação push e pull no modo contínuo. Tudo é tratado pelos replicadores para garantir que seu aplicativo e o Sync Gateway sempre tenham os documentos mais recentes sincronizados.
No entanto, uma replicação pull contínua significa que o Couchbase Lite usará técnicas como polling longo ou soquetes da Web para verificar se há novos dados a serem obtidos do Sync Gateway. Isso pode afetar a duração da bateria e, consequentemente, a experiência do usuário.
Nesta postagem, exploraremos uma alternativa à replicação pull contínua usando o Google Cloud Messaging, o serviço de notificação por push do Android.
Você pode dar uma olhada em exemplo de trabalho no ToDoLite Android. Vamos ver como você pode incluir a sincronização do GCM em seu aplicativo!
Habilitando o GCM em seu aplicativo
Primeiro, vamos configurar o ToDoLite Android para se registrar no Google Cloud Messaging. Criaremos um novo projeto de API do Google no diretório console do desenvolvedor. Siga este guia para configurá-lo. Você deve ter um número de projeto e uma chave de API. Agora podemos atualizar a seção AndroidManifest.xml com as permissões, o filtro de intenção e o serviço necessários. Ele deve ter a seguinte aparência:
|
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 |
// ... // ... /* ... activities ... */ |
Observação: Confira o exemplo do site do desenvolvedor do Android também.
Se o projeto estiver configurado corretamente, poderemos recuperar o token do dispositivo com o número do projeto que obtivemos ao criar o aplicativo no console do desenvolvedor do Google. Adicione um método na atividade principal para recuperar o token do dispositivo do GCM e salvá-lo no documento do perfil do usuário, por exemplo:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void getDeviceToken() { new AsyncTask() { @Override protected String doInBackground(Void... params) { GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(getApplicationContext()); String deviceToken = gcm.register("632113338862"); Log.i("GCM", "Device token : " + deviceToken); // update user profile document return null; } }.execute(null, null, null); } |
Observação: Os tokens de dispositivo no Android sempre começam com APA91, portanto, fique atento a eles no LogCat ;)
Em seguida, temos de adicionar algum código para tratar uma notificação recebida. Fizemos uma subclasse da classe WakefulBroadcastReceiver, na qual o método onReceive é chamado toda vez que recebemos uma notificação.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // Explicitly specify that GcmMessageHandler will handle the intent. ComponentName component = new ComponentName(context.getPackageName(), GcmMessageHandler.class.getName()); // Start the service, keeping the device awake while it is launching. startWakefulService(context, (intent.setComponent(component))); setResultCode(Activity.RESULT_OK); } } |
A partir daí, o serviço em vigília inicia a classe GcmMessageHandler e executa uma replicação pull de uma só vez. O serviço de vigília é executado mesmo que seu aplicativo esteja em execução em segundo plano. Assim, seu aplicativo mostraria os novos dados de acordo com a abertura do aplicativo.
|
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 |
public class GcmMessageHandler extends IntentService { /* ... */ @Override protected void onHandleIntent(Intent intent) { mIntent = intent; showToast(); Application application = (Application) getApplication(); try { URL url = new URL(BuildConfig.SYNC_URL_HTTP); Replication pull = application.getDatabase().createPullReplication(url); pull.addChangeListener(getReplicationListener()); pull.start(); } catch (MalformedURLException e) { e.printStackTrace(); } } private Replication.ChangeListener getReplicationListener() { return new Replication.ChangeListener() { @Override public void changed(Replication.ChangeEvent event) { Log.i("GCM", "replication status is : " + event.getSource().getStatus()); if (event.getSource().getStatus() == Replication.ReplicationStatus.REPLICATION_STOPPED) { GcmBroadcastReceiver.completeWakefulIntent(mIntent); } } }; } /* ... */ } |
Observe que estamos usando o ouvinte de alteração de replicação para sermos notificados quando ela for concluída e para encerrar o serviço wakeful.
Isso é tudo o que precisamos fazer no lado do Android para lidar com a notificação de sincronização.
Salvando os tokens do dispositivo
Agora podemos armazenar o token do dispositivo no documento do perfil do usuário. Cada usuário pode estar conectado a mais de um dispositivo ao mesmo tempo, portanto, devemos armazenar cada um deles. O documento do usuário terá a seguinte aparência:
|
1 2 3 4 5 |
{ "_id": "profile:johnny@couchbase.com", ... "device_tokens": ["APA91K...", "APA91O..."] } |
Na próxima seção, falaremos sobre a adição de lógica de aplicativo adicional ao Sync Gateway usando o Changes Feed.
O Gateway de sincronização altera o feed
O /database/changes retorna uma lista ordenada das alterações feitas nos documentos do banco de dados. Esse ponto de extremidade faz parte do CouchDB especificação e tanto o Couchbase Lite Listener quanto o Sync Gateway o implementam.
É muito fácil se conectar ao Changes Feed do Sync Gateway para adicionar lógica extra ao back-end, como, no nosso caso, enviar notificações push.
Você pode usar qualquer biblioteca que implemente a API de feed de alterações:
- NodeJS: https://github.com/iriscouch/follow
- Ir: https://github.com/fjl/go-couchdb
- Python: https://github.com/djc/couchdb-python
- Java: https://github.com/helun/Ektorp
De todos os parâmetros disponíveis na string de consulta, os mais importantes em nosso caso são:
- feed=continuous para garantir que recebamos as alterações imediatamente
- since=now para obter as alterações da hora atual; caso contrário, ele registrará todas as alterações desde que o banco de dados foi criado!
Por fim, vamos nos concentrar na última peça do quebra-cabeça: dada uma alteração de documento do feed de alterações, precisamos obter os documentos do perfil do usuário "interessado" nessa mudança porque eles detêm os tokens de dispositivo.
Alterações no Feed → GCM
No ToDoLite, há três tipos de documentos: um perfil, uma lista e uma tarefa. O documento de tarefa contém uma referência à lista à qual pertence e uma lista tem um proprietário e uma matriz de membros.

Quando um documento de tarefa ou um documento de lista é alterado, gostaríamos de notificar o proprietário e os membros dessa lista. Há dois tipos de eventos que gostaríamos de tratar:
1. Um evento de modificação de documento de lista:
- obter o documento de perfil do proprietário
- obter o documento de perfil de cada membro
2. Um evento de modificação de documento de tarefa:
- obter o documento da lista ao qual pertence
- siga as mesmas etapas de 1)
Com os tokens de dispositivo recuperados, a última etapa é enviar uma solicitação aos servidores do Google Cloud Messaging com nossa chave de API e carga útil de notificação. Você também pode encontrar muitas bibliotecas no GitHub que simplificam a interação com os servidores GCM:
- NodeJS: https://github.com/ToothlessGear/node-gcm
- Ir: https://github.com/alexjlockwood/gcm
- Python: https://github.com/geeknam/python-gcm
- Java: https://github.com/inloop/easygcm
Encerramento
O uso do Google Cloud Messaging para acionar a busca de dados no lado do servidor pode proporcionar uma excelente experiência ao usuário sem nenhuma sobrecarga adicional de uso da bateria e da rede.
Siga a leia-me instruções para executar a demonstração do ToDoLite.
Gostaria muito de saber como você está usando as notificações do Google Cloud Messaging em seu aplicativo. Deixe sua opinião nos comentários abaixo!
Mais leituras:
- Dicas sobre como configurar o GCM em seu aplicativo: https://blog.pushbullet.com/2014/02/12/keeping-google-cloud-messaging-for-android-working-reliably-techincal-post/
- Sincronização de dados no aplicativo Google I/O: https://android-developers.blogspot.co.uk/2014/09/conference-data-sync-gcm-google-io.html