21 marca 2017 7min.
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 wielu modułów.
Zawartość artykułu:
Moduły od Firebase
- 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 Android Studio
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 Android Studio
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
Na raporcie 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:
<
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.
Firebase Android Studio – 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).