streda 4. januára 2017

Firebase Cloud Messaging in Android

Firebase Cloud Messaging (FCM) je v podstate nová platforma na posielanie push správy. Nahrádza starý framework Google Cloud Messaging (GCM), ktorý je momentálne deprecated. Trochu som sa hral s FCM-kom a popravde, mi zo začiatku prišlo zložitejšie, keďže môžem posielať dva typy správ, a to: Notification message a Data message. Správy môžeme posielať troma spôsobmi, teda jednému zariadeniu, skupine zariadení alebo zariadení, ktoré sú subscribnuté na nejaký topic. FCM ponúka ešte jednu možnosť, ale tú som osobne neskúšal, keďže som sa ešte nestretol počas vývoja s takým use caseom, jedná sa o posielanie správ smerom od zariadenia na server. Bližšie introduction ponúka následujúci link: Firebase Cloud Messaging.

Pridanie Firebase Cloud Messaging-u do projektu


FCM má zmysel pre zariadenia verzie Android 2.3 a vyššie, je potrebné mať aj Google Play Services SDK  a minimálne Android Studio 1.5 alebo vyššie. Pri Google Play Services si treba dať ale pozor, spoločnosť Google oznámila, že prestane podporovať zariadenia Android verzie 2.3 a 3.0. To znamená, že Google Play Services verzie 10.2.0 už bude podporovať zariadenia s verzion 4.0 a vyššie, bližšie info: Google Play Services and Firebase for Android will support API level 14 at-minimum.

Pridať FCM je možné dvoma spôsobmi, a to manuálne alebo pomocou Assistant záložky v Android Studio. Použitie Assistanta neopíšem, pôjdem manuálnou cestou.
Ako prvé je nutné vytvoriť vo Firebase konzole projekt, viď. obrázok:

Firebase console - create new project
Po vyplnení mená projektu nám ukáže ďaľšiu obrazovku, kde môžeme pridať aplikáciu do projektu. Po zvolení pridania, nám zobrazí dialóg, ktorý nás prevedie všetkými potrebnými krokmi. Prvá obrazovka je:
Firebase console - dialóg pridanie aplikácie
V prvom dialógu pridania aplikácie je potrebné vyplniť package name aplikácie. Pozor, treba zadať presne a nepomýliťsa. Možné je aj dodať ďalšie voliteľné polia, viac sa o nich môžete dozvedieť tak v samotnom dialógu. Dialóg poskytuje nápovedu.
Firebase console - vygenerovania a stiahnutie config súboru
V tejto obrazovke nám dialóg vygeneruje config súbor a začne automatické sťahovanie(možno vyzve na potvrdenie začatia sťahovania v prehliadači, záleží od konkrétneho prehliadača a jeho nastavení) config súboru, ktorý má meno google-services.json. Ten si treba pridať do Android Studia projektu, veď návod už je v dialógu, stačí len čítať.

Firebase console - zakončenie dialógu a posledné úpravy v projekte Android Studia 
Následne je potrebné pridať niekoľko riadkov do build.gradlu ako je v poslednej časti dialógu. Keby nestačil návod v dialógu, alebo tento návod: Android firebase setup. Ako posledné je potrebné ešte pridať požadované dependencie: compile 'com.google.firebase:firebase-messaging:10.0.1' .



Editácia manifestu a zdrojákov

Pre ďalšiu prácu potrebujem pridať dve služby na projektu a definovať ich v manifeste. Vytvorím classu s menom MessagingService, kde extendnem triedu FirebaseMessagingService. To nám poslúži ako kostra na pridanie eventu, ktorý obslúži push message. Potom vytvorím druhú classu TokenGenerationService, kde extendnem triedu FirebaseInstanceIdService, ktorá ma na starosti generovanie tokenu, ktorý neskôr využijeme. V manifeste projektu treba definovať ešte dve služby, a to:

<service android:name=".MessagingService">
  <intent-filter>
     <action android:name="com.google.firebase.MESSAGING_EVENT"/>
  </intent-filter>
</service>


<service android:name=".TokenGenerationService">
  <intent-filter>
     <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
  </intent-filter>
</service>

Položiek do manifestu súvisiacích s FCM je viacej, stačí sa obrátiť na tento zdroj Set Up a Firebase Cloud Messaging Client App on Android. Dve ďaľšie súvisia s nastaveniami defaultnej ikony pre notifikácie a farby prichádzajúcej notifikácie. Týmto sme urobili všetko potrebné a stačí nám úž len v doplniť potrebný kód do tried, ktoré sme vyššie uviedli. Ešte poznámku, že ak chceme používať vygenerovaný token, netreba zabúdať, že sa vygeneruje nanovo vždy počas určitých udalostí, ktoré nastanú v zariadení, Vo vyššie uvedenom linku sa dá dočítať počas akých udalosti sa generuje na novo token. Udalosť, kde ohandlujeme novo vygenerovaný token by mohla vyzerať takto:

public class TokenGenerationService extends FirebaseInstanceIdService {
@Override
public void onTokenRefresh() {
    super.onTokenRefresh();
    String refreshedToken = FirebaseInstanceId.getInstance().getToken();
    //tymto mozeme vidiet v logcat-e ako vypada token
    Log.d("BAGA", refreshedToken);

    /*
    token mozeme posielat na backend server aby som subscribol aplikaciu pre
    odber noviniek a posielanie upozorneni uzivatelom na zariadenia alebo mozem 
   uplne ignorovat token, to zalezi od use case-u
   */
 }
}


Posledná trieda má na starosti spracovanie push správ, ktoré prichádzaju v údalosti onMessageReceived. Než doplním  poslednú triedu, ktorá bude mať na starosti príjem push správy a vytvorenie notifikácie v zariadení, vysvetlím aké typy push správ posiela server. 

Push správy (Push message)

Google predstavil dva typy správ a to Notification message a Data message. Každá z nich má určité výhody, ale aj nevýhody. Skúsim ich naznačit, ale bližšie informácie sa nájdu na tomto mieste: About FCM Messages

Notification message:
  • je ľahšia verzia správy s veľkosťou do 2 KB
  • má preddefinované kľúče, ktoré sa nedajú meniť ani dopĺňať(vysvetlím nižšie)
Takto vydapá Notification message, všetko čo object notification obsahuje, je preddefinované a nedajú sa dopĺňať dodatočné informácie. To znamená, že ak máme ešte potrebujeme poslať iné štruktúrované (xml, json alebo iné) údaje môžeme to poslať jedine v kľúči body, ale to by bolo neprehľadné. Ostatné kľúče sú vopred preddefinované a slúžia svojmu účelu. Tak napr. kľúč title je titulok notifikácie, ktorá sa zobrazí v zariadení a body je zase text notifikácie. Kľúč icon slúži na názov ikony, ktorú je potrebné použiť, ale s tou nemám také skúsenosti a neviem si to presne predstaviť ako to má fungovať.


{
 "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
 "notification" : {
     "body" : "great match!",
     "title" : "Portugal vs. Denmark",
     "icon" : "myicon"
     }
}

Nakoniec tu máme Date message:
  • správa môže byť veľkosťou do 4 KB
  • môže mať užívateľom definované kľuče a hodnoty
{
 "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
 "data" : {
     "Nick" : "Mario",
     "body" : "great match!",
     "Room" : "PortugalVSDenmark"
 },
}



Nič nam nebráni v tom použiť ešte ďaľšie kľúče v Data message. Pre jednoduchší život radšej používajte Data message. Dôvod je hlavne taký, že aplikácia handluje prijatú správu, viac informácií je možné nájsť v následujúcom linku Receive Messages in an Android App. Na ozrejmenie nám poslúži následujúca tabuľka:


Tabl 1. Správanie aplikácie pri Notification a Data message
Stav aplikácie Notification Data Obidve
Foreground onMessageReceived onMessageReceived onMessageReceived
Background System tray onMessageReceived Notification: System tray
Data: v extras Intentu


Ešte raz opakujem pre lepší život je vhodnejšie na začiatku používať Data message. Takže keď pošleme Notification message a aplikácia je v popredí(foreground), tak správa sa spracuje v udalosti onMessageReceived služby MessagingService. Ak je aplikácia v pozadí (background), tak správa sa nespracuje v onMessageReceived, ale zobrazí sa v systemových notifikáciach a po tapnutý na notifikáciu otvorí hlavnú obrazovku aplikácie. Užívateľ nemá dosah pomocou aplikácie na to ako sa zobrazí notifikácia v systémovom tray bare a ani nemá dosah na to keď sa tapne aby sa zobrazila určitá obrazovka aplikácie. Ak sa jedná o Data message, život máme jednoduchší. Všetko sa môže spracovať v onMessageReceived.

onMessageReceived

Tak prišiel čas na to implementovať túto udalosť a zobraziť jednoduchú notifikáciu v system tray bare. V podstate je tento event jednoduchý, stačí dobre ohandlovať, viď. nižšie:

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
  super.onMessageReceived(remoteMessage);
  if (remoteMessage.getData().size() > 0){
      Log.d("BAGA", remoteMessage.getData().get("Nick"));
      Log.d("BAGA", remoteMessage.getData().get("body"));
      Log.d("BAGA", remoteMessage.getData().get("Room"));
  }
}

Tento event je veľmi jednoduchý. Môžeme vybuildovať notifikáciu a pending intentom, ktorý spustí nami zvolenú aktivitu alebo inú akciu, záleží podľa use case-u.

Na záver ukážem ako môžeme posielať push správy so servera do zariadenia. Príklad bude ale pod windowsom v PowerShell konzole, keďže som dlhoročný užívateľ windows.

Server a posielanie push správ

Posielať push správy budeme posielať na Google servere a ten ich bude rozposielať jednotlivým zariadeniam. Adresa, na ktorú sa majú posielať jednotlivé push správy je: https://fcm.googleapis.com/fcm/send. Posiela sa to ako HTTP POST. Treba definovať http hlavičku, kde idú polia:

  • kľúč: Content-Type, hodota:  application/json
  • kľúč: Authorization, hodnota: key=<moj-server-kluc>
Server kľúč je možné nájsť vo firebase konzole, nastaveniach projektu. Následne treba vygenerovať JSON, ktoré pôjde do HTTP tela. JSON bude mať následujúcu podobu:

 {
    "to":"cqlFlvpZvTw......",
        "data": {
              "Nick" : "Mario",
              "body" : "great match!",
              "Room" : "PortugalVSDenmark"
     }
}

V tomto prípade treba brať do úvahy, že kľúč "to" obsahuje hodnotu, čo je token, ktorý vygenerovalo zariadenia. Tento token vieme získať so zariadenia a ho na server. V našom prípade ho ale vytiahneme z logcat-u. Ako štruktúrovať JSON správu a aké kľúče je možné použiť je možné vidieť v následujúcom linku Firebase Cloud Messaging HTTP Protocol.

Záver

FCM je v podstate asi jednoduchšie oproti GCM. Jednotlivé rozdieli medzi FCM a GCM a ako migrovať si môžete prečítať tu: Migrate a GCM Client App for Android to Firebase Cloud Messaging. Pre vývojárov je FCM veľmi jedoduchý implementovať v aplikácií. Osobne som sa s touto technológiou stretol prvýkrát a musím povedať, že som rýchlo pochopil koncept a aj implementoval v aplikácií pre zákazníka.