Tworzenie aplikacji na Androida przy użyciu Firebase i Jetpack Compose

1. Wprowadzenie

Ostatnia aktualizacja: 16 listopada 2022 r.

Tworzenie aplikacji na Androida za pomocą Firebase i Jetpack Compose

W tym ćwiczeniu z programowania utworzysz aplikację na Androida o nazwie Make It So. Interfejs tej aplikacji jest w pełni utworzony za pomocą Jetpack Compose, czyli nowoczesnego pakietu narzędzi Androida do tworzenia natywnego interfejsu użytkownika .Jest on intuicyjny i wymaga mniej kodu niż pisanie plików XML i wiązanie ich z działaniami, fragmentami lub widokami.

Aby zrozumieć, jak dobrze Firebase i Jetpack Compose współpracują ze sobą, musisz najpierw poznać nowoczesną architekturę Androida. Dzięki dobrej architekturze system jest łatwy do zrozumienia, rozwijania i utrzymywania, ponieważ bardzo wyraźnie widać, jak komponenty są zorganizowane i jak komunikują się ze sobą. W świecie Androida zalecana architektura nosi nazwę Model – View – ViewModel. Model reprezentuje warstwę, która uzyskuje dostęp do danych w aplikacji. Widok to warstwa interfejsu użytkownika, która nie powinna znać logiki biznesowej. ViewModel to miejsce, w którym stosowana jest logika biznesowa, co czasami wymaga wywołania warstwy Model.

Zalecamy przeczytanie tego artykułu, aby zrozumieć, jak architektura Model – View – ViewModel jest stosowana w aplikacji na Androida utworzonej za pomocą Jetpack Compose. Ułatwi to zrozumienie kodu źródłowego i ułatwi 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. Na obrazkach poniżej widać 2 główne strony tej aplikacji: stronę tworzenia zadań i główną stronę z listą utworzonych zadań.

Ekran Dodawanie zadania w aplikacji Make it So Ekran Make it So Home

Dodasz niektóre funkcje, których brakuje 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 określonego 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
  • Jak dostosować interfejsy API Firebase do architektury MVVM
  • Odzwierciedlanie zmian wprowadzonych za pomocą interfejsów API Firebase w interfejsie Compose

Czego potrzebujesz

2. Pobieranie przykładowej aplikacji i konfigurowanie Firebase

Pobieranie kodu przykładowej aplikacji

Sklonuj repozytorium GitHub z poziomu 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:

Konsola Firebase

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, internet, Flutter i Unity.

Wybierz opcję Androida:

Omówienie projektu Firebase

Następnie wykonaj te czynności:

  1. Jako nazwę pakietu wpisz com.example.makeitso, a opcjonalnie pseudonim. W tym ćwiczeniu nie musisz dodawać certyfikatu debugowania.
  2. Kliknij Dalej, aby zarejestrować aplikację i uzyskać dostęp do pliku konfiguracyjnego Firebase.
  3. Kliknij Pobierz plik google-services.json, aby pobrać plik konfiguracji i zapisać go w katalogu make-it-so-android/app.
  4. 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.
  5. Aby zakończyć, kliknij Przejdź do konsoli.

Aby aplikacja Make it So działała prawidłowo, przed rozpoczęciem pracy nad kodem musisz wykonać 2 działania w konsoli: włączyć dostawców uwierzytelniania i utworzyć bazę danych Firestore.

Konfigurowanie uwierzytelniania

Najpierw włącz uwierzytelnianie, aby użytkownicy mogli logować się w aplikacji:

  1. W menu Tworzenie wybierz Uwierzytelnianie, a potem kliknij Rozpocznij.
  2. Na karcie Metoda logowania wybierz E-mail/hasło i włącz tę opcję.
  3. Następnie kliknij Dodaj nowego dostawcę, wybierz i włącz opcję Anonimowy.

Konfigurowanie Cloud Firestore

Następnie skonfiguruj Firestore. Do przechowywania zadań zalogowanego użytkownika użyjesz Firestore. Każdy użytkownik otrzyma własny dokumentkolekcji bazy danych.

  1. W panelu po lewej stronie w konsoli Firebase rozwiń Kompilacja, a potem wybierz Baza danych Firestore.
  2. Kliknij Utwórz bazę danych.
  3. Pozostaw wartość (default) w polu Identyfikator bazy danych.
  4. Wybierz lokalizację bazy danych, a potem kliknij Dalej.
    W przypadku prawdziwej aplikacji wybierz lokalizację blisko użytkowników.
  5. 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.
  6. Kliknij Utwórz.

Poświęć chwilę na skonfigurowanie niezawodnych reguł zabezpieczeń w bazie danych Firestore.

  1. Otwórz panel Firestore i otwórz kartę Reguły.
  2. Zaktualizuj reguły zabezpieczeń, aby wyglądały 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, tylko użytkownik, który utworzył dokument, będzie mógł go wyświetlić, zaktualizować lub usunąć.

Uruchom aplikację

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 używa uwierzytelniania anonimowego. Jednak konta anonimowe nie umożliwiają użytkownikowi dostępu do danych na innych urządzeniach ani 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. W tym celu w tym CodeLab dodasz uwierzytelnianie za pomocą 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 wewnątrz 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ęUtwórz konto zniknęły, ponieważ użytkownik jest już uwierzytelniony. Aby to zrobić, skonfigurujmy SettingsViewModel tak, aby słuchał stanu bieżącego użytkownika (dostępnego w AccountService.kt), aby sprawdzić, czy konto jest anonimowe. Aby to zrobić, zaktualizuj wartość uiState w pliku SettingsViewModel.kt, aby wyglądała tak:

screens/settings/SettingsViewModel.kt

val uiState = accountService.currentUser.map {
    SettingsUiState(it.isAnonymous)
}

Ostatnią rzeczą, którą musisz zrobić, jest zaktualizowanie uiStateSettingsScreen.kt, aby zbierać stany emitowane przez SettingsViewModel:

screens/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 testowanie

Uruchom Zrób to i otwórz ustawienia, klikając ikonę koła zębatego w prawym górnym rogu ekranu. Następnie kliknij opcję utworzenia konta:

Ekran ustawień Make it So Ekran rejestracji w aplikacji So

Aby utworzyć konto, wpisz prawidłowy adres e-mail i silne hasło. Powinno to zadziałać. Powinieneś zostać przekierowany na stronę ustawień, na której zobaczysz 2 nowe opcje: logowania się i usuwania 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 do kolekcji zadań słuchacza na podstawie elementu 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 zmieni się stan currentUser (np. po wylogowaniu), zostanie wyemitowany nowy obiekt Flow.

Teraz musisz ustawić FlowTasksViewModel.kt tak samo jak w usłudze:

screens/tasks/TasksViewModel.kt

val tasks = storageService.tasks

Ostatnią rzeczą będzie composable functionTasksScreens.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 to do TasksScreen composable function:

screens/tasks/TasksScreen.kt

val tasks = viewModel
    .tasks
    .collectAsStateWithLifecycle(emptyList())

Gdy funkcja składana ma dostęp do tych stanów, możesz zaktualizować LazyColumn (która jest strukturą używaną do wyświetlania listy na ekranie) tak, aby wyglądała tak:

screens/tasks/TasksScreen.kt

LazyColumn {
    items(tasks.value, key = { it.id }) { taskItem ->
        TaskItem( [...] )
    }
}

Czas na testowanie

Aby sprawdzić, czy wszystko działa prawidłowo, dodaj nowe zadanie w aplikacji (klikając przycisk dodawania w prawym dolnym rogu ekranu). Po zakończeniu tworzenia zadania powinno się ono pojawić w zbiorze 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

Jaką funkcję chcesz dodać?

Wydajność jest bardzo ważna, ponieważ użytkownicy prawdopodobnie zrezygnują z korzystania z aplikacji, jeśli jej działanie będzie niewystarczająco dobre i jeśli wykonanie prostego zadania będzie zajmować 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. Aby dodać logi niestandardowe i zmierzyć wydajność różnych fragmentów kodu w Make it So, wykonaj podane niżej czynności.

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 ślad, przekazując nazwę śladu jako parametr. Drugi parametr, który widzisz, to 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 kodu źródłowego, które Twoim zdaniem warto mierzyć, i dodać do nich niestandardowe śledzenia. Oto przykład dodawania niestandardowego śledzenia do funkcji linkAccount, którą widzisz wcześniej (w funkcji AccountServiceImpl.kt) w tym CodeLab:

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 do aplikacji Make it So kilka niestandardowych ścieżek i przejdź do następnej sekcji, aby sprawdzić, czy działają zgodnie z oczekiwaniami.

Czas na testowanie

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 znajdziesz 3 karty: Żądania sieciowe, Ścieżki niestandardoweWyś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

Jaką 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 tym ćwiczeniu na platformie Codelab użyjesz Zdalnej konfiguracji do utworzenia przełącznika, który będzie wyświetlać lub ukrywać nową funkcję edytowania zadania w aplikacji Make it So.

Czas na kodowanie!

Najpierw musisz utworzyć konfigurację w konsoli Firebase. Aby to zrobić, otwórz panel Zdalna konfiguracja i kliknij przycisk Dodaj parametr. Wypełnij pola zgodnie z podanym niżej obrazem:

Okno „Tworzenie parametru” w Zdalnej konfiguracji

Gdy wypełnisz wszystkie pola, możesz kliknąć kolejno przyciski ZapiszOpublikuj. 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, gdy tylko aplikacja się uruchomi, w funkcji SplashViewModel.kt. To najlepszy sposób na zapewnienie, że na wszystkich ekranach od razu będą dostępne najnowsze wartości. Zmiana interfejsu lub zachowania aplikacji w momencie, gdy użytkownik coś robi, nie jest dobrym rozwiązaniem.

Druga funkcja zwraca wartość logiczną opublikowaną dla parametru, który został utworzony w konsoli. Aby pobrać te informacje w funkcji TasksViewModel.kt, dodaj do funkcji loadTaskOptions te elementy:

screens/tasks/TasksViewModel.kt

fun loadTaskOptions() {
  val hasEditOption = configurationService.isShowTaskEditButtonConfig
  options.value = TaskActionOption.getOptions(hasEditOption)
}

Pobierasz wartość na pierwszym wierszu i używasz jej do wczytania opcji menu dla elementów zadania na drugim wierszu. Jeśli wartość to false, menu nie będzie zawierać opcji edycji. Teraz, gdy masz już listę opcji, musisz odpowiednio wyświetlić ją w interfejsie. Podczas tworzenia aplikacji za pomocą Jetpack Compose musisz znaleźć composable function, który określa, jak powinno wyglądać UI TasksScreen. Otwórz plik TasksScreen.kt i zaktualizuj element LazyColum, aby wskazywał opcje dostępne w pliku 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 określa, jak powinien wyglądać interfejs pojedynczego zadania. Każde zadanie ma menu z opcjami, które wyświetla się, gdy użytkownik kliknie ikonę z 3 kropkami na końcu zadania.

Czas na testowanie

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 powinny być widoczne tylko 2 opcje.
  • Jeśli to true, po kliknięciu ikony z 3 kropkami zobaczysz 3 opcje:

Spróbuj kilka razy zmienić wartość w Konsoli i ponownie uruchom aplikację. Tak łatwo można uruchamiać nowe funkcje w aplikacji za pomocą 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

Dokumenty referencyjne