21 / 03 / 2017 Developers

Podłączenie Firebase do projektu Android

Projekt Firebase to narzędzie analityczne dla aplikacji mobilnych (zarówno Android jak i iOS) pozwalające na darmowe skorzystanie z takich modułów jak:

  • Analytics – monitorowanie zachowania użytkowników aplikacji
  • Authentication – logowanie za pomocą loginu i hasła / Facebooka / Google / Twittera / githuba (wszystko na infrastrukturze Google)
  • Realtime Database – zdalna baza danych
  • Cloud Storage – zewnętrzna powierzchnia dyskowa
  • Test Lab (tylko Android) – przydatne narzędzia umożliwiające przeprowadzić testy na różnych urządzeniach
  • Cloud Messaging – dla nas najważniejszy z modułów Firebase – manager powiadomień push (darmowy niezależnie od zasięgu powiadomienia)
  • kilka innych modułów takich jak AdMod, AdWords, Invites i inne

Projekt Firebase został przejęty przez Google w 2014 roku.

Dodawanie projektu do Firebase

Zakładam, że jesteśmy już zalogowani do konsoli Firebase (https://console.firebase.google.com/). Klikamy “Utwórz nowy projekt” i wypełniamy podstawowe dane dla naszego projektu. Po chwili mamy utworzony projekt, który możemy podpiąć pod nasze aplikacje (1 projekt to może być kilka aplikacji). Firebase nie ogranicza naszych możliwości do aplikacji mobilnych (Android i iOS), ale możemy podpiąć także aplikację webową. Tym nie będę się dzisiaj zajmował.

Powiązanie aplikacji z Firebase

Zacznijmy od zbierania w konsoli Firebase błędów występujących w naszej aplikacji. Klikam w projekcie na Crash Reporting -> Rozpocznij. Ponieważ w nowym projekcie nie mamy podpiętej jeszcze aplikacji zostaniemy poproszeni o jej dodanie.

Musimy podać:

  • nazwę pakietu – nazwa pakietu to applicationId w pliku build.gradle na poziomie aplikacji
  • pseudonim aplikacji (nie jest wymagany), jeżeli nazwa pakietu jest dla nas jasna i wystarczająca (i nie za długa) to możemy skorzystać z niej
  • certyfikat SHA-1 – nie jest konieczny dla Crash Reporting – instrukcja jak go pozyskać jest zamieszczona pod tym linkiem

Po tych informacjach możemy już pobrać plik google-services.json, który dodajemy do aplikacji. 

Do pliku build.gradle na poziomie projektu dodajemy:

buildscript {
  dependencies {
    // Add this line
    classpath 'com.google.gms:google-services:3.0.0'
  }
}

Do pliku build.gradle na poziomie aplikacji dodajemy:

...
// Add to the bottom of the file
apply plugin: 'com.google.gms.google-services'

Mamy już zainstalowane SDK i możemy dodać obsługę Crash Reporting. 

Do pliku build.gradle na poziomie aplikacji dodajemy zależności:

compile 'com.google.firebase:firebase-core:9.2.0'
compile 'com.google.firebase:firebase-crash:10.2.0'

 

Oczywiście nasze aplikacje nie zawierają błędów 😉 dlatego musimy zasymulować jakieś zdarzenie, które zaloguje się w konsoli Firebase.

Możemy to zrobić np. wg przykładu od Google:

FirebaseCrash.report(new Exception("Wyjątek do zobaczenia w Firebase Console"));

Od tej pory jeżeli w naszej aplikacji zdarzy się (a jednak) błąd to będziemy mieli sporo informacji, które mogą nam pomóc w zidentyfikowaniu problemu i poprawieniu błędu.

Przykładowy raport z błędu.. 

..widzimy jaki procent użytkowników został dotknięty błędem, czy był krytyczny (przewrócił nam aplikację), na jakich urządzeniach wystąpił.

Dostajemy też garść informacji ze stack trace:

Exception java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131624360, class android.widget.ListView) with Adapter(class pl.tim.mtim.adapters.ProductsListView)]
android.widget.ListView.layoutChildren (ListView.java:1575)
android.widget.AbsListView.onLayout (AbsListView.java:2191)
android.view.View.layout (View.java:16694)
android.view.ViewGroup.layout (ViewGroup.java:5481)
android.widget.RelativeLayout.onLayout (RelativeLayout.java:1079)
android.view.View.layout (View.java:16694)
android.view.ViewGroup.layout (ViewGroup.java:5481)
android.support.v4.view.ViewPager.onLayout (ViewPager.java:1627)
android.view.View.layout (View.java:16694)
android.view.ViewGroup.layout (ViewGroup.java:5481)
android.widget.RelativeLayout.onLayout (RelativeLayout.java:1079)
android.view.View.layout (View.java:16694)
android.view.ViewGroup.layout (ViewGroup.java:5481)
android.support.v4.widget.DrawerLayout.onLayout (DrawerLayout.java:1043)
android.view.View.layout (View.java:16694)
android.view.ViewGroup.layout (ViewGroup.java:5481)
android.widget.FrameLayout.layoutChildren (FrameLayout.java:336)
android.widget.FrameLayout.onLayout (FrameLayout.java:273)
android.view.View.layout (View.java:16694)
android.view.ViewGroup.layout (ViewGroup.java:5481)
com.android.internal.widget.ActionBarOverlayLayout.onLayout (ActionBarOverlayLayout.java:493)
android.view.View.layout (View.java:16694)
android.view.ViewGroup.layout (ViewGroup.java:5481)
android.widget.FrameLayout.layoutChildren (FrameLayout.java:336)
android.widget.FrameLayout.onLayout (FrameLayout.java:273)
com.android.internal.policy.PhoneWindow$DecorView.onLayout (PhoneWindow.java:2697)
android.view.View.layout (View.java:16694)
android.view.ViewGroup.layout (ViewGroup.java:5481)
android.view.ViewRootImpl.performLayout (ViewRootImpl.java:2229)
android.view.ViewRootImpl.performTraversals (ViewRootImpl.java:1982)
android.view.ViewRootImpl.doTraversal (ViewRootImpl.java:1140)
android.view.ViewRootImpl$TraversalRunnable.run (ViewRootImpl.java:6233)
android.view.Choreographer$CallbackRecord.run (Choreographer.java:858)
android.view.Choreographer.doCallbacks (Choreographer.java:670)
android.view.Choreographer.doFrame (Choreographer.java:606)
android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:844)
android.os.Handler.handleCallback (Handler.java:739)
android.os.Handler.dispatchMessage (Handler.java:95)
android.os.Looper.loop (Looper.java:148)
android.app.ActivityThread.main (ActivityThread.java:5527)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:730)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:620)

Wysyłanie powiadomień push

Do wysyłania powiadomień do aplikacji mobilnej musimy dodać zależność na poziomie aplikacji w build.gradle:

compile 'com.google.firebase:firebase-messaging:10.2.0'

oraz nadpisać klasę FirebaseMessagingService w manifeście:

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

Następnie w klasie MyFirebaseMessagingService implementujemy metodę:

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
}

Obsługa powiadomień odbywa się w dwojaki sposób:

  • aplikacja jest włączona – obsługujemy powiadomienia wewnątrz naszego kodu
  • aplikacja nie jest włączona – obsługa powiadomień jest standardowa

Wraz z Androidem 6.0 została zmieniona obsługa powiadomień i zamiast kolorowych ikonek na górnym pasku mamy teraz ikonki monochromatyczne z kolorem dostosowywanym do tła. Jeżeli wrzucimy do powiadomienia standardową ikonę i mamy w aplikacji używany targetSdkVersion 23 to prawdopodobnie zobaczymy zamiast naszej ikony biały (lub innego koloru) kwadrat. Spokojnie – it’s not a bug, it’s a feature 🙂
Powinniśmy ustawić ikonę jako przezroczystą, układającą się w logo – jeżeli w naszej księdze znaku jest już taka ikona zaprojektowana to po prostu jej używamy – jeżeli nie – trzeba coś stworzyć od zera. Niektóre telefony z systemem Android 6 (np. Huawei P9) rozpoznają, że aplikacja udostępnia kolorową ikonę i same obsłużą powiadomienia z kolorową ikoną. Dla innych sami musimy obsłużyć wyświetlanie poprawnej ikony. Jeżeli nie użyliśmy jeszcze na targetSdkVersion 23 to możemy nawet na Android 6 wyświetlać kolorowe ikony od razu. Jednak jeżeli nasza aplikacja weszła na Google Play z wersją 23 to już nie możemy cofnąć się do wcześniejszych wersji (związane jest to ze zmianą w uprawnieniach w nowych wersjach SDK).

Do obsługi różnych wersji możemy w metodzie onMessageReceived użyć:

NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
       .setContentTitle(messageTitle)
       .setContentText(messageBody)
       .setAutoCancel(true)
       .setSound(defaultSoundUri)
       .setContentIntent(pendingIntent);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
   notificationBuilder.setSmallIcon(R.drawable.przezroczysta).setColor(getResources().getColor(R.color.yellow));
}else{
      notificationBuilder.setSmallIcon(R.drawable.kolorowa).setColor(getResources().getColor(R.color.white));
}

Dla powiadomień, które przychodzą w czasie, kiedy aplikacja jest wyłączona, używamy parametru w samej wiadomości z Firebase – jest to parametr icon, który wprowadzamy w sekcji “Dane niestandardowe” nowej wiadomości firebase. Powiadomienia możemy wysyłać zarówno z konsoli Firebase jak i przez proste API, łatwe do implementacji w różnych językach programowania. Dzięki temu nasze powiadomienia w prosty sposób mogą być zautomatyzowane.

Podsumowanie

Wszystkie aplikacje jakimi się opiekuję mają podpięty Firebase. Dzięki niemu monitorujemy zachowanie aplikacji, użytkowników w aplikacji, poprawiamy błędy, których nie wyłapaliśmy na naszym QA, a także komunikujemy się w niektórych aplikacjach z użytkownikami za pomocą powiadomień. Narzędzie mimo szerokiej gamy zastosowań jest darmowe, co ucieszy na pewno wielu deweloperów (i managerów).

FacebookTwitterGoogle+LinkedIn
  • Fajny poradnik, Firebase w module „Analytics – monitorowanie zachowania użytkowników aplikacji” nie tylko daje możliwość monitorowania, ale też tworzenia list remarketingowych do AdWords co otwiera mega możliwości dla marketerów.