Mit Firebase Data Connect entwickeln (iOS / Swift)

1. Übersicht

In diesem Codelab erfahren Sie, wie Sie Firebase Data Connect in eine Cloud SQL-Datenbank einbinden, um mit SwiftUI eine Filmbewertungs-App für iOS zu erstellen.

Sie erfahren, wie Sie Ihre iOS-Anwendung mit Firebase Data Connect mit einer Cloud SQL-Datenbank verbinden, um eine nahtlose Datensynchronisierung für Filmbesprechungen zu ermöglichen.

Am Ende dieses Codelabs haben Sie eine funktionierende iOS-App, mit der Nutzer Filme durchsuchen und als Favoriten markieren können. Die App wird von einer Cloud SQL-Datenbank unterstützt, die auf Firebase Data Connect basiert.

Lerninhalte

In diesem Codelab lernen Sie Folgendes:

  • Richten Sie Firebase Data Connect ein und verwenden Sie die Firebase Emulator Suite, um schnell Ergebnisse zu erhalten.
  • Datenbankschema mit Data Connect und GraphQL entwerfen
  • Erstellen Sie ein typsicheres Swift-SDK aus Ihrem Datenbankschema und fügen Sie es einer Swift-Anwendung hinzu.
  • Implementieren Sie die Nutzerauthentifizierung und binden Sie sie in Firebase Data Connect ein, um die Daten Ihrer Nutzer zu schützen.
  • Mit Abfragen und Mutationen, die auf GraphQL basieren, können Sie Daten in Cloud SQL abrufen, aktualisieren, löschen und verwalten.
  • Optional: Stellen Sie einen Data Connect-Dienst für die Produktion bereit.

Vorbereitung

  • Die aktuelle Version von Xcode
  • Der Beispielcode für das Codelab. Sie laden den Beispielcode in einem der ersten Schritte des Codelabs herunter.

2. Beispielprojekt einrichten

Firebase-Projekt erstellen

  1. Melden Sie sich mit Ihrem Google-Konto in der Firebase Console an.
  2. Klicken Sie auf die Schaltfläche, um ein neues Projekt zu erstellen, und geben Sie dann einen Projektnamen ein (z. B. Friendly Flix).
  3. Klicken Sie auf Weiter.
  4. Lesen und akzeptieren Sie bei Aufforderung die Firebase-Nutzungsbedingungen und klicken Sie dann auf Weiter.
  5. (Optional) Aktivieren Sie die KI-Unterstützung in der Firebase Console (als „Gemini in Firebase“ bezeichnet).
  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.

Code herunterladen

Führen Sie den folgenden Befehl aus, um den Beispielcode für dieses Codelab zu klonen. Dadurch wird auf Ihrem Computer ein Verzeichnis mit dem Namen codelab-dataconnect-ios erstellt:

git clone https://github.com/FirebaseExtended/codelab-dataconnect-ios`

Wenn Sie Git nicht auf Ihrem Computer haben, können Sie den Code auch direkt von GitHub herunterladen.

Firebase-Konfiguration hinzufügen

Das Firebase SDK verwendet eine Konfigurationsdatei, um eine Verbindung zu Ihrem Firebase-Projekt herzustellen. Auf Apple-Plattformen heißt diese Datei GoogleServices-Info.plist. In diesem Schritt laden Sie die Konfigurationsdatei herunter und fügen sie Ihrem Xcode-Projekt hinzu.

  1. Wählen Sie in der Firebase Console im linken Navigationsbereich Projektübersicht aus.
  2. Klicken Sie auf die Schaltfläche iOS+, um die Plattform auszuwählen. Geben Sie im Feld Apple-Bundle-ID den Wert com.google.firebase.samples.FriendlyFlix ein.
  3. Klicken Sie auf App registrieren und folgen Sie der Anleitung, um die GoogleServices-Info.plist-Datei herunterzuladen.
  4. Verschieben Sie die heruntergeladene Datei in das Verzeichnis start/FriendlyFlix/app/FriendlyFlix/FriendlyFlix/ des gerade heruntergeladenen Codes und ersetzen Sie die vorhandene Datei GoogleServices-Info.plist.
  5. Klicken Sie dann einige Male auf Weiter, um das Einrichtungsprojekt in der Firebase Console abzuschließen. Sie müssen das SDK nicht der App hinzufügen, da dies bereits im Starterprojekt erfolgt ist.
  6. Klicken Sie abschließend auf Weiter zur Konsole, um die Einrichtung abzuschließen.

3. Data Connect einrichten

Installation

Automatische Installation

Führen Sie den folgenden Befehl im Verzeichnis codelab-dataconnect-ios/FriendlyFlix aus:

curl -sL https://firebase.tools/dataconnect | bash

Dieses Skript versucht, die Entwicklungsumgebung für Sie einzurichten und eine browserbasierte IDE zu starten. Diese IDE bietet Tools, einschließlich einer vorab gebündelten VS Code-Erweiterung, mit denen Sie Ihr Schema verwalten, Abfragen und Mutationen für Ihre Anwendung definieren und stark typisierte SDKs generieren können.

Nachdem Sie das Skript ausgeführt haben, sollte VS Code automatisch geöffnet werden.

Nachdem Sie dies einmal getan haben, können Sie VS Code starten, indem Sie VS Code im lokalen Verzeichnis ausführen:

code .

Manuelle Installation

  1. Visual Studio Code installieren
  2. Installieren Sie Node.js.
  3. Öffnen Sie in VS Code das Verzeichnis codelab-dataconnect-ios/FriendlyFlix.
  4. Installieren Sie die Firebase Data Connect-Erweiterung über den Visual Studio Code Marketplace.

Data Connect im Projekt initialisieren

Klicken Sie im linken Bereich auf das Firebase-Symbol, um die Benutzeroberfläche der Data Connect VS Code-Erweiterung zu öffnen.

  1. Klicken Sie auf die Schaltfläche Über Google anmelden. Ein Browserfenster wird geöffnet. Folgen Sie der Anleitung, um sich mit Ihrem Google-Konto in der Erweiterung anzumelden.
  2. Klicken Sie auf die Schaltfläche Firebase-Projekt verknüpfen und wählen Sie das Projekt aus, das Sie zuvor in der Console erstellt haben.
  3. Klicken Sie auf die Schaltfläche firebase init ausführen und folgen Sie der Anleitung im integrierten Terminal.

SDK-Generierung konfigurieren

Wenn Sie auf die Schaltfläche firebase init ausführen klicken, sollte die Firebase Data Connect-Erweiterung ein dataconnect-Verzeichnis für Sie initialisieren.

Öffnen Sie in VS Code die Datei dataconnect/connector/connector.yaml. Dort finden Sie die Standardkonfiguration.

Aktualisieren Sie die Konfiguration und verwenden Sie die folgenden Einstellungen, damit der generierte Code mit diesem Codelab funktioniert. Achten Sie insbesondere darauf, dass connectorId auf friendly-flix und das Swift-Paket auf FriendlyFlixSDK gesetzt ist.

connectorId: "friendly-flix"
generate:
  swiftSdk:
    outputDir: "../../app"
    package: "FriendlyFlixSDK"
    observablePublisher: observableMacro

Das bedeuten die Einstellungen:

  • connectorId: ein eindeutiger Name für diesen Connector.
  • outputDir: Pfad, in dem das generierte Data Connect SDK gespeichert wird. Dieser Pfad bezieht sich auf das Verzeichnis, das die connector.yaml-Datei enthält.
  • package: Der Paketname, der für das generierte Swift-Paket verwendet werden soll.

Sobald Sie diese Datei speichern, generiert Firebase Data Connect ein Swift-Paket mit dem Namen FriendlyFlixSDK und platziert es neben dem Projektordner FriendlyFlix.

Firebase-Emulatoren starten

Wechseln Sie in VS Code zur Firebase-Ansicht und klicken Sie dann auf die Schaltfläche Emulatoren starten.

Dadurch wird der Firebase-Emulator im integrierten Terminal gestartet. Die Ausgabe sollte in etwa so aussehen:

npx -y firebase-tools@latest emulators:start --project <your-project-id>

Generiertes Paket Ihrer Swift-App hinzufügen

  1. FriendlyFlix/app/FriendlyFlix/FriendlyFlix.xcodeproj in Xcode öffnen
  2. Wählen Sie File > Add Package Dependencies... aus.
  3. Klicken Sie auf Add Local... (Lokal hinzufügen…) und fügen Sie dann das FriendlyFlixSDK-Paket aus dem Ordner FriendlyFlix/app hinzu.
  4. Warten Sie, bis Xcode die Paketabhängigkeiten aufgelöst hat.
  5. Wählen Sie im Dialogfeld Choose Package Products for FriendlyFlixSDK (Paketprodukte für FriendlyFlixSDK auswählen) FriendlyFlix als Ziel aus und klicken Sie auf Add Package (Paket hinzufügen).

iOS-App für die Verwendung des lokalen Emulators konfigurieren

  1. Öffnen Sie FriendlyFlixApp.swift. (Sie können CMD + Umschalt + O drücken, um das Dialogfeld Schnell öffnen zu öffnen, und dann „FriendlyFlixApp“ eingeben, um die Datei schnell zu finden.)
  2. Firebase, Firebase Auth, Firebase Data Connect und das generierte SDK für Ihr Schema importieren
  3. Konfigurieren Sie Firebase im Initialisierer.
  4. Achten Sie darauf, dass DataConnect und Firebase Auth den lokalen Emulator verwenden.
import SwiftUI
import os
import Firebase
import FirebaseAuth
import FriendlyFlixSDK
import FirebaseDataConnect

@main
struct FriendlyFlixApp: App {
  ...

  init() {
    FirebaseApp.configure()
    if useEmulator {
      DataConnect.friendlyFlixConnector.useEmulator(port: 9399)
      Auth.auth().useEmulator(withHost: "localhost", port: 9099)
    }

    authenticationService = AuthenticationService()
  }

  ...

}
  1. Wählen Sie im Drop-down-Menü Ziel einen iOS-Simulator aus.
  2. Drücken Sie in Xcode CMD+R oder klicken Sie auf die Schaltfläche Run (Ausführen), um die App auf einem Simulator auszuführen.

4. Schema definieren und Datenbank vorab mit Daten füllen

In diesem Abschnitt definieren Sie die Struktur und die Beziehungen zwischen den wichtigsten Einheiten in der Filmanwendung in einem Schema. Entitäten wie Movie und MovieMetaData werden Datenbanktabellen zugeordnet. Beziehungen werden mit Firebase Data Connect und GraphQL-Schemaanweisungen hergestellt.

Wichtige Entitäten und Beziehungen

Das Datenmodell für diese Filmtracker-App besteht aus mehreren Entitäten, die Sie im Laufe dieses Codelabs erstellen. Sie erstellen zuerst die wichtigsten Entitäten und fügen dann, wenn Sie immer mehr Funktionen implementieren, die für diese Funktionen erforderlichen Entitäten hinzu.

In diesem Schritt erstellen Sie die Typen Movie und MovieMetadata.

Film

Der Typ Movie definiert die Hauptstruktur für eine Filmentität, einschließlich Feldern wie title, genre, releaseYear und rating.

Fügen Sie in VS Code die Typdefinition Movie zu dataconnect/schema/schema.gql hinzu:

type Movie @table {
  id: UUID! @default(expr: "uuidV4()")
  title: String!
  imageUrl: String!
  releaseYear: Int
  genre: String
  rating: Float
  description: String
  tags: [String]
}

MovieMetadata

Der Typ MovieMetadata stellt eine 1:1-Beziehung zum Typ Movie her. Sie enthält zusätzliche Daten wie den Regisseur des Films.

Fügen Sie der Datei dataconnect/schema/schema.gql die Tabellendefinition MovieMetadata hinzu:

type MovieMetadata @table {
  movie: Movie! @ref
  director: String
}

Automatisch generierte Felder und Standardwerte

Im Schema werden Ausdrücke wie @default(expr: "uuidV4()") verwendet, um automatisch eindeutige IDs und Zeitstempel zu generieren. Das Feld id vom Typ Movie wird beispielsweise automatisch mit einer UUID gefüllt, wenn ein neuer Datensatz erstellt wird.

Scheindaten für Filme und Filmdaten einfügen

Nachdem Sie das Schema definiert haben, können Sie die Datenbank jetzt mit Scheindaten für Tests vorab befüllen.

  1. Kopieren Sie im Finder finish/FriendlyFlix/dataconnect/moviedata_insert.gql in den Ordner start/FriendlyFlix/dataconnect.
  2. Öffnen Sie in VS Code dataconnect/moviedata_insert.gql.
  3. Prüfen Sie, ob die Emulatoren in der Firebase Data Connect-Erweiterung ausgeführt werden.
  4. Oben in der Datei sollte die Schaltfläche Lokal ausführen angezeigt werden. Klicken Sie darauf, um die Testfilmdaten in Ihre Datenbank einzufügen.
  5. Prüfen Sie im Terminal Data Connect Execution, ob die Daten erfolgreich hinzugefügt wurden.

Nachdem Sie die Daten eingerichtet haben, fahren Sie mit dem nächsten Schritt fort, um zu erfahren, wie Sie Abfragen in Data Connect erstellen.

5. Filme abrufen und anzeigen

In diesem Abschnitt implementieren Sie eine Funktion zum Anzeigen einer Liste von Filmen.

Zuerst erfahren Sie, wie Sie eine Abfrage erstellen, mit der alle Filme aus der Tabelle movies abgerufen werden. Firebase Data Connect generiert Code für ein typsicheres SDK, mit dem Sie die Abfrage ausführen und die abgerufenen Filme in der Benutzeroberfläche Ihrer App anzeigen können.

Abfrage „ListMovies“ definieren

Abfragen in Firebase Data Connect werden in GraphQL geschrieben. So können Sie angeben, welche Felder abgerufen werden sollen. In FriendlyFlix sind für die Bildschirme, auf denen Filme angezeigt werden, die folgenden Felder erforderlich: title, description, releaseYear, rating und imageUrl. Da es sich um eine SwiftUI-App handelt, benötigen Sie außerdem id, um die Identität der SwiftUI-Ansicht zu bestimmen.

Öffnen Sie in VS Code die Datei dataconnect/connector/queries.gql und fügen Sie die Abfrage ListMovies hinzu:

query ListMovies @auth(level: PUBLIC) {
  movies {
    id
    title
    imageUrl
    releaseYear
    genre
    rating
    tags
    description
  }
}

Wenn Sie die neue Abfrage testen möchten, klicken Sie auf die Schaltfläche Lokal ausführen, um die Abfrage für Ihre lokale Datenbank auszuführen. Die Liste der Filme aus der Datenbank sollte im Terminal für die Data Connect-Ausführung im Bereich Results (Ergebnisse) angezeigt werden.

Die ListMovies-Anfrage mit dem Startbildschirm der App verbinden

Nachdem Sie die Abfrage im Data Connect-Emulator getestet haben, können Sie sie in Ihrer App aufrufen.

Wenn Sie queries.gql speichern, generiert Firebase Data Connect den Code, der der ListMovies-Abfrage im FriendlyFlixSDK-Paket entspricht.

Öffnen Sie in Xcode Movie+DataConnect.swift und fügen Sie den folgenden Code hinzu, um ListMoviesQuery.Data.Movie Movie zuzuordnen:

import FirebaseDataConnect
import FriendlyFlixSDK

extension Movie {
  init(from: ListMoviesQuery.Data.Movie) {
    id = from.id
    title = from.title
    description = from.description ?? ""
    releaseYear = from.releaseYear
    rating = from.rating
    imageUrl = from.imageUrl
  }
}

Öffnen Sie die Datei HomeScreen.swift und aktualisieren Sie sie mit dem folgenden Code-Snippet.

import SwiftUI
import FirebaseDataConnect
import FriendlyFlixSDK

struct HomeScreen: View {
  ...

  private var connector = DataConnect.friendlyFlixConnector
  let heroMoviesRef: QueryRefObservation<ListMoviesQuery.Data, ListMoviesQuery.Variables>

  init() {
    heroMoviesRef = connector.listMoviesQuery.ref()
  }
}

extension HomeScreen {
  ...

  private var heroMovies: [Movie] {
    heroMoviesRef.data?.movies.map(Movie.init) ?? []
  }

 private var topMovies: [Movie] {
    heroMoviesRef.data?.movies.map(Movie.init) ?? []
  }

  private var watchList: [Movie] {
    heroMoviesRef.data?.movies.map(Movie.init) ?? []
  }

  ...
}

Die listMoviesQuery()-Abfrage wurde von Data Connect generiert, als Sie queries.gql gespeichert haben. Die Swift-Implementierung finden Sie in der Datei FriendlyFlixOperations.swift im Paket FriendlyFlixSDK.

Anwendung ausführen

Klicken Sie in Xcode auf die Schaltfläche Run (Ausführen), um die App im iOS-Simulator zu starten.

Nach dem Start der App sollte ein Bildschirm wie dieser angezeigt werden:

Möglicherweise wird in allen Bereichen der App (Hero-Bereich, Top-Filme und Watchlist) dieselbe Liste angezeigt. Das liegt daran, dass Sie für alle diese Datenansichten dieselbe Abfrage verwenden. In den nächsten Abschnitten implementieren Sie benutzerdefinierte Abfragen.

6. Hero- und Top-Filme anzeigen

In diesem Schritt konzentrieren Sie sich darauf, die Darstellung von Filmen im Hero-Bereich – dem prominenten Karussell oben auf dem Startbildschirm – und im Bereich „Top-Filme“ darunter zu aktualisieren.

Derzeit werden mit der Abfrage „ListMovies“ alle Filme abgerufen. Um die Anzeige für diese Abschnitte zu optimieren, begrenzen Sie die Anzahl der Filme, die bei jeder Anfrage zurückgegeben werden. Die aktuelle Implementierung der ListMovies-Abfrage bietet noch keine integrierte Unterstützung für das Einschränken von Ergebnissen. Die Unterstützung für das Einschränken und Sortieren wird in diesem Abschnitt hinzugefügt.

Abfrage „ListMovies“ optimieren

Öffnen Sie queries.gql und aktualisieren Sie ListMovies so, dass die Unterstützung für das Sortieren und Begrenzen hinzugefügt wird:

query ListMovies(
  $orderByRating: OrderDirection
  $orderByReleaseYear: OrderDirection
  $limit: Int
) @auth(level: PUBLIC) {
  movies(
    orderBy: [{ rating: $orderByRating }, { releaseYear: $orderByReleaseYear }]
    limit: $limit
  ) {
    id
    title
    description
    releaseYear
    rating
    imageUrl
  }
}

So können Sie die Anzahl der Filme, die von der Abfrage zurückgegeben werden, begrenzen und den Ergebnissatz sowohl nach Bewertung als auch nach Erscheinungsjahr sortieren.

Sobald Sie diese Datei speichern, wird der Code in FriendlyFlixSDK automatisch von Firebase Data Connect neu generiert. Im nächsten Schritt können Sie den Code in HomeScreen.swift aktualisieren, um diese zusätzlichen Funktionen zu nutzen.

Erweiterte Abfrage in der Benutzeroberfläche verwenden

Kehren Sie zu Xcode zurück, um die erforderlichen Änderungen an HomeScreen.swift vorzunehmen.

Aktualisieren Sie zuerst heroMoviesRef, um die drei zuletzt veröffentlichten Filme abzurufen:

struct HomeScreen {
  ...

  init() {
    heroMoviesRef = connector.listMoviesQuery
      .ref { optionalVars in
        optionalVars.limit = 3
        optionalVars.orderByReleaseYear = .DESC
      }

  }
}

Richten Sie als Nächstes eine weitere Abfrage-Referenz für die Top-Filme ein und legen Sie den Filter auf die fünf am besten bewerteten Filme fest:

struct HomeScreen {
  ...

  let topMoviesRef: QueryRefObservation<ListMoviesQuery.Data, ListMoviesQuery.Variables>

  init() {
    heroMoviesRef = ...

    topMoviesRef = connector.listMoviesQuery
      .ref { optionalVars in
        optionalVars.limit = 5
        optionalVars.orderByRating = .DESC
      }
  }
}

Aktualisieren Sie schließlich die berechnete Eigenschaft, die das Ergebnis dieser Abfrage mit der Benutzeroberfläche verbindet:

extension HomeScreen {
  ...

  private var topMovies: [Movie] {
    topMoviesRef.data?.movies.map(Movie.init) ?? []
  }

}

Demo

Führen Sie die App noch einmal aus, um die drei neuesten Filme im Hero-Bereich und die fünf am besten bewerteten Filme im Bereich „Top-Filme“ zu sehen:

7. Filmdetails und Schauspielerdetails anzeigen

Der Nutzer kann jetzt Filme ansehen. Wenn Nutzer auf eine Filmkarte tippen, werden ihnen einige Details zum Film angezeigt. Allerdings sind diese Details nicht sehr ausführlich.

Das liegt daran, dass wir nur so viele Details zu den einzelnen Filmen abgerufen haben, wie wir für die Darstellung des Hero-Bereichs und des Bereichs mit den Top-Filmen benötigen: den Filmtitel, eine kurze Beschreibung und die Bild-URL.

Auf der Seite mit den Filmdetails möchten wir weitere Informationen zum Film anzeigen. In diesem Abschnitt erweitern Sie die App so, dass auf der Detailseite die Schauspieler des Films und alle Rezensionen angezeigt werden.

Dazu sind einige Schritte erforderlich:

  • Schema zur Unterstützung von Filmdarstellern und Rezensionen erweitern
  • Firebase Data Connect-Abfragen zum Abrufen von Details zu einem bestimmten Film schreiben
  • Ergebnisse auf dem Bildschirm mit den Filmdetails anzeigen

Schema optimieren

Öffnen Sie in VS Code dataconnect/schema/schema.gql und fügen Sie die Schemadefinitionen für Actor und MovieActor hinzu.

## Actors
## An actor can participate in multiple movies; movies can have multiple actors
## Movie - Actors (or vice versa) is a many to many relationship
type Actor @table {
  id: UUID!
  imageUrl: String!
  name: String! @col(name: "name", dataType: "varchar(30)")
}

## Join table for many-to-many relationship for movies and actors
## The 'key' param signifies the primary key(s) of this table
## In this case, the keys are [movieId, actorId], the generated fields of the reference types [movie, actor]
type MovieActor @table(key: ["movie", "actor"]) {
  ## @ref creates a field in the current table (MovieActor) that holds the primary key of the referenced type
  ## In this case, @ref(fields: "id") is implied
  movie: Movie!
  ## movieId: UUID! <- this is created by the implied @ref, see: implicit.gql

  actor: Actor!
  ## actorId: UUID! <- this is created by the implied  @ref, see: implicit.gql

  role: String! ## "main" or "supporting"
}

Scheindaten für Akteure hinzufügen

Nachdem das Schema aktualisiert wurde, können Sie die Datenbank jetzt mit weiteren Scheindaten für Tests füllen.

  1. Kopieren Sie im Finder finish/FriendlyFlix/dataconnect/moviededetails_insert.gql in den Ordner start/FriendlyFlix/dataconnect.
  2. Öffnen Sie in VS Code dataconnect/moviededetails_insert.gql.
  3. Prüfen Sie, ob die Emulatoren in der Firebase Data Connect-Erweiterung ausgeführt werden.
  4. Oben in der Datei sollte die Schaltfläche Lokal ausführen angezeigt werden. Klicken Sie darauf, um die Testfilmdaten in Ihre Datenbank einzufügen.
  5. Prüfen Sie im Terminal für die Data Connect-Ausführung, ob die Daten erfolgreich hinzugefügt wurden.

Nachdem die Daten vorhanden sind, fahren Sie mit dem nächsten Schritt fort, um die Abfrage zum Abrufen der Filmdetails zu definieren.

Die Abfrage „GetMovieById“ definieren

Öffnen Sie in VS Code die Datei dataconnect/connector/queries.gql und fügen Sie die Abfrage GetMovieById hinzu:

## Get movie by id
query GetMovieById($id: UUID!) @auth(level: PUBLIC) {
  movie(id: $id) {
    id
    title
    imageUrl
    releaseYear
    genre
    rating
    description
    tags
    metadata: movieMetadatas_on_movie {
      director
    }
    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
      id
      name
      imageUrl
    }
    supportingActors: actors_via_MovieActor(
      where: { role: { eq: "supporting" } }
    ) {
      id
      name
      imageUrl
    }
  }
}

Die Abfrage „GetMovieById“ mit der „MovieDetailsView“ verbinden

Öffnen Sie in Xcode die Datei MovieDetailsView.swift und aktualisieren Sie die berechnete Eigenschaft movieDetails mit dem folgenden Code:

import NukeUI
import SwiftUI
import FirebaseDataConnect
import FriendlyFlixSDK

@MainActor
struct MovieDetailsView: View {
  private var movie: Movie

  private var movieDetails: MovieDetails? {
    DataConnect.friendlyFlixConnector
      .getMovieByIdQuery
      .ref(id: movie.id)
      .data?.movie.map { movieDetails in
        MovieDetails(
          title: movieDetails.title,
          description: movieDetails.description ?? "",
          releaseYear: movieDetails.releaseYear,
          rating: movieDetails.rating ?? 0,
          imageUrl: movieDetails.imageUrl,
          mainActors: movieDetails.mainActors.map { mainActor in
            MovieActor(id: mainActor.id,
                       name: mainActor.name,
                       imageUrl: mainActor.imageUrl)
          },
          supportingActors: movieDetails.supportingActors.map{ supportingActor in
            MovieActor(id: supportingActor.id,
                       name: supportingActor.name,
                       imageUrl: supportingActor.imageUrl)
          },
          reviews: []
        )
      }
  }

  public init(movie: Movie) {
    self.movie = movie
  }
}

Anwendung ausführen

Klicken Sie in Xcode auf die Schaltfläche Run (Ausführen), um die App im iOS-Simulator zu starten.

Tippe nach dem Starten der App auf eine Filmkarte, um die Filmdetails aufzurufen. Das sollte so aussehen:

8. Nutzerauthentifizierung implementieren

Derzeit werden in der App nicht personalisierte Informationen zu Filmen und Schauspielern angezeigt. In den folgenden Schritten implementieren Sie Funktionen, mit denen Daten dem angemeldeten Nutzer zugeordnet werden. Zuerst ermöglichen Sie Nutzern, Filme zu ihrer persönlichen Merkliste hinzuzufügen.

Bevor Sie die Funktion „Beobachtungsliste“ implementieren können, müssen Sie zuerst die Nutzeridentität feststellen. Dazu müssen Sie Firebase Authentication einbinden, damit sich Nutzer in der App anmelden können.

Vielleicht haben Sie die Schaltfläche mit dem Nutzeravatar oben rechts auf dem Startbildschirm schon gesehen. Wenn Sie darauf tippen, gelangen Sie zu einem Bildschirm, auf dem sich Nutzer mit ihrer E-Mail-Adresse und ihrem Passwort registrieren oder anmelden können.

Nachdem sich ein Nutzer erfolgreich angemeldet hat, muss Ihre App seine wichtigsten Daten speichern, vor allem seine eindeutige Nutzer-ID und den ausgewählten Nutzernamen.

Firebase Authentication aktivieren

Rufen Sie in der Firebase Console für Ihr Projekt den Bereich „Authentifizierung“ auf und aktivieren Sie Firebase Authentication. Aktivieren Sie dann den Authentifizierungsanbieter für E-Mail-Adresse/Passwort.

Suchen Sie in Ihrem lokalen Projektordner nach firebase.json und aktualisieren Sie die Datei wie unten beschrieben, um den Firebase Authentication-Emulator zu aktivieren.

{
  "emulators": {
    "dataconnect": {
    },
    "auth": {
    }
  },
  "dataconnect": {
    "source": "dataconnect"
  }
}

Danach müssen Sie den Firebase-Emulator beenden und neu starten, damit die Änderung wirksam wird.

Authentifizierungs-Handler implementieren

Im folgenden Abschnitt implementieren Sie die Logik, die die Nutzerauthentifizierung mit Ihrer Datenbank verbindet. Dazu müssen Sie einen Authentifizierungs-Handler erstellen, der auf erfolgreiche Anmeldungen wartet.

Sobald ein Nutzer authentifiziert ist, wird durch diesen Handler automatisch das entsprechende Konto in Ihrer Datenbank erstellt.

Öffnen Sie in Xcode die Datei AuthenticationService.swift und fügen Sie den folgenden Code ein:

import Foundation
import Observation
import os
import FirebaseAuth

enum AuthenticationState {
  case unauthenticated
  case authenticating
  case authenticated
}

@Observable
class AuthenticationService {
  private let logger = Logger(subsystem: "FriendlyFlix", category: "auth")

  var presentingAuthenticationDialog = false
  var presentingAccountDialog = false

  var authenticationState: AuthenticationState = .unauthenticated
  var user: User?
  private var authenticationListener: AuthStateDidChangeListenerHandle?

  init() {
    authenticationListener = Auth.auth().addStateDidChangeListener { auth, user in
      if let user {
        self.authenticationState = .authenticated
        self.user = user
      } else {
        self.authenticationState = .unauthenticated
      }
    }
  }

  private var onSignUp: ((User) -> Void)?
  public func onSignUp(_ action: @escaping (User) -> Void) {
    onSignUp = action
  }

  func signInWithEmailPassword(email: String, password: String) async throws {
    try await Auth.auth().signIn(withEmail: email, password: password)
    authenticationState = .authenticated
  }

  func signUpWithEmailPassword(email: String, password: String) async throws {
    try await Auth.auth().createUser(withEmail: email, password: password)

    if let onSignUp, let user = Auth.auth().currentUser {
      logger
        .debug(
          "User signed in \(user.displayName ?? "(no fullname)") with email \(user.email ?? "(no email)")"
        )
      onSignUp(user)
    }

    authenticationState = .authenticated
  }

  func signOut() throws {
    try Auth.auth().signOut()
    authenticationState = .unauthenticated
  }
}

Dies ist ein generischer Authentifizierungshandler, mit dem Sie mit onSignUp einen Abschluss registrieren können, der aufgerufen wird, wenn sich der Nutzer angemeldet hat.

Innerhalb dieses Closure können Sie dann ein neues Nutzerkonto in der Datenbank erstellen. Bevor Sie das tun können, müssen Sie jedoch eine Mutation erstellen, mit der Sie neue Nutzer in der Datenbank erstellen oder aktualisieren können.

Nutzerentität dem Schema hinzufügen

Der Typ User definiert eine Nutzerentität. Nutzer können mit Filmen interagieren, indem sie Rezensionen schreiben oder Filme als Favoriten markieren.

Öffnen Sie in VS Code die Datei dataconnect/schema/schema.gql und fügen Sie die folgende User-Tabellendefinition hinzu:

## Users
## A user can leave reviews for movies
## user-reviews is a one to many relationship, movie-reviews is a one to many relationship, movie:user is a many to many relationship
type User @table {
  id: String! @col(name: "user_auth")
  username: String! @col(name: "username", dataType: "varchar(50)")
}

Mutation zum Einfügen oder Aktualisieren eines Nutzers definieren

Öffnen Sie in VS Code die Datei dataconnect/connector/mutations.gql und fügen Sie die Mutation UpsertUser hinzu:

mutation UpsertUser($username: String!) @auth(level: USER) {
  user_upsert(
    data: {
      id_expr: "auth.uid"
      username: $username
    }
  )
}

Neuen Nutzer nach erfolgreicher Anmeldung erstellen

Öffnen Sie in Xcode FriendlyFlixApp.swift und fügen Sie dem Initialisierer den folgenden Code hinzu:

@main
struct FriendlyFlixApp: App {

  ...

  init() {
    ...
    authenticationService = AuthenticationService()
    authenticationService?.onSignUp { user in
      let userName = String(user.email?.split(separator: "@").first ?? "(unknown)")
      Task {
        try await DataConnect.friendlyFlixConnector
          .upsertUserMutation.execute(username: userName)
      }
    }
  }

  var body: some Scene {
    ...
  }
}

In diesem Code wird der upsertUserMutation Firebase Data Connect verwendet, der für Sie generiert wurde, um einen neuen Nutzer einzufügen (oder einen vorhandenen Nutzer mit derselben ID zu aktualisieren), wenn sich ein Nutzer erfolgreich mit Firebase Authentication registriert hat.

Demo

So prüfen Sie, ob das funktioniert:

  • Falls nicht, beenden Sie den Firebase-Emulator und starten Sie ihn neu, um sicherzustellen, dass der Firebase Authentication-Emulator ausgeführt wird.
  • Klicken Sie in Xcode auf die Schaltfläche Run (Ausführen), um die App im iOS-Simulator zu starten.
  • Klicken Sie oben rechts auf dem Bildschirm auf das Avatarsymbol.
  • Wechseln Sie zum Ablauf Registrieren und registrieren Sie sich für die App.

Fragen Sie dann die Datenbank ab, um zu prüfen, ob die App ein neues Nutzerkonto für den Nutzer erstellt hat:

  • Öffnen Sie dataconnect/schema/schema.gql in VS Code und klicken Sie für die User-Entität auf Daten lesen.
  • Dadurch wird eine neue Abfragedatei mit dem Namen User_read.gql erstellt.
  • Klicken Sie auf Lokal ausführen, um alle Nutzer in der Nutzertabelle zu sehen.
  • Im Bereich „Data Connect Execution“ (Data Connect-Ausführung) sollte jetzt ein Konto für den Nutzer angezeigt werden, mit dem Sie sich gerade registriert haben 

9. Lieblingsfilme verwalten

In diesem Abschnitt des Codelabs implementieren Sie Nutzerinteraktionen in der Filmrezensions-App. Nutzer sollen insbesondere ihre Lieblingsfilme verwalten können. Als Favoriten markierte Filme werden im Bereich „Merkliste“ der App angezeigt.

Schema zur Unterstützung von Favoriten erweitern

Der Typ FavoriteMovie ist eine Join-Tabelle, in der Viele-zu-viele-Beziehungen zwischen Nutzern und ihren Lieblingsfilmen verwaltet werden. In jeder Tabelle wird ein User mit einem Movie verknüpft.

Kopieren Sie das Code-Snippet und fügen Sie es in Ihre dataconnect/schema/schema.gql-Datei ein:

type FavoriteMovie
  @table(name: "FavoriteMovies", singular: "favorite_movie", plural: "favorite_movies", key: ["user", "movie"]) {
  ## @ref is implicit
  user: User!
  movie: Movie!
}

Mutationen zum Hinzufügen und Entfernen von Favoriten definieren

Bevor die App die Lieblingsfilme des Nutzers anzeigen kann, muss der Nutzer angeben, welche Filme seine Favoriten sind. Dazu müssen Sie zuerst zwei Mutationen hinzufügen, um einen Film als Favorit des Nutzers zu markieren oder ihn wieder aus seinen Favoriten zu entfernen.

  1. Öffnen Sie in VS Code mutations.gql in dataconnect/connector/mutations.gql.
  2. Fügen Sie die folgenden Mutationen hinzu, um das Markieren von Filmen als Favoriten zu ermöglichen:
## Add a movie to the user's favorites list
mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
}

## Remove a movie from the user's favorites list
mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}

Mutationen mit der Benutzeroberfläche Ihrer App verbinden

Nutzer können einen Film als Favorit markieren, indem sie auf dem Detailbildschirm des Films auf das Herzsymbol klicken.

Damit die gerade erstellten Mutationen mit der Benutzeroberfläche der App verbunden werden, nehmen Sie die folgenden Änderungen in MovieCardView vor:

  1. FriendlyFlixSDK importieren und Connector einrichten
import NukeUI
import os
import SwiftUI
import FirebaseDataConnect
import FriendlyFlixSDK

struct MovieCardView: View {
  private let logger = Logger(subsystem: "FriendlyFlix", category: "moviecard")
  @Environment(\.dismiss) private var dismiss
  private var connector = DataConnect.friendlyFlixConnector

  ...
}
  1. Implementieren Sie die Methode toggleFavourite. Sie wird immer aufgerufen, wenn der Nutzer in MovieCardView auf das Herzsymbol tippt:
struct MovieCardView {

  ...

  private func toggleFavourite() {
    Task {
      if isFavourite {
        let _ = try await connector.deleteFavoritedMovieMutation.execute(movieId: movie.id)
      } else {
        let _ = try await connector.addFavoritedMovieMutation.execute(movieId: movie.id)
      }
    }
  }
}

Dadurch wird der Favoritenstatus des aktuellen Films in der Datenbank aktualisiert. Ein letzter Schritt fehlt noch: Der UI-Status muss entsprechend aktualisiert werden.

Abfrage definieren, um herauszufinden, ob ein Film als Favorit markiert ist

  1. Öffnen Sie in VS Code queries.gql in dataconnect/connector.
  2. Fügen Sie die folgende Abfrage hinzu, um zu prüfen, ob ein Film als Favorit markiert ist:
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
    movieId
  }
}
  1. Instanziieren Sie in Xcode eine Referenz auf die GetIfFavoritedMovie-Abfrage und implementieren Sie die berechnete Eigenschaft, die bestimmt, ob der auf dieser MovieCardView angezeigte Film für den aktuellen Nutzer als Favorit markiert ist.
struct MovieCardView: View {

  ...

  public init(showDetails: Bool, movie: Movie) {
    self.showDetails = showDetails
    self.movie = movie

    isFavouriteRef = connector.getIfFavoritedMovieQuery.ref(movieId: movie.id)
  }

  // MARK: - Favourite handling

  private let isFavouriteRef: QueryRefObservation<
    GetIfFavoritedMovieQuery.Data,
    GetIfFavoritedMovieQuery.Variables
  >
  private var isFavourite: Bool {
    isFavouriteRef.data?.favorite_movie?.movieId != nil
  }

  ...

}
  1. Aktualisieren Sie den Code in toggleFavourite, damit die Abfrage ausgeführt wird, wenn der Nutzer auf die Schaltfläche tippt. So wird sichergestellt, dass die berechnete Property isFavourite immer den richtigen Wert zurückgibt.
  private func toggleFavourite() {
    Task {
      if isFavourite {
        ...
      }

      let _ = try await isFavouriteRef.execute()
    }
  }

Lieblingsfilme abrufen

Als letzten Schritt für diese Funktion müssen Sie die Lieblingsfilme des Nutzers abrufen, damit er sie auf seiner Watchlist sehen kann.

  1. Öffnen Sie in VS Code queries.gql in dataconnect/connector/queries.gql und fügen Sie die folgende Abfrage ein:
## Get favorite movies by user ID
query GetUserFavoriteMovies @auth(level: USER) {
  user(id_expr: "auth.uid") {
    favoriteMovies: favorite_movies_on_user {
      movie {
        id
        title
        genre
        imageUrl
        releaseYear
        rating
        description
      }
    }
  }
}

Die Liste der Lieblingsfilme des Nutzers wird auf der LibraryScreen angezeigt. Auf diesem Bildschirm sollten nur Daten angezeigt werden, wenn der Nutzer angemeldet ist. Verbinden Sie daher zuerst den Authentifizierungsstatus des Bildschirms mit dem AuthenticationService der App.

  1. Fügen Sie Code hinzu, um FavoriteMovieFavoriteMovies, Movie und Movie+DataConnect.swift zuzuordnen:
import FirebaseDataConnect
import FriendlyFlixSDK

extension Movie {

  ...

  init(from: GetUserFavoriteMoviesQuery.Data.User.FavoriteMovieFavoriteMovies) {
    id = from.movie.id
    title = from.movie.title
    description = from.movie.description ?? ""
    releaseYear = from.movie.releaseYear
    rating = from.movie.rating
    imageUrl = from.movie.imageUrl
  }
}
  1. Öffnen Sie in Xcode LibraryScreen und aktualisieren Sie isSignedIn so:
struct LibraryScreen: View {
  ...

  private var isSignedIn: Bool {
    authenticationService.user != nil
  }

}
  1. Importieren Sie dann Firebase Data Connect und FriendlyFlixSDK und rufen Sie eine Referenz auf die GetUserFavoriteMovies-Abfrage ab:
import SwiftUI
import FirebaseDataConnect
import FriendlyFlixSDK

struct LibraryScreen {

 ...

  private var connector = DataConnect.friendlyFlixConnector

  ...

  init() {
    watchListRef = connector.getUserFavoriteMoviesQuery.ref()
  }

  private let watchListRef: QueryRefObservation<
    GetUserFavoriteMoviesQuery.Data,
    GetUserFavoriteMoviesQuery.Variables
  >
  private var watchList: [Movie] {
    watchListRef.data?.user?.favoriteMovies.map(Movie.init) ?? []
  }

  ...

}


  1. Prüfen Sie, ob die watchListRef-Abfrage ausgeführt wird, wenn die Ansicht angezeigt wird:
extension LibraryScreen: View {
  var body: some View {
    ...
            MovieListSection(namespace: namespace, title: "Watch List", movies: watchList)
              .onAppear {
                Task {
                  try await watchListRef.execute()
                }
  ...

Demo

Sie können die App jetzt ausführen und die gerade implementierte Favoritenfunktion ausprobieren. Beachten Sie Folgendes:

  • Prüfen, ob der Firebase-Emulator ausgeführt wird
  • Achten Sie darauf, dass Sie Mock-Daten für die Filme und Filmdetails hinzugefügt haben.
  • Sie müssen sich als Nutzer registriert haben.
  1. Klicken Sie in Xcode auf die Schaltfläche Run (Ausführen), um die App im iOS-Simulator zu starten.
  2. Tippe nach dem Starten der App auf eine Filmkarte, um die Filmdetails aufzurufen.
  3. Tippe auf das Herzsymbol, um den Film als Favorit zu markieren. Das Herz sollte durchgehend gefüllt sein.
  4. Wiederhole diesen Vorgang für einige Filme.
  5. Gehe zum Tab „Mediathek“. Sie sollten jetzt eine Liste aller Filme sehen, die Sie als Favoriten markiert haben.

10. Glückwunsch

Herzlichen Glückwunsch, Sie haben Firebase Data Connect erfolgreich zu einer iOS-App hinzugefügt. Sie kennen nun die wichtigsten Schritte, die zum Einrichten von Data Connect, zum Erstellen von Abfragen und Mutationen sowie zum Verarbeiten der Nutzerauthentifizierung erforderlich sind.

Optional: In der Produktion bereitstellen

Bisher wurden in dieser App nur die Firebase-Emulatoren verwendet. Wenn Sie wissen möchten, wie Sie diese App in einem echten Firebase-Projekt bereitstellen, fahren Sie mit dem nächsten Schritt fort.

11. (Optional) Anwendung bereitstellen

Bisher war diese App vollständig lokal. Alle Daten sind in der Firebase Emulator Suite enthalten. In diesem Abschnitt erfahren Sie, wie Sie Ihr Firebase-Projekt so konfigurieren, dass diese App in der Produktion funktioniert.

Firebase Authentication aktivieren

  1. Rufen Sie in der Firebase Console den Abschnitt Authentifizierung auf und klicken Sie auf Jetzt starten.
  2. Rufen Sie den Tab Anmeldemethode auf .
  3. Wählen Sie im Bereich „Native Anbieter“ die Option „E-Mail/Passwort“ aus.
  4. Aktivieren Sie den Anbieter für E-Mail-Adresse/Passwort und klicken Sie dann auf Speichern.

Firebase Data Connect aktivieren

Wichtig: Wenn Sie zum ersten Mal ein Schema in Ihrem Projekt bereitstellen, wird bei diesem Vorgang eine Cloud SQL for PostgreSQL-Instanz erstellt. Das kann etwa 15 Minuten dauern. Sie können die Funktion erst bereitstellen, wenn die Cloud SQL-Instanz bereit und in Firebase Data Connect eingebunden ist.

1. Klicken Sie in der Benutzeroberfläche der VS Code-Erweiterung „Firebase Data Connect“ auf Deploy to production (In Produktion bereitstellen). 2. Möglicherweise müssen Sie Schemaänderungen überprüfen und potenziell destruktive Änderungen genehmigen. Sie werden aufgefordert, - Schemaänderungen mit firebase dataconnect:sql:diff zu prüfen. - Wenn Sie mit den Änderungen zufrieden sind, wenden Sie sie mit dem von firebase dataconnect:sql:migrate gestarteten Ablauf an.

Ihre Cloud SQL for PostgreSQL-Instanz wird mit dem endgültigen bereitgestellten Schema und den endgültigen bereitgestellten Daten aktualisiert. Sie können den Status in der Firebase Console überwachen.

Klicken Sie nun im Bereich „Firebase Data Connect“ auf „Ausführen (Produktion)“, um Daten in die Produktionsumgebung einzufügen.

Bevor Sie die iOS-App noch einmal ausführen, müssen Sie dafür sorgen, dass sie mit der Produktionsinstanz Ihres Projekts verbunden ist:

  1. Öffnen Sie das Menü Produkt > Schema > Schema bearbeiten….
  2. Entfernen Sie im Bereich Ausführen das Häkchen für das Startargument -useEmulator YES.