Firebase iOS-Codelab: FriendlyChat

1. Übersicht

Willkommen zum Codelab FriendlyChat für iOS. In diesem Codelab erfahren Sie, wie Sie mit Firebase und modernen Swift-Funktionen wie SwiftUI, Swift Concurrency und dem Observation-Framework eine voll funktionsfähige iOS-App für Echtzeit-Chats erstellen.

Lerninhalte

  • Status mit dem modernen Observation-Framework (@Observable) verwalten.
  • Nutzer mit Firebase Authentication authentifizieren.
  • Chatnachrichten in Echtzeit mit Cloud Firestore synchronisieren.
  • Bilder mit Cloud Storage for Firebase speichern und bereitstellen.
  • Mit modernen Swift Concurrency -Funktionen auf Firebase APIs zugreifen.

Voraussetzungen

  • Die aktuelle Version von Xcode
  • Ein iOS-Simulator oder ein physisches Testgerät
  • Ein Google-Konto zum Erstellen und Verwalten Ihres Firebase-Projekts

2. Beispielcode abrufen

Klonen Sie das GitHub-Repository über die Befehlszeile:

$ git clone https://github.com/firebase/codelab-friendlychat-ios

Das Repository codelab-friendlychat-ios enthält mehrere Beispielprojekte:

  • ios-starter/swift-starter : Das Xcode-Startprojekt mit dem SwiftUI-Layoutgerüst und TODO-Kommentaren, in denen Sie App-Funktionen mit Firebase implementieren.
  • ios/swift : Das abgeschlossene Xcode-Projekt mit der fertigen Beispiel-App.

3. Start-App erstellen

Erstellen und führen Sie die Start-App aus, um sich mit der Benutzeroberfläche vertraut zu machen:

  1. Wechseln Sie im Finder oder Terminal zum Verzeichnis ios-starter/swift-starter.
  2. Doppelklicken Sie auf FriendlyChatSwift.xcodeproj , um das Projekt in Xcode zu öffnen.
  3. Xcode löst Swift Package Manager-Abhängigkeiten automatisch im Hintergrund auf (Herunterladen von firebase-ios-sdk Version 12 oder höher von GitHub).
  4. Wählen Sie einen iOS-Simulator aus (z. B. iPhone 17 Pro) und klicken Sie auf die Schaltfläche Ausführen (cmd + R).

Nach einigen Sekunden wird der Anmeldebildschirm von FriendlyChat angezeigt. An dieser Stelle sind die Anmeldeschaltflächen und Nachrichtenfeeds Platzhalter. In den folgenden Schritten verbinden Sie Firebase mit der App.

4. Firebase-Projekt einrichten

Neues Firebase-Projekt erstellen

  1. Melden Sie sich in der Firebase Console mit Ihrem Google-Konto an.
  2. Klicken Sie auf die Schaltfläche, um ein neues Projekt zu erstellen, und geben Sie dann einen Projektnamen ein (z. B. FriendlyChat).
  3. Klicken Sie auf Weiter.
  4. Überprüfen und akzeptieren Sie gegebenenfalls die Firebase-Nutzungsbedingungen und klicken Sie dann auf Weiter.
  5. (Optional) Aktivieren Sie die KI-Unterstützung in der Firebase Console (Gemini in Firebase genannt).
  6. Für dieses Codelab benötigen Sie kein Google Analytics. Deaktivieren Sie daher die Google Analytics-Option.
  7. Klicken Sie auf Projekt erstellen, warten Sie, bis Ihr Projekt bereitgestellt wurde, und klicken Sie dann auf Weiter.

Firebase-Preismodell aktualisieren

Wenn Sie Cloud Storage for Firebase verwenden möchten, muss Ihr Firebase-Projekt auf den Blaze-Tarif (Pay as you go) umgestellt sein. Das bedeutet, dass es mit einem Cloud-Rechnungskonto verknüpft ist.

So aktualisieren Sie Ihr Projekt auf den Blaze-Tarif:

  1. Wählen Sie in der Firebase Console aus, um Ihren Tarif zu aktualisieren.
  2. Wählen Sie den Blaze-Tarif aus. Folgen Sie der Anleitung auf dem Bildschirm, um ein Cloud-Rechnungskonto mit Ihrem Projekt zu verknüpfen.
    Wenn Sie im Rahmen dieses Upgrades ein Cloud-Rechnungskonto erstellen mussten, müssen Sie möglicherweise zum Upgrade-Ablauf in der Firebase Console zurückkehren, um das Upgrade abzuschließen.

iOS-App verbinden

  1. Klicken Sie auf dem Bildschirm „Projektübersicht“ auf das Symbol iOS, um den Workflow für die App-Einrichtung zu starten.
  2. Geben Sie die Paket-ID ein:
    com.google.firebase.codelab.FriendlyChatSwift
    
  3. Klicken Sie auf App registrieren.

GoogleService-Info.plist zum Xcode-Projekt hinzufügen

  1. Klicken Sie auf GoogleService-Info.plist herunterladen , um die Konfigurationsdatei zu speichern.
  2. Ziehen Sie in Xcode die heruntergeladene Datei GoogleService-Info.plist in der Projektnavigation in die Hauptgruppe FriendlyChatSwift.
  3. Prüfen Sie, ob Elemente bei Bedarf kopieren ausgewählt ist und das Ziel FriendlyChatSwift ausgewählt ist, und klicken Sie dann auf Fertig.

Firebase in FriendlyChatSwiftApp.swift konfigurieren

Initialisieren Sie Firebase schließlich mit Ihrer Projektkonfiguration, wenn Ihre SwiftUI-App gestartet wird. Öffnen Sie FriendlyChatSwiftApp.swift und ersetzen Sie die TODO-Platzhalter durch import FirebaseCore und FirebaseApp.configure():

import SwiftUI
import FirebaseCore

@main
struct FriendlyChatSwiftApp: App {
  init() {
    FirebaseApp.configure()
  }

  var body: some Scene {
    WindowGroup {
      ContentView()
    }
  }
}

5. Nutzer authentifizieren

Authentifizierung in der Firebase Console konfigurieren

Bevor Sie Nutzer authentifizieren können, müssen Sie zuerst den gewünschten Authentifizierungsanbieter in der Firebase Console aktivieren. In dieser Anleitung wird die Authentifizierung per E‑Mail/Passwort verwendet:

  1. Wechseln Sie in der Firebase Console zu Sicherheit > Authentifizierung und klicken Sie dann auf Jetzt starten.
  2. Wählen Sie den Tab Anmeldemethode aus.
  3. Klicken Sie auf E‑Mail/Passwort, aktivieren Sie den Schalter Aktivieren und klicken Sie auf Speichern.

Cloud Firestore mit Authentifizierungsregeln schützen

Als Nächstes müssen sich Nutzer authentifizieren, bevor sie Nachrichten lesen oder schreiben können:

  1. Wechseln Sie in der Firebase Console zu Datenbanken und Speicher > Firestore-Datenbank und klicken Sie dann auf Datenbank erstellen.
  2. Wählen Sie einen Standort aus und klicken Sie auf Weiter.
  3. Wählen Sie Im Testmodus starten aus und klicken Sie auf Erstellen.
  4. Wählen Sie den Tab Regeln aus und aktualisieren Sie die Sicherheitsregeln auf:
    rules_version = '2';
    
    service cloud.firestore {
      match /databases/{database}/documents {
        match /messages/{messageId} {
          allow read, write: if request.auth != null;
        }
      }
    }
    
    Mit diesen Regeln kann jeder authentifizierte Nutzer Nachrichten in der Datenbank lesen oder schreiben. Das ist für Lernzwecke geeignet. Weitere Informationen zu Sicherheitsregeln finden Sie in der Dokumentation zu Sicherheitsregeln.
  5. Klicken Sie auf Veröffentlichen.

Authentifizierungsstatus in UserViewModel.swift beobachten

In SwiftUI sorgt die reaktive Beobachtung des Firebase Auth-Status dafür, dass die Benutzeroberfläche reibungslos zwischen dem Anmeldebildschirm und der Chat-Oberfläche wechselt.

Öffnen Sie ViewModels/UserViewModel.swift und ersetzen Sie das TODO in init(), um Änderungen am Authentifizierungsstatus mit der AsyncSequence authStateChanges zu beobachten:

  init() {
    authTask = Task {
      for await user in Auth.auth().authStateChanges {
        self.user = user
      }
    }
  }

Anmeldung, Registrierung und Abmeldung mit Swift Concurrency implementieren

Ersetzen Sie in UserViewModel.swift die verbleibenden TODO-Kommentare durch moderne async/await-Authentifizierungsmethoden:

  func signIn(email: String, password: String) async {
    errorMessage = nil
    if email.isEmpty || password.isEmpty {
      showError("Please enter both email and password.")
      return
    }
    do {
      try await Auth.auth().signIn(withEmail: email, password: password)
    } catch {
      showError(error.localizedDescription)
    }
  }

  func signUp(email: String, password: String, displayName: String) async {
    errorMessage = nil
    if email.isEmpty || password.isEmpty {
      showError("Please enter both email and password.")
      return
    }
    do {
      let result =
        try await Auth.auth().createUser(withEmail: email, password: password)
      let changeRequest = result.user.createProfileChangeRequest()
      changeRequest.displayName = displayName.isEmpty ? email : displayName
      try await changeRequest.commitChanges()
      self.user = Auth.auth().currentUser
    } catch {
      showError(error.localizedDescription)
    }
  }

  func updateDisplayName(_ displayName: String) async {
    guard let currentUser = Auth.auth().currentUser else { return }
    do {
      let changeRequest = currentUser.createProfileChangeRequest()
      changeRequest.displayName = displayName
      try await changeRequest.commitChanges()
      self.user = Auth.auth().currentUser
    } catch {
      showError(error.localizedDescription)
    }
  }

  func signOut() {
    do {
      try Auth.auth().signOut()
    } catch {
      showError(error.localizedDescription)
    }
  }

Nutzerauthentifizierung testen

  1. Klicken Sie in Xcode auf die Schaltfläche Ausführen.
  2. Klicken Sie im App-Simulator auf Registrieren, geben Sie einen Anzeigenamen, eine E‑Mail-Adresse und ein Passwort ein und tippen Sie auf REGISTRIEREN.
  3. Sie sollten automatisch authentifiziert und zum leeren Nachrichtenbildschirm weitergeleitet werden.

6. Aus Cloud Firestore lesen

Beispielnachrichten in der Firebase Console hinzufügen

Füllen Sie die Datenbank mit Beispielnachrichten:

  1. Wechseln Sie in der Firebase Console zu Firestore-Datenbank und wählen Sie den Tab Daten aus.
  2. Klicken Sie auf Sammlung starten.
  3. Geben Sie messages für die Sammlungs-ID ein und klicken Sie dann auf Weiter.
  4. Lassen Sie die Dokument-ID auf „Automatisch generieren“ eingestellt (oder klicken Sie auf Auto-ID).
  5. Fügen Sie dem Dokument die folgenden Felder hinzu:
    • text (Typ: string, Wert: Hello)
    • displayName (Typ: string, Wert: anonymous)
  6. Klicken Sie auf Speichern.
  7. Optional können Sie auf Dokument hinzufügen klicken, um weitere Beispielnachrichten hinzuzufügen.

Nachrichten in FriendlyMessageViewModel.swift synchronisieren

In SwiftUI steuert ein @Observable-Modell deklarative UI-Updates. Öffnen Sie ViewModels/FriendlyMessageViewModel.swift und implementieren Sie startListening() und stopListening() mit der AsyncSequence snapshots:

  func startListening() {
    stopListening()
    listenerTask = Task {
      let db = Firestore.firestore()
      do {
        for try await snapshot in db.collection("messages").snapshots {
          self.messages = snapshot.documents.compactMap { document in
            try? document.data(as: FriendlyMessage.self)
          }
        }
      } catch {
        print("Error listening for messages: \(error)")
      }
    }
  }

  func stopListening() {
    listenerTask?.cancel()
    listenerTask = nil
    messages.removeAll()
  }

So rendert und scrollt SwiftUI Nachrichten automatisch

In Views/ContentView.swift sehen Sie, wie ScrollViewReader und LazyVStack Chatblasen rendern und automatisch zur neuesten Nachricht scrollen, wenn sich messages.count ändert:

ScrollViewReader { scrollViewReader in
  ScrollView {
    LazyVStack(spacing: 12) {
      ForEach(messageViewModel.messages) { message in
        FriendlyMessageView(friendlyMessage: message)
          .id(message.id)
      }
    }
    .padding(.horizontal)
    .onChange(of: messageViewModel.messages.count) { _, count in
      guard count > 0,
            let lastId = messageViewModel.messages.last?.id else { return }
      withAnimation(.easeInOut) {
        scrollViewReader.scrollTo(lastId, anchor: .bottom)
      }
    }
  }
}

Indem der Datenbankstatus über das Ansichtsmodell direkt mit dem UI-Status verknüpft wird, kann der App-Code Übergänge sauber Animationen zuordnen. Im nächsten Schritt schreiben Sie Daten aus der App in die Datenbank, um diese Animation in Aktion zu sehen.

7. Nachrichten senden

sendMessage mit Swift Concurrency implementieren

Wenn Sie mit addDocument() ein Dokument zu einer Sammlung hinzufügen, generiert Cloud Firestore eine eindeutige ID für jede Chatnachricht.

Ersetzen Sie in ViewModels/FriendlyMessageViewModel.swift das TODO in sendMessage(text:imageUrl:) durch eine async throws-Methode:

  func sendMessage(text: String?, imageUrl: String?) async throws {
    guard let currentUser = Auth.auth().currentUser else { return }
    let message = FriendlyMessage(
      text: text,
      displayName: currentUser.displayName ?? currentUser.email ?? "Anonymous",
      imageUrl: imageUrl,
      userId: currentUser.uid
    )
    let db = Firestore.firestore()
    _ = try db.collection("messages").addDocument(from: message)
  }

Das Senden von Nachrichten testen

  1. Klicken Sie in Xcode auf die Schaltfläche Ausführen.
  2. Melden Sie sich in Ihrem Konto an.
  3. Geben Sie eine Nachricht in das Textfeld unten ein und tippen Sie auf das Symbol „Senden“.
  4. Die Nachricht wird sofort im Simulator angezeigt.

8. Bilder speichern und empfangen

Cloud Storage for Firebase einrichten

  1. Wechseln Sie in der Firebase Console zu Datenbanken und Speicher > Speicher und klicken Sie dann auf Jetzt starten.
  2. Wählen Sie Im Testmodus starten aus und klicken Sie auf Weiter.
  3. Übernehmen Sie den Standardspeicherort und klicken Sie auf Fertig.

Native Bildauswahl mit SwiftUI PhotosPicker

Modernes SwiftUI (iOS 16 oder höher) bietet eine native Fotoauswahl über PhotosPicker aus import PhotosUI. Es sind keine UIKit-Delegatbrücken oder UIImagePickerController-Wrapper erforderlich.

In Views/FooterView.swift sehen Sie, wie PhotosPicker ausgewählte Bilder bindet:

PhotosPicker(selection: $selectedItem, matching: .images) {
  Image(systemName: "photo.on.rectangle.angled")
    .font(.system(size: 26))
    .foregroundStyle(.blue)
    .accessibilityLabel("Select photo")
}
.onChange(of: selectedItem) { _, newItem in
  Task {
    if let data = try? await newItem?.loadTransferable(type: Data.self) {
      await uploadAndSendImage(data: data)
    }
  }
}

Bild-Upload implementieren

Wenn ein Foto ausgewählt ist, laden Sie die Bilddaten in Cloud Storage hoch und speichern Sie die öffentliche Download-URL in Cloud Firestore.

Ersetzen Sie in Views/FooterView.swift das TODO in uploadAndSendImage(data:):

  private func uploadAndSendImage(data: Data) async {
    guard let uid = Auth.auth().currentUser?.uid else { return }
    isUploading = true
    defer {
      isUploading = false
      selectedItem = nil
    }
    do {
      let filename = "\(uid)/\(UUID().uuidString).jpg"
      let storageRef =
        Storage.storage().reference().child("images").child(filename)
      let metadata = StorageMetadata()
      metadata.contentType = "image/jpeg"

      _ = try await storageRef.putDataAsync(data, metadata: metadata)
      let downloadURL = try await storageRef.downloadURL()
      try await viewModel.sendMessage(
        text: nil, imageUrl: downloadURL.absoluteString)
    } catch {
      print("Error uploading image: \(error.localizedDescription)")
    }
  }

Bilder mit Cloud Storage freigeben

In Views/FriendlyMessageImageView.swift werden Bild-URLs asynchron mit Swift Concurrency und dem Cloud Storage SDK geladen:

  • Standardmäßige HTTP/HTTPS-Download-URLs werden asynchron über URLSession abgerufen.
  • Google Cloud Storage-URLs (z. B. gs://...) werden mit Storage.storage().reference(forURL:) abgerufen.

Bildnachrichten testen

  1. Klicken Sie in Xcode auf die Schaltfläche Ausführen.
  2. Melden Sie sich in Ihrem Konto an.
  3. Tippen Sie auf das Fotosymbol, wählen Sie ein Bild aus der Mediathek aus und sehen Sie zu, wie es hochgeladen wird und im Chat erscheint.

9. Fazit

Herzlichen Glückwunsch! Sie haben mit Swift und Firebase erfolgreich eine iOS-App für Echtzeit-Chats erstellt.

Das haben Sie gelernt

  • Swift Package Manager (SPM) -Xcode-Integration für firebase-ios-sdk.
  • SwiftUI -Deklarative Layouts, PhotosPicker und automatisches Scrollen mit ScrollViewReader.
  • Swift Concurrency (async/await) für Authentifizierung, Cloud Firestore und Cloud Storage.
  • Authentifizierung per E‑Mail/Passwort und anonyme Authentifizierung mit reaktiver Statusbeobachtung.
  • Cloud Firestore -Echtzeit-Snapshot-Abhören und automatisierte ID-Schreibvorgänge.
  • Cloud Storage for Firebase -Binäruploads und öffentliche Download-URLs.

Weitere Informationen