Google Cloud Messaging (GCM) è un servizio gratuito fornito dall'omonima azienda che consente di inviare messaggi push da un server web verso un'applicazione o un'estensione Chrome.
Per poter utilizzare correttamente il servizio sarà necessario disporre dell'ultima versione della libreria Google Play Services integrata nel progetto e del relativo apk installato sul dispositivo mobile.
Funzionamento
La piattaforma GCM rende possibile l'invio di notifiche push grazie all'interazione tra tre attori: l'applicazione Android, un'applicazione server e GCM.
Spoiler:
All'avvio dell'applicazione Android che implementa i servizi GCM, per prima cosa occorre registrare l'app presso il server GCM, dal quale si otterrà un ID, che dovrà essere memorizzato sul nostro server web. Tale procedura è riassunta nell'illustrazione sottostante.
Spoiler:
In seguito, se non si vorranno più ricevere messaggi dal server web, sarà sufficiente eliminare dal database l'ID di registrazione.
In sequenza le fasi da rispettare per una corretta implementazione del servizio sono:
- Registrare l'applicazione Android sul server di GCM al primo avvio
- Dall'operazione di cui sopra si otterrà un ID alfanumerico che identifica l'applicazione e che dovrà essere memorizzato sulla vostra implementazione web (l'applicazione server)
- Se l'esito del punto due è positivo, salvare un valore booleano vero utilizzando le SharedPreferences
- Implementare un servizio per definire le operazioni da eseguire alla ricezione di un messaggio
Implementazione
Per comodità ed una migliore comprensione distingueremo le implementazioni in lato client e lato server.
Implementazione lato client
Il primo passo da fare è ottenere la Server API Key ovvero un identificatore alfanumerico che ci consentirà di comunicare con il server di GCM mediante l'applicazione web. Con la medesima procedura (illustrata a breve) si otterrà un Sender ID ossia un identificatore numerico che identifica il progetto sui server Google e autorizza l'applicazione server a comunicare con il client GCM. Per ottenere questi dati sarà sufficiente collegarsi al seguente sito, Add Google Services, e compilare il modulo inserendo tutte le informazioni richieste.
Successivamente, nel vostro progetto Android, entrare nell'AndroidManifest ed aggiungere i seguenti permessi:
1
2<uses-permission android:name="com.vostro.packagename.permission.C2 D_MESSAGE"/>
3<uses-permission android:name="com.google.android.c2dm.permission.R ECEIVE"/>
4<uses-permission android:name="android.permission.WAKE_LOCK"/>
5<uses-permission android:name="android.permission.INTERNET"/>
6
7<permission
8android:name="com.vostro.packagename.gcm.permissio n.C2D_MESSAGE"
9android:protectionLevel="signature"/>
10
Il permesso android.permission.INTERNET serve per consentire l'invio dell'ID alfanumerico che il server GCM ci restituirà all'applicazione web; android.permission.WAKE_LOCK assicurerà che il processore non si assopisca e possa ricevere correttamente i messaggi; com.vostro.packagename.permission.C2D_MESSAGE permette all'applicazione di ricevere ed inviare i messaggi, evitando che altre apps possano ricevere quei messaggi.
Aggiungere a corredo un BroadcastReceiver che avrà il compito di intercettare le richieste GCM.
121
2<receiver
3android:name="com.google.android.gms.gcm.GcmReceiv er"
4android:permission="com.google.android.c2dm.permis sion.SEND"
5android:exported="true">
6<intent-filter>
7<action android:name="com.google.android.c2dm.intent.REGIS TRATION"/>
8<action android:name="com.google.android.c2dm.intent.RECEI VE"/>
9<category android:name="com.vostro.packagename"/>
10</intent-filter>
11</receiver>
12
Attenzione: l'action com.google.android.c2dm.intent.REGISTRATION serve per supportare le versioni di Android inferiori alla 4.4 (KitKat). Senza questa dichiarazione GCM non funzionerà su API inferiori alle 19.
Inserire i seguenti servizi:
211
2<service
3android:name="com.vostro.packagename.GCMListenerSe rvice"
4android:exported="false">
5<intent-filter>
6<action android:name="com.google.android.c2dm.intent.RECEI VE"/>
7</intent-filter>
8</service>
9
10<service
11android:name="com.vostro.packagename.IDListenerSer vice"
12android:exported="false">
13<intent-filter>
14<action android:name="com.google.android.gms.iid.InstanceI D"/>
15</intent-filter>
16</service>
17
18<service
19android:name="com.vostro.packagename.RegistrationI ntentService"
20android:exported="false"/>
21
GCMListenerService è il servizio che useremo per ricevere i messaggi e mostrare la relativa notifica; IDListenerService permetterà la gestione dell'id di registrazione a GCM richiamando il servizio RegistrationIntentService che amministerà la registrazione al server GCM e all'applicazione web.
Una volta configurato l'AndroidManifest come su esposto l'app sarà pronta per ricevere messaggi. Tutto quel che rimane da fare è implementare i servizi. Il primo sarà RegistrationIntentService poichè in ordine cronologico la prima operazione da eseguire è registrare l'applicazione a GCM e al nostro web-server.
371public class RegistrationIntentService extends IntentService {
2
3InstanceID instanceId;
4
5private final static GCM_SENDER_ID = "vostro_sender_id_numerico";
6
7public RegistrationIntentService() {
8super(RegistrationIntentService.class.getSimpleName());
9// TODO Auto-generated constructor stub
10}
11
12<a rel="nofollow" href="https://www.androidiani.com/forum/members/override.html" target="_blank">Override</a>
13protected void onHandleIntent(Intent intent) {
14// TODO Auto-generated method stub
15instanceId = InstanceID.getInstance(this);
16try {
17String token = instanceId.getToken(GCM_SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
18
19try {
20JSONObject jsonObject = new JSONObject();
21jsonObject.put(GCM_ID, token);
22String webResponse = WebUtility.sendTo(GCM_URL, jsonObject.toString());
23if(!webResponse.equals(ServerCostants.RESPONSE_DUPLICATE) || !webResponse.equals(ServerCostants.RESPONSE_FAILED)) {
24//Memorizzare l'avvenuta registrazione salvando un valore booleano true
25}
26} catch (JSONException e) {
27// TODO Auto-generated catch block
28e.printStackTrace();
29}
30
31} catch (IOException e) {
32// TODO Auto-generated catch block
33e.printStackTrace();
34}
35}
36
37}
Il metodo getToken() permette di ottenere l'ID di registrazione sul server GCM basandosi sul Sender ID passato come parametro. Questo metodo non deve mai essere eseguito sul thread della UI, pena crash. Una volta ottenuto il token lo inseriamo in un JSONObject e lo inviamo al nostro web-server per registrarlo nel database. L'implementazione di come e attraverso quali strumenti inviarlo su protocollo HTTP è una vostra scelta; personalmente suggerisco l'utilizzo della libreria OkHttp che gestisce gran parte degli aspetti lasciando all'utente il mero onere di passare il dato da inviare e l'URL.
Il servizio successivo è IDListenerService che dovrà estendere la classe InstanceIDListenerService e riscrivere il metodo onTokenRefresh() che viene richiamato quando l'ID GCM subisce delle modifiche. Pertanto, quando verrà richiamato non dovrà far altro che avviare il servizio RegistrationIntentService per registrare il nuovo ID GCM.
91public class IDListenerService extends InstanceIDListenerService {
2
3<a rel="nofollow" href="https://www.androidiani.com/forum/members/override.html" target="_blank">Override</a>
4public void onTokenRefresh() {
5Intent intent = new Intent(this, RegistrationIntentService.class);
6startService(intent);
7}
8
9}
L'ultimo servizio da definire è GCMListenerService che, come detto in precedenza, è quello dal quale recupereremo i messaggi inviati da GCM e li mostreremo all'utente tramite una notifica.
81public class GCMListenerService extends GcmListenerService {
2
3<a rel="nofollow" href="https://www.androidiani.com/forum/members/override.html" target="_blank">Override</a>
4public void onMessageReceived(String from, Bundle data) {
5String message = data.getString("message");
6}
7
8}
Il metodo onMessageReceived() viene richiamato ogni qualvolta il BroadcastReceiver GcmReceiver intercetta un messaggio inviato da GCM. Sarà dunque in questo metodo che saranno eseguite le elaborazioni desiderate sui messaggi ricevuti, tenendo a mente che il parametro stringa "from" contiene il Sender ID mentre "data" i dati inviati dal nostro server.
Per concludere l'implementazione client non resta che avviare il servizio RegistrationIntentService dall'Activity desiderata.
11startService(new Intent(this, RegistrationIntentService.class));