Erstellen Sie eine Android-App mit Firebase und Jetpack Compose

1. Einleitung

Letzte Aktualisierung: 16.11.2022

Erstellen einer Android-App mit Firebase und Jetpack Compose

In diesem Codelab erstellen Sie eine Android-App namens Make It So . Die Benutzeroberfläche dieser App wurde vollständig mit Jetpack Compose erstellt, dem modernen Toolkit von Android zum Erstellen einer nativen Benutzeroberfläche. Es ist intuitiv und erfordert weniger Code als das Schreiben von XML-Dateien und deren Bindung an Aktivitäten, Fragmente oder Ansichten.

Der erste Schritt, um zu verstehen, wie gut Firebase und Jetpack Compose zusammenarbeiten, ist das Verständnis der modernen Android-Architektur. Eine gute Architektur macht das System leicht verständlich, leicht zu entwickeln und zu warten, da sie sehr deutlich macht, wie die Komponenten organisiert sind und miteinander kommunizieren. In der Android-Welt heißt die empfohlene Architektur Model – View – ViewModel . Das Modell stellt die Ebene dar, die auf Daten in der Anwendung zugreift. Die Ansicht ist die UI-Ebene und sollte nichts über die Geschäftslogik wissen. Und im ViewModel wird die Geschäftslogik angewendet, was manchmal erfordert, dass das ViewModel die Modellebene aufruft.

Wir empfehlen dringend, diesen Artikel zu lesen, um zu verstehen, wie „Model – View – ViewModel“ auf eine mit Jetpack Compose erstellte Android-App angewendet wird, da dadurch die Codebasis leichter zu verstehen und die nächsten Schritte einfacher durchzuführen sind.

Was Sie bauen werden

Make It So ist eine einfache Aufgabenlistenanwendung, mit der der Benutzer Aufgaben hinzufügen und bearbeiten, Markierungen, Prioritäten und Fälligkeitstermine hinzufügen und die Aufgaben als erledigt markieren kann. Die Bilder unten zeigen die beiden Hauptseiten dieser Anwendung: die Seite zur Aufgabenerstellung und die Hauptseite mit der Liste der erstellten Aufgaben.

Machen Sie es so, Bildschirm „Aufgabe hinzufügen“.Make it So-Startbildschirm

Sie werden einige Funktionen hinzufügen, die in dieser App fehlen:

  • Authentifizieren Sie Benutzer mit E-Mail und Passwort
  • Fügen Sie einer Firestore-Sammlung einen Listener hinzu und sorgen Sie dafür, dass die Benutzeroberfläche auf Änderungen reagiert
  • Fügen Sie benutzerdefinierte Traces hinzu, um die Leistung von bestimmtem Code in der App zu überwachen
  • Erstellen Sie mit Remote Config einen Funktionsumschalter und starten Sie ihn über den gestaffelten Rollout

Was Sie lernen werden

  • So verwenden Sie Firebase-Authentifizierung, Leistungsüberwachung, Remote-Konfiguration und Cloud Firestore in einer modernen Android-Anwendung
  • So passen Firebase-APIs in eine MVVM-Architektur
  • So spiegeln Sie mit Firebase-APIs vorgenommene Änderungen in einer Compose-Benutzeroberfläche wider

Was du brauchen wirst

2. Holen Sie sich die Beispiel-App und richten Sie Firebase ein

Holen Sie sich den Code der Beispiel-App

Klonen Sie das GitHub-Repository über die Befehlszeile:

git clone https://github.com/FirebaseExtended/make-it-so-android.git

Richten Sie Firebase ein

Als Erstes müssen Sie zur Firebase-Konsole gehen und ein Firebase-Projekt erstellen, indem Sie auf die Schaltfläche „+ Projekt hinzufügen“ klicken, wie Sie unten sehen können:

Firebase-Konsole

Befolgen Sie die Schritte auf dem Bildschirm, um die Projekterstellung abzuschließen.

Innerhalb jedes Firebase-Projekts können Sie verschiedene Apps erstellen: für Android, iOS, Web, Flutter und Unity. Wählen Sie die Android-Option, wie Sie hier sehen:

Übersicht über das Firebase-Projekt

Befolgen Sie dann diese Schritte:

  1. Geben Sie com.example.makeitso als Paketnamen ein und geben Sie optional einen Spitznamen ein. Für dieses Codelab müssen Sie das Debug-Signaturzertifikat nicht hinzufügen.
  2. Klicken Sie auf „Weiter“ , um Ihre App zu registrieren und auf die Firebase-Konfigurationsdatei zuzugreifen.
  3. Klicken Sie auf „Google-services.json herunterladen“ , um Ihre Konfigurationsdatei herunterzuladen und im Verzeichnis make-it-so-android/app zu speichern.
  4. Weiter klicken . Da die Firebase SDKs bereits in der Datei build.gradle im Beispielprojekt enthalten sind, klicken Sie auf Weiter , um mit den nächsten Schritten fortzufahren.
  5. Klicken Sie zum Abschluss auf Weiter zur Konsole .

Damit die Make it So- App ordnungsgemäß funktioniert, müssen Sie in der Konsole zwei Dinge tun, bevor Sie zum Code springen: Authentifizierungsanbieter aktivieren und die Firestore-Datenbank erstellen. Aktivieren wir zunächst die Authentifizierung, damit sich Benutzer bei der App anmelden können:

  1. Wählen Sie im Menü „Erstellen“ die Option „Authentifizierung“ aus und klicken Sie dann auf „Erste Schritte“ .
  2. Wählen Sie auf der Karte „Anmeldemethode“ die Option E-Mail/Passwort aus und aktivieren Sie sie.
  3. Klicken Sie anschließend auf „Neuen Anbieter hinzufügen“ und wählen und aktivieren Sie „Anonymous“ .

Als nächstes richten Sie Firestore ein. Sie verwenden Firestore, um die Aufgaben eines angemeldeten Benutzers zu speichern. Jeder Benutzer erhält sein eigenes Dokument in einer Sammlung der Datenbank.

  1. Wählen Sie im Menü „Erstellen“ die Option „Firestore“ aus und klicken Sie dann auf „Datenbank erstellen“ .
  2. Lassen Sie Start im Produktionsmodus aktiviert und klicken Sie auf Weiter .
  3. Wenn Sie dazu aufgefordert werden, wählen Sie den Speicherort aus, an dem Ihre Cloud Firestore-Daten gespeichert werden. Wenn Sie eine Produktions-App entwickeln, möchten Sie, dass diese sich in einer Region befindet, die der Mehrheit Ihrer Benutzer nahe kommt und mit anderen Firebase-Diensten wie Funktionen gemeinsam ist. Für dieses Codelab können Sie die Standardregion beibehalten oder die Region auswählen, die Ihnen am nächsten liegt.
  4. Klicken Sie auf „Aktivieren“ , um Ihre Firestore-Datenbank bereitzustellen.

Nehmen wir uns einen Moment Zeit, um robuste Sicherheitsregeln für die Firestore-Datenbank zu erstellen. Öffnen Sie das Firestore-Dashboard und gehen Sie zur Registerkarte „Regeln“ . Aktualisieren Sie dann die Sicherheitsregeln so, dass sie wie folgt aussehen:

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;
    }
  }
}

Diese Regeln besagen im Wesentlichen, dass jeder angemeldete Benutzer der App innerhalb jeder Sammlung ein Dokument für sich selbst erstellen kann. Nach der Erstellung kann dann nur der Benutzer, der das Dokument erstellt hat, dieses Dokument anzeigen, aktualisieren oder löschen.

Führen Sie die Anwendung aus

Jetzt können Sie die Anwendung ausführen! Öffnen Sie den Ordner make-it-so-android/start in Android Studio und führen Sie die App aus (dies kann mit einem Android-Emulator oder einem echten Android-Gerät erfolgen).

3. Firebase-Authentifizierung

Welche Funktion werden Sie hinzufügen?

Im aktuellen Status der Make It So- Beispiel-App kann ein Benutzer mit der Nutzung der App beginnen, ohne sich zuerst anmelden zu müssen. Um dies zu erreichen, wird eine anonyme Authentifizierung verwendet. Allerdings ermöglichen anonyme Konten einem Benutzer keinen Zugriff auf seine Daten auf anderen Geräten oder sogar in zukünftigen Sitzungen. Obwohl die anonyme Authentifizierung für ein warmes Onboarding nützlich ist, sollten Sie Benutzern immer die Möglichkeit bieten, zu einer anderen Anmeldeform zu wechseln. Vor diesem Hintergrund fügen Sie in diesem Codelab der Make It So -App E-Mail- und Passwortauthentifizierung hinzu.

Zeit zum Codieren!

Sobald der Benutzer ein Konto erstellt, indem er eine E-Mail-Adresse und ein Passwort eingibt, müssen Sie die Firebase-Authentifizierungs-API nach E-Mail-Anmeldeinformationen fragen und dann die neuen Anmeldeinformationen mit dem anonymen Konto verknüpfen. Öffnen Sie die Datei AccountServiceImpl.kt in Android Studio und aktualisieren Sie die Funktion linkAccount , sodass sie wie folgt aussieht:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String) {
    val credential = EmailAuthProvider.getCredential(email, password)
    auth.currentUser!!.linkWithCredential(credential).await()
}

Öffnen Sie nun SignUpViewModel.kt und rufen Sie die Service- linkAccount -Funktion im launchCatching Block der onSignUpClick Funktion auf:

screens/sign_up/SignUpViewModel.kt

launchCatching {
    accountService.linkAccount(email, password)
    openAndPopUp(SETTINGS_SCREEN, SIGN_UP_SCREEN)
}

Zuerst wird versucht, sich zu authentifizieren. Wenn der Anruf erfolgreich ist, wird mit dem nächsten Bildschirm (dem SettingsScreen ) fortgefahren. Wenn Sie diese Aufrufe innerhalb eines launchCatching Blocks ausführen und in der ersten Zeile ein Fehler auftritt, wird die Ausnahme abgefangen und behandelt, und die zweite Zeile wird überhaupt nicht erreicht.

Sobald der SettingsScreen erneut geöffnet wird, müssen Sie sicherstellen, dass die Optionen „Anmelden “ und „Konto erstellen“ verschwunden sind, da der Benutzer nun bereits authentifiziert ist. Lassen Sie uns dazu festlegen, dass SettingsViewModel den Status des aktuellen Benutzers (verfügbar in AccountService.kt ) abhört, um zu überprüfen, ob das Konto anonym ist oder nicht. Aktualisieren Sie dazu den uiState in SettingsViewModel.kt so, dass er wie folgt aussieht:

screens/settings/SettingsViewModel.kt

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

Als letztes müssen Sie den uiState in SettingsScreen.kt aktualisieren, um die vom SettingsViewModel ausgegebenen Zustände zu sammeln:

screens/settings/SettingsScreen.kt

val uiState by viewModel.uiState.collectAsState(
    initial = SettingsUiState(false)
)

Jedes Mal, wenn sich der Benutzer ändert, stellt sich der SettingsScreen neu zusammen, um die Optionen entsprechend dem neuen Authentifizierungsstatus des Benutzers anzuzeigen.

Zeit zum Testen!

Führen Sie „Make it So“ aus und navigieren Sie zu den Einstellungen, indem Sie auf das Zahnradsymbol in der oberen rechten Ecke des Bildschirms klicken. Klicken Sie dort auf die Option „Konto erstellen“:

Make it So-EinstellungsbildschirmMake it So-Anmeldebildschirm

Geben Sie eine gültige E-Mail-Adresse und ein sicheres Passwort ein, um Ihr Konto zu erstellen. Es sollte funktionieren und Sie sollten zur Einstellungsseite weitergeleitet werden, wo Ihnen zwei neue Optionen angezeigt werden: Abmelden und Löschen Ihres Kontos. Sie können das neue Konto überprüfen, das im Authentifizierungs-Dashboard der Firebase-Konsole erstellt wurde, indem Sie auf die Registerkarte „Benutzer“ klicken.

4. Cloud Firestore

Welche Funktion werden Sie hinzufügen?

Für Cloud Firestore fügen Sie der Firestore-Sammlung einen Listener hinzu, der die Dokumente speichert, die die in Make it So angezeigten Aufgaben darstellen. Sobald Sie diesen Listener hinzufügen, erhalten Sie jedes an dieser Sammlung vorgenommene Update.

Zeit zum Codieren!

Aktualisieren Sie den in StorageServiceImpl.kt verfügbaren Flow so, dass er wie folgt aussieht:

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()
      }

Dieser Code fügt der Aufgabensammlung basierend auf user.id einen Listener hinzu. Jede Aufgabe wird durch ein Dokument in einer Sammlung mit dem Namen „ tasks dargestellt, und jede von ihnen verfügt über ein Feld mit dem Namen „ userId . Bitte beachten Sie, dass ein neuer Flow ausgegeben wird, wenn sich der Status des currentUser ändert (z. B. durch Abmelden).

Jetzt müssen Sie dafür sorgen, dass der Flow in TasksViewModel.kt dem im Dienst entspricht:

screens/tasks/TasksViewModel.kt

val tasks = storageService.tasks

Und als Letztes muss die composable function in TasksScreens.kt , die die Benutzeroberfläche darstellt, diesen Fluss erkennen und ihn als Status erfassen. Jedes Mal, wenn sich der Status ändert, stellt sich die zusammensetzbare Funktion automatisch neu zusammen und zeigt dem Benutzer den neuesten Status an. Fügen Sie dies zur TasksScreen composable function hinzu:

screens/tasks/TasksScreen.kt

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

Sobald die zusammensetzbare Funktion Zugriff auf diese Zustände hat, können Sie die LazyColumn (die Struktur, die Sie zum Anzeigen einer Liste auf dem Bildschirm verwenden) so aktualisieren, dass sie wie folgt aussieht:

screens/tasks/TasksScreen.kt

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

Zeit zum Testen!

Um zu testen, ob es funktioniert hat, fügen Sie über die App eine neue Aufgabe hinzu (indem Sie auf die Schaltfläche „Hinzufügen“ in der unteren rechten Ecke des Bildschirms klicken). Sobald Sie die Aufgabe erstellt haben, sollte sie in der Firestore-Sammlung in der Firestore-Konsole angezeigt werden. Wenn Sie sich auf anderen Geräten mit demselben Konto bei Make it So anmelden, können Sie Ihre Aufgaben bearbeiten und in Echtzeit zusehen, wie sie auf allen Geräten aktualisiert werden.

5. Leistungsüberwachung

Welche Funktion werden Sie hinzufügen?

Es ist sehr wichtig, auf die Leistung zu achten, da Benutzer die Verwendung Ihrer App sehr wahrscheinlich aufgeben, wenn die Leistung nicht gut ist und sie zu viel Zeit benötigen, um eine einfache Aufgabe damit zu erledigen. Aus diesem Grund ist es manchmal nützlich, einige Kennzahlen zu einer bestimmten Reise zu sammeln, die ein Benutzer in Ihrer App unternimmt. Und um Ihnen dabei zu helfen, bietet Firebase Performance Monitoring benutzerdefinierte Traces . Befolgen Sie die nächsten Schritte, um benutzerdefinierte Ablaufverfolgungen hinzuzufügen und die Leistung in verschiedenen Codeteilen in Make it So zu messen.

Zeit zum Codieren!

Wenn Sie die Datei Performance.kt öffnen, sehen Sie eine Inline-Funktion namens Trace. Diese Funktion ruft die Performance Monitoring API auf, um eine benutzerdefinierte Ablaufverfolgung zu erstellen, und übergibt dabei den Ablaufverfolgungsnamen als Parameter. Der andere Parameter, den Sie sehen, ist der Codeblock, den Sie überwachen möchten. Die für jede Ablaufverfolgung erfasste Standardmetrik ist die Zeit, die für die vollständige Ausführung benötigt wird:

model/service/Performance.kt

inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)

Sie können auswählen, welche Teile der Codebasis Ihrer Meinung nach für die Messung wichtig sind, und benutzerdefinierte Traces hinzufügen. Hier ist ein Beispiel für das Hinzufügen einer benutzerdefinierten Ablaufverfolgung zur Funktion linkAccount , die Sie zuvor (in AccountServiceImpl.kt ) in diesem Codelab gesehen haben:

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()
  }

Jetzt bist du dran! Fügen Sie der Make it So -App einige benutzerdefinierte Traces hinzu und fahren Sie mit dem nächsten Abschnitt fort, um zu testen, ob es wie erwartet funktioniert.

Zeit zum Testen!

Nachdem Sie die benutzerdefinierten Spuren hinzugefügt haben, führen Sie die App aus und stellen Sie sicher, dass Sie die Funktionen, die Sie messen möchten, einige Male verwenden. Gehen Sie dann zur Firebase-Konsole und gehen Sie zum Performance-Dashboard . Am unteren Bildschirmrand finden Sie drei Registerkarten: Netzwerkanfragen , benutzerdefinierte Ablaufverfolgungen und Bildschirmrendering .

Gehen Sie zur Registerkarte „Benutzerdefinierte Traces“ und überprüfen Sie, ob die Traces, die Sie in der Codebasis hinzugefügt haben, dort angezeigt werden und dass Sie sehen können, wie viel Zeit es normalerweise dauert, diese Codeteile auszuführen.

6. Remote-Konfiguration

Welche Funktion werden Sie hinzufügen?

Es gibt eine Vielzahl von Anwendungsfällen für Remote Config, von der Remote-Änderung des Erscheinungsbilds Ihrer App bis hin zur Konfiguration verschiedener Verhaltensweisen für verschiedene Benutzersegmente. In diesem Codelab verwenden Sie Remote Config, um einen Funktionsschalter zu erstellen, der die neue Funktion zum Bearbeiten von Aufgaben in der Make it So- App ein- oder ausblendet.

Zeit zum Codieren!

Als Erstes müssen Sie die Konfiguration in der Firebase-Konsole erstellen. Dazu müssen Sie zum Remote Config-Dashboard navigieren und auf die Schaltfläche Parameter hinzufügen klicken. Füllen Sie die Felder gemäß dem Bild unten aus:

Remote-Konfiguration: Dialogfeld „Parameter erstellen“.

Sobald alle Felder ausgefüllt sind, können Sie auf die Schaltfläche „Speichern “ und dann auf „Veröffentlichen“ klicken. Nachdem der Parameter nun erstellt wurde und für Ihre Codebasis verfügbar ist, müssen Sie den Code hinzufügen, der die neuen Werte in Ihre App abruft. Öffnen Sie die Datei ConfigurationServiceImpl.kt und aktualisieren Sie die Implementierung dieser beiden Funktionen:

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()

Die erste Funktion ruft die Werte vom Server ab und wird aufgerufen, sobald die App gestartet wird, in SplashViewModel.kt . Dies ist der beste Weg, um sicherzustellen, dass von Anfang an auf allen Bildschirmen die aktuellsten Werte verfügbar sind. Es ist keine gute Benutzererfahrung, wenn Sie die Benutzeroberfläche oder das Verhalten der App später ändern, während der Benutzer gerade etwas tut!

Die zweite Funktion gibt den booleschen Wert zurück, der für den Parameter veröffentlicht wurde, den Sie gerade in der Konsole erstellt haben. Und Sie müssen diese Informationen in TasksViewModel.kt abrufen, indem Sie Folgendes zur Funktion loadTaskOptions hinzufügen:

screens/tasks/TasksViewModel.kt

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

Sie rufen den Wert in der ersten Zeile ab und verwenden ihn, um die Menüoptionen für die Aufgabenelemente in der zweiten Zeile zu laden. Wenn der Wert false ist, bedeutet dies, dass das Menü die Bearbeitungsoption nicht enthält. Da Sie nun über die Liste der Optionen verfügen, müssen Sie dafür sorgen, dass sie in der Benutzeroberfläche korrekt angezeigt wird. Wenn Sie eine App mit Jetpack Compose erstellen, müssen Sie nach der composable function suchen, die angibt, wie die Benutzeroberfläche des TasksScreen aussehen soll. Öffnen Sie also die Datei TasksScreen.kt und aktualisieren Sie „ LazyColum , um auf die in TasksViewModel.kt verfügbaren Optionen zu verweisen:

screens/tasks/TasksScreen.kt

val options by viewModel.options

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

Das TaskItem ist eine weitere composable function , die deklariert, wie die Benutzeroberfläche einer einzelnen Aufgabe aussehen soll. Und jede Aufgabe verfügt über ein Menü mit Optionen, das angezeigt wird, wenn der Benutzer auf das Dreipunktsymbol am Ende klickt.

Zeit zum Testen!

Jetzt können Sie die App ausführen! Überprüfen Sie, ob der Wert, den Sie über die Firebase-Konsole veröffentlicht haben, mit dem Verhalten der App übereinstimmt:

  • Wenn es false ist, sollten Sie beim Klicken auf das Drei-Punkte-Symbol nur zwei Optionen sehen;
  • Wenn dies true , sollten Sie drei Optionen sehen, wenn Sie auf das Drei-Punkte-Symbol klicken.

Versuchen Sie, den Wert ein paar Mal in der Konsole zu ändern und die App neu zu starten. So einfach ist es, mit Remote Config neue Funktionen in Ihrer App zu starten!

7. Herzlichen Glückwunsch

Herzlichen Glückwunsch, Sie haben erfolgreich eine Android-App mit Firebase und Jetpack Compose erstellt!

Sie haben Firebase-Authentifizierung, Leistungsüberwachung, Remote-Konfiguration und Cloud Firestore zu einer Android-App hinzugefügt, die vollständig mit Jetpack Compose für die Benutzeroberfläche erstellt wurde, und Sie haben dafür gesorgt, dass sie in die empfohlene MVVM-Architektur passt!

Weiterführende Literatur

Referenzdokumente