1. Wprowadzenie
Ostatnia aktualizacja: 16 listopada 2022 r.
Tworzenie aplikacji na Androida przy użyciu Firebase i Jetpack Compose
W ramach tego ćwiczenia w Codelabs stworzysz aplikację na Androida o nazwie Make It So. Interfejs tej aplikacji jest w całości oparty na Jetpack Compose, które jest nowoczesnym narzędziem do tworzenia natywnego interfejsu użytkownika na Androida. To intuicyjne rozwiązanie, które wymaga mniej kodu niż pisanie plików .xml i powiązanie ich z aktywnościami, fragmentami czy widokami.
Pierwszym krokiem do zrozumienia, jak dobrze Firebase i Jetpack Compose współpracują ze sobą, jest poznanie nowoczesnej architektury Androida. Dobra architektura systemu jest łatwa do opanowania, opracowania i utrzymywania, ponieważ zapewnia przejrzystą strukturę elementów i komunikację między nimi. W świecie Androida zalecana architektura to Model – Widok – WidokModel. Model reprezentuje warstwę, która uzyskuje dostęp do danych w aplikacji. Widok to warstwa interfejsu, który nie powinien wiedzieć o logice biznesowej. ViewModel to miejsce, w którym stosowana jest logika biznesowa, co czasami wymaga wywołania warstwy Model.
Zdecydowanie zalecamy przeczytanie tego artykułu, aby dowiedzieć się, jak zastosowanie modelu Model – Widok – ViewModel działa w aplikacji na Androida utworzonej za pomocą Jetpack Compose, ponieważ ułatwi to zrozumienie bazy kodu i wykonanie kolejnych kroków.
Co utworzysz
Make It So to prosta aplikacja do tworzenia listy zadań, która umożliwia użytkownikowi dodawanie i edytowanie zadań, dodawanie flag, priorytetów i terminów oraz oznaczanie zadań jako ukończonych. Poniższe obrazy przedstawiają 2 główne strony tej aplikacji: stronę tworzenia zadań i stronę główną z utworzoną listą zadań.
Dodasz funkcje, których nie ma w tej aplikacji:
- uwierzytelnianie użytkowników za pomocą adresu e-mail i hasła;
- Dodawanie do kolekcji Firestore detektora i reagowanie interfejsu na zmiany
- Dodawanie niestandardowych logów czasu do monitorowania wydajności konkretnego kodu w aplikacji
- Utwórz przełącznik funkcji za pomocą Zdalnej konfiguracji i wprowadź go w ramach wdrażania etapowego
Czego się nauczysz
- Jak używać Uwierzytelniania Firebase, Monitorowania wydajności, Zdalnej konfiguracji i Cloud Firestore w nowoczesnej aplikacji na Androida
- Dopasowanie interfejsów API Firebase do architektury MVVM
- Jak odzwierciedlać zmiany wprowadzone za pomocą interfejsów API Firebase w interfejsie Compose
Czego potrzebujesz
- Android Studio Flamingo+
- Emulator Androida z interfejsem API w wersji 21 lub nowszej.
- znajomość języka programowania Kotlin;
2. Pobieranie przykładowej aplikacji i konfigurowanie Firebase
Pobieranie kodu przykładowej aplikacji
Sklonuj repozytorium GitHub, używając wiersza poleceń:
git clone https://github.com/FirebaseExtended/make-it-so-android.git
Tworzenie projektu Firebase
Najpierw otwórz konsolę Firebase i utwórz projekt Firebase, klikając przycisk „+ Dodaj projekt”, jak pokazano poniżej:
Aby utworzyć projekt, wykonaj czynności wyświetlane na ekranie.
Dodaj aplikację na Androida do projektu Firebase
W projekcie Firebase możesz zarejestrować różne aplikacje: na Androida, iOS, przeglądarki internetowe, Flutter i Unity.
Wybierz opcję Androida:
Następnie wykonaj te czynności:
- Wpisz
com.example.makeitso
jako nazwę pakietu i opcjonalnie podaj własną nazwę. W tym ćwiczeniu nie musisz dodawać certyfikatu debugowania. - Kliknij Dalej, aby zarejestrować aplikację i uzyskać dostęp do pliku konfiguracyjnego Firebase.
- Kliknij Download google-services.json, aby pobrać plik konfiguracji i zapisać go w katalogu
make-it-so-android/app
. - Kliknij Dalej. Pakiety SDK Firebase są już uwzględnione w pliku
build.gradle
w próbnym projekcie, więc kliknij Dalej, aby przejść do sekcji Kolejne kroki. - Aby zakończyć, kliknij Przejdź do konsoli.
Aby aplikacja Zrób to tak prawidłowo działała, przed przejściem do kodu musisz wykonać w konsoli 2 rzeczy: włączyć dostawców uwierzytelniania i utworzyć bazę danych Firestore.
Konfigurowanie uwierzytelniania
Najpierw włączmy uwierzytelnianie, aby użytkownicy mogli logować się w aplikacji:
- W menu Tworzenie wybierz Uwierzytelnianie, a potem kliknij Rozpocznij.
- Na karcie Metoda logowania wybierz E-mail/hasło i włącz tę funkcję.
- Następnie kliknij Dodaj nowego dostawcę, wybierz i włącz opcję Anonimowy.
Konfigurowanie Cloud Firestore
Następnie skonfiguruj Firestore. W Firestore będziesz przechowywać zadania zalogowanego użytkownika. Każdy użytkownik otrzyma własny dokument w kolekcji w bazie danych.
- W panelu po lewej stronie konsoli Firebase rozwiń Build (Kompilacja), a potem wybierz Firestore database (Baza danych Firestore).
- Kliknij Utwórz bazę danych.
- W polu Identyfikator bazy danych pozostaw wartość
(default)
. - Wybierz lokalizację bazy danych i kliknij Dalej.
W przypadku prawdziwej aplikacji musisz wybrać lokalizację znajdującą się w pobliżu użytkowników. - Kliknij Rozpocznij w trybie testowym. Zapoznaj się z oświadczeniem wyłączenia odpowiedzialności za reguły zabezpieczeń.
W kolejnych krokach tej sekcji dodasz reguły zabezpieczeń, aby chronić swoje dane. Nie udostępniaj ani nie udostępniaj publicznie aplikacji bez dodania reguł bezpieczeństwa dla bazy danych. - Kliknij Utwórz.
Poświęć chwilę na skonfigurowanie niezawodnych reguł zabezpieczeń w bazie danych Firestore.
- Otwórz panel Firestore i przejdź na kartę Reguły.
- Zaktualizuj reguły zabezpieczeń tak:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow create: if request.auth != null;
allow read, update, delete: if request.auth != null && resource.data.userId == request.auth.uid;
}
}
}
Te reguły mówią, że każdy zalogowany użytkownik aplikacji może utworzyć dokument dla siebie w dowolnej kolekcji. Następnie po utworzeniu dokumentu tylko użytkownik, który go utworzył, będzie mógł go wyświetlić, zaktualizować lub usunąć.
Uruchamianie aplikacji
Teraz możesz uruchomić aplikację. Otwórz folder make-it-so-android/start
w Android Studio i uruchom aplikację (możesz to zrobić w emulatorze Androida lub na prawdziwym urządzeniu z Androidem).
3. Uwierzytelnianie Firebase
Jaką funkcję chcesz dodać?
W bieżącej wersji przykładowej aplikacji Make It So użytkownik może zacząć z niej korzystać bez konieczności logowania się. Do tego celu wykorzystuje anonimowe uwierzytelnianie. Jednak konta anonimowe nie umożliwiają użytkownikom dostępu do ich danych na innych urządzeniach ani nawet w przyszłych sesjach. Chociaż anonimowe uwierzytelnianie jest przydatne podczas wprowadzania użytkowników, zawsze należy dać im możliwość przejścia na inną formę logowania. Mając to na uwadze, w ramach tego ćwiczenia w Codelabs dowiesz się, jak dodać uwierzytelnianie przy użyciu adresu e-mail i hasła do aplikacji Make It So.
Czas na kodowanie
Gdy użytkownik utworzy konto, wpisując adres e-mail i hasło, musisz poprosić interfejs Firebase Authentication API o dane logowania e-mail, a potem połączyć nowe dane z kontem anonimowym. Otwórz plik AccountServiceImpl.kt
w Android Studio i zaktualizuj funkcję linkAccount
, aby wyglądała tak:
model/service/impl/AccountServiceImpl.kt
override suspend fun linkAccount(email: String, password: String) {
val credential = EmailAuthProvider.getCredential(email, password)
auth.currentUser!!.linkWithCredential(credential).await()
}
Teraz otwórz plik SignUpViewModel.kt
i w bloku launchCatching
funkcji onSignUpClick
wywołaj funkcję usługi linkAccount
:
screens/sign_up/SignUpViewModel.kt
launchCatching {
accountService.linkAccount(email, password)
openAndPopUp(SETTINGS_SCREEN, SIGN_UP_SCREEN)
}
Najpierw próbuje się uwierzytelnić, a jeśli się uda, przechodzi do następnego ekranu (SettingsScreen
). Ponieważ te wywołania są wykonywane w bloku launchCatching
, jeśli na pierwszym wierszu wystąpi błąd, wyjątek zostanie przechwycony i potraktowany, a drugi wiersz nie zostanie w ogóle wywołany.
Gdy tylko SettingsScreen
zostanie ponownie otwarte, musisz się upewnić, że opcje Zaloguj się i Utwórz konto zniknęły, ponieważ użytkownik jest już uwierzytelniony. Aby to zrobić, SettingsViewModel
nasłuchuje informacji o stanie bieżącego użytkownika (dostępny w wersji AccountService.kt
) i sprawdzamy, czy konto jest anonimowe. Aby to zrobić, zaktualizuj wartość uiState
w pliku SettingsViewModel.kt
, tak aby wyglądał tak:
screen/settings/SettingsViewModel.kt
val uiState = accountService.currentUser.map {
SettingsUiState(it.isAnonymous)
}
Ostatnia rzecz, jaką musisz zrobić, to zaktualizować pole uiState
w narzędziu SettingsScreen.kt
, tak aby zbierały stany wysyłane przez SettingsViewModel
:
screen/settings/SettingsScreen.kt
val uiState by viewModel.uiState.collectAsState(
initial = SettingsUiState(false)
)
Teraz za każdym razem, gdy użytkownik się zmienia, SettingsScreen
będzie się ponownie składać, aby wyświetlać opcje zgodnie z nowym stanem uwierzytelniania użytkownika.
Czas na testy
Uruchom polecenie Zrób to tak i przejdź do ustawień, klikając ikonę koła zębatego w prawym górnym rogu ekranu. Następnie kliknij opcję utworzenia konta:
Aby utworzyć konto, wpisz prawidłowy adres e-mail i silne hasło. Powinno zadziałać. Powinno nastąpić przekierowanie na stronę ustawień, gdzie zobaczysz 2 nowe opcje: wylogowanie się i usunięcie konta. Możesz sprawdzić nowe konto utworzone w panelu uwierzytelniania w konsoli Firebase, klikając kartę Użytkownicy.
4. Cloud Firestore
Jaką funkcję chcesz dodać?
W przypadku Cloud Firestore dodasz do kolekcji Firestore listenera, który przechowuje dokumenty odpowiadające zadaniom wyświetlanym w sekcji Zrób to. Po dodaniu tego listenera będziesz otrzymywać wszystkie aktualizacje tej kolekcji.
Czas na kodowanie
Zmień Flow
dostępny w StorageServiceImpl.kt
na taki:
model/service/impl/StorageServiceImpl.kt
override val tasks: Flow<List<Task>>
get() =
auth.currentUser.flatMapLatest { user ->
firestore.collection(TASK_COLLECTION).whereEqualTo(USER_ID_FIELD, user.id).dataObjects()
}
Ten kod dodaje detektor do kolekcji zadań opartej na: user.id
. Każde zadanie jest reprezentowane przez dokument w kolekcji o nazwie tasks
, a każdy z nich ma pole o nazwie userId
. Pamiętaj, że jeśli stan currentUser
się zmieni (np. przez wylogowanie się), zostanie wysłany nowy Flow
.
Teraz musisz skonfigurować pole Flow
w usłudze TasksViewModel.kt
tak, aby było takie samo jak w usłudze:
screen/tasks/TasksViewModel.kt
val tasks = storageService.tasks
Ostatnią rzeczą będzie composable function
w TasksScreens.kt
, która reprezentuje interfejs użytkownika, aby była świadoma tego przepływu i zbierała go jako stan. Za każdym razem, gdy stan się zmieni, funkcja składana automatycznie się przekształci i wyświetli użytkownikowi najnowszy stan. Dodaj te informacje do TasksScreen composable function
:
screens/tasks/TasksScreen.kt
val tasks = viewModel
.tasks
.collectAsStateWithLifecycle(emptyList())
Gdy funkcja kompozycyjna ma dostęp do tych stanów, możesz zaktualizować obiekt LazyColumn
(czyli strukturę, której używasz do wyświetlania listy na ekranie), tak aby wyglądał on tak:
screen/tasks/TasksScreen.kt
LazyColumn {
items(tasks.value, key = { it.id }) { taskItem ->
TaskItem( [...] )
}
}
Czas na testowanie
Aby sprawdzić, czy wszystko zadziałało, dodaj nowe zadanie w aplikacji (kliknij przycisk dodawania w prawym dolnym rogu ekranu). Gdy utworzysz zadanie, powinno się ono pojawić w kolekcji Firestore w konsoli Firestore. Jeśli zalogujesz się w Make it So na innych urządzeniach za pomocą tego samego konta, będziesz mieć możliwość edytowania swoich zadań i obserwowania ich aktualizacji na wszystkich urządzeniach w czasie rzeczywistym.
5. Monitorowanie wydajności
Którą funkcję chcesz dodać?
Wydajność jest bardzo ważna, ponieważ użytkownicy w niewielkim stopniu przestaną z niej korzystać, jeśli jej wydajność będzie niska i będą poświęcać na to zbyt dużo czasu. Dlatego czasami warto zbierać dane o konkretnej ścieżce użytkownika w aplikacji. Aby Ci to ułatwić, Firebase Performance Monitoring udostępnia śledzenia niestandardowe. Wykonaj kolejne czynności, aby dodać niestandardowe logi czasu i zmierzyć wydajność w różnych fragmentach kodu na stronie Make it Tak.
Czas na kodowanie!
Jeśli otworzysz plik Performance.kt
, zobaczysz funkcję wbudowaną o nazwie trace. Ta funkcja wywołuje interfejs Performance Monitoring API, aby utworzyć niestandardowy log czasu, przekazując jego nazwę jako parametr. Kolejnym parametrem jest blok kodu, który chcesz monitorować. Domyślne dane zbierane w przypadku każdego śladu to czas jego pełnego wykonania:
model/service/Performance.kt
inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)
Możesz wybrać części bazy kodu, które Twoim zdaniem powinny być objęte pomiarem, i dodać do niej niestandardowe logi czasu. Oto przykład dodawania niestandardowego logu czasu do funkcji linkAccount
, która została wyświetlona wcześniej (w AccountServiceImpl.kt
) w ramach tego ćwiczenia w Codelabs:
model/service/impl/AccountServiceImpl.kt
override suspend fun linkAccount(email: String, password: String): Unit =
trace(LINK_ACCOUNT_TRACE) {
val credential = EmailAuthProvider.getCredential(email, password)
auth.currentUser!!.linkWithCredential(credential).await()
}
Teraz Twoja kolej. Dodaj niestandardowe logi czasu do aplikacji Zrób to tak i przejdź do następnej sekcji, aby sprawdzić, czy wszystko zadziałało zgodnie z oczekiwaniami.
Czas na testy
Po dodaniu niestandardowych śladów uruchom aplikację i kilka razy użyj funkcji, które chcesz mierzyć. Następnie otwórz konsolę Firebase i kliknij Panel wydajności. U dołu ekranu znajdują się 3 karty: Żądania sieciowe, Ścieżki niestandardowe i Wyświetlanie ekranu.
Otwórz kartę Logi niestandardowe i sprawdź, czy wyświetlają się na niej ścieżki dodane w bazie kodu, oraz czy widzisz, ile czasu zwykle zajmuje wykonanie tych fragmentów kodu.
6. Zdalna konfiguracja
Którą funkcję chcesz dodać?
Zdalną konfigurację można stosować na wiele sposobów, od zdalnej zmiany wyglądu aplikacji po konfigurowanie różnych zachowań dla różnych segmentów użytkowników. W ramach tego ćwiczenia w programowaniu użyjesz Zdalnej konfiguracji do utworzenia przełącznika funkcji, który będzie pokazywać lub ukrywać nową funkcję edycji zadania w aplikacji Zmień konfigurację.
Czas na kodowanie
Najpierw musisz utworzyć konfigurację w konsoli Firebase. Aby to zrobić, przejdź do panelu Zdalnej konfiguracji i kliknij przycisk Dodaj parametr. Wypełnij pola zgodnie z podanym niżej obrazem:
Po wypełnieniu wszystkich pól możesz kliknąć przycisk Zapisz, a następnie Opublikuj. Parametr został już utworzony i jest dostępny w Twojej bazie kodu, więc musisz dodać do aplikacji kod, który pobiera nowe wartości. Otwórz plik ConfigurationServiceImpl.kt
i zaktualizuj implementację tych 2 funkcji:
model/service/impl/ConfigurationServiceImpl.kt
override suspend fun fetchConfiguration(): Boolean {
return remoteConfig.fetchAndActivate().await()
}
override val isShowTaskEditButtonConfig: Boolean
get() = remoteConfig[SHOW_TASK_EDIT_BUTTON_KEY].asBoolean()
Pierwsza funkcja pobiera wartości z serwera i jest wywoływana zaraz po uruchomieniu aplikacji (SplashViewModel.kt
). To najlepszy sposób na zapewnienie, że na wszystkich ekranach od razu będą dostępne najbardziej aktualne wartości. Zmiana interfejsu lub działania aplikacji później, gdy użytkownik jest w trakcie wykonywania jakiejś czynności, może być dla użytkownika nieprzyjemna.
Druga funkcja zwraca wartość logiczną, która została opublikowana dla parametru utworzonego właśnie w Konsoli. Te informacje trzeba będzie pobrać w narzędziu TasksViewModel.kt
, dodając do funkcji loadTaskOptions
ten kod:
screens/tasks/TasksViewModel.kt
fun loadTaskOptions() {
val hasEditOption = configurationService.isShowTaskEditButtonConfig
options.value = TaskActionOption.getOptions(hasEditOption)
}
W pierwszym wierszu pobierasz wartość, a potem używasz jej do wczytania opcji menu dla elementów zadania w drugim wierszu. Jeśli wartość to false
, menu nie będzie zawierać opcji edycji. Masz już listę opcji. Teraz musisz zadbać o to, aby interfejs wyświetlał się poprawnie. Gdy tworzysz aplikację za pomocą Jetpack Compose, poszukaj elementu composable function
, który deklaruje, jak powinien wyglądać interfejs użytkownika TasksScreen
. Otwórz plik TasksScreen.kt
i zaktualizuj element LazyColum
, aby wskazywał opcje dostępne w usłudze TasksViewModel.kt
:
screens/tasks/TasksScreen.kt
val options by viewModel.options
LazyColumn {
items(tasks.value, key = { it.id }) { taskItem ->
TaskItem(
options = options,
[...]
)
}
}
TaskItem
to kolejny composable function
, który deklaruje, jak powinien wyglądać interfejs użytkownika danego zadania. Każde zadanie ma też menu z opcjami, które wyświetla się, gdy użytkownik kliknie ikonę z 3 kropkami na końcu zadania.
Czas na testy
Teraz możesz uruchomić aplikację. Sprawdź, czy wartość opublikowana za pomocą konsoli Firebase odpowiada działaniu aplikacji:
- Jeśli to
false
, po kliknięciu ikony z 3 kropkami zobaczysz tylko 2 opcje. - Jeśli jest to
true
, po kliknięciu ikony z 3 kropkami zobaczysz 3 opcje:
Spróbuj kilka razy zmienić tę wartość w Konsoli i ponownie uruchom aplikację. Tak łatwo możesz uruchamiać nowe funkcje w aplikacji dzięki Zdalnej konfiguracji.
7. Gratulacje
Gratulacje! Udało Ci się utworzyć aplikację na Androida za pomocą Firebase i Jetpack Compose.
Dodałeś/dodałaś do aplikacji na Androida, która została w pełni utworzona za pomocą Jetpack Compose na potrzeby interfejsu użytkownika, uwierzytelnianie Firebase, monitorowanie wydajności, zdalne konfigurowanie i Cloud Firestore, a następnie dopasowałeś/dopasowałaś je do zalecanej architektury MVVM.
Więcej informacji
- Tworzenie aplikacji na Androida za pomocą Firebase i Compose
- Dodawanie uwierzytelniania Firebase do aplikacji Jetpack Compose
- Dodawanie Cloud Firestore do aplikacji Jetpack Compose
- Dodawanie Coroutines i Flow do aplikacji na Androida utworzonej za pomocą Firebase i Compose
- Dodawanie Monitorowania wydajności Firebase do aplikacji Jetpack Compose
- Dodawanie Zdalnej konfiguracji Firebase do aplikacji Jetpack Compose