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 App für Filmbewertungen für iOS zu erstellen.

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

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

Lerninhalte

In diesem Codelab lernen Sie Folgendes:

  • Richten Sie Firebase Data Connect mit der Firebase Emulator Suite ein, um schnell loszulegen.
  • Entwerfen Sie ein Datenbankschema mit Data Connect und GraphQL.
  • Erstellen Sie ein typsicheres Swift SDK aus Ihrem Datenbankschema und fügen Sie es einer Swift-Anwendung hinzu.
  • Implementieren Sie die Nutzerauthentifizierung und integrieren Sie sie in Firebase Data Connect, um die Daten Ihrer Nutzer zu schützen.
  • Mithilfe von Abfragen und Mutationen, die auf GraphQL basieren, können Sie Daten in Cloud SQL abrufen, aktualisieren, löschen und verwalten.
  • Optional: Bereitstellen eines Data Connect-Dienstes in der Produktion.

Vorbereitung

  • Die neueste Version von Xcode
  • Der Beispielcode des Codelabs 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 in der Firebase Console auf Firebase-Projekt erstellen.
  3. Geben Sie einen Namen für Ihr Firebase-Projekt ein (z. B. „Friendly Flix“) und klicken Sie auf Weiter.
  4. Sie werden möglicherweise aufgefordert, die KI-Unterstützung für Ihr Firebase-Projekt zu aktivieren. Für dieses Codelab spielt Ihre Auswahl keine Rolle.
  5. Möglicherweise werden Sie aufgefordert, Google Analytics zu aktivieren. Für dieses Codelab spielt Ihre Auswahl keine Rolle.
  6. Nach etwa einer Minute ist Ihr Firebase-Projekt bereit. Klicken Sie 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/peterfriese/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 mehrmals auf Weiter, um das Einrichtungsprojekt in der Firebase Console abzuschließen. Sie müssen der App das SDK nicht hinzufügen, da dies bereits im Starterprojekt für Sie erledigt wurde.
  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 Script versucht, die Entwicklungsumgebung für Sie einzurichten und eine browserbasierte IDE zu starten. Diese IDE bietet Tools, einschließlich einer vorkonfigurierten VS Code-Erweiterung, mit denen Sie Ihr Schema verwalten, Abfragen und Mutationen für Ihre Anwendung definieren und stark typisierte SDKs generieren können.

Nach dem Ausführen des Scripts 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. Node.js installieren
  3. Öffnen Sie in VS Code das Verzeichnis codelab-dataconnect-ios/FriendlyFlix.
  4. Installieren Sie die Firebase Data Connect-Erweiterung aus dem 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 verbinden 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 bedeutet:

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

Nachdem Sie diese Datei gespeichert haben, 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 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>

Das generierte Paket Ihrer Swift-App hinzufügen

  1. FriendlyFlix/app/FriendlyFlix/FriendlyFlix.xcodeproj in Xcode öffnen
  2. Wählen Sie Datei > Paketabhängigkeiten hinzufügen… aus.
  3. Klicken Sie auf Lokales hinzufügen… und fügen Sie das FriendlyFlixSDK-Paket aus dem Ordner FriendlyFlix/app hinzu.
  4. Warten Sie, bis Xcode die Paketabhängigkeiten aufgelöst hat.
  5. Wähle im Dialogfeld Choose Package Products for FriendlyFlixSDK (Paketprodukte für FriendlyFlixSDK auswählen) FriendlyFlix als Ziel aus und klicke 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 + Umschalttaste + 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 die Tastenkombination CMD+R (oder klicken Sie auf die Schaltfläche Ausführen), um die App in einem Simulator auszuführen.

4. Schema definieren und Datenbank vorab befüllen

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

Wichtige Entitäten und Beziehungen

Das Datenmodell für diese Film-Tracker-App besteht aus mehreren Entitäten, die Sie im Laufe dieses Codelabs erstellen. Sie erstellen zuerst die Hauptentitäten und fügen nach und nach die für die einzelnen Funktionen erforderlichen Entitäten hinzu.

In diesem Schritt erstellen Sie die Typen Movie und MovieMetadata.

Film

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

Fügen Sie in VS Code dataconnect/schema/schema.gql die Typdefinition Movie 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 Eins-zu-eins-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. Beispielsweise wird das Feld id vom Typ Movie beim Erstellen eines neuen Eintrags automatisch mit einer UUID ausgefüllt.

Mock-Daten für Filme und Filmmetadaten einfügen

Nachdem Sie das Schema definiert haben, können Sie die Datenbank jetzt mit Testdaten füllen.

  1. Kopieren Sie finish/FriendlyFlix/dataconnect/moviedata_insert.gql im Finder 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 Ausführen (lokal) angezeigt werden. Klicken Sie darauf, um die simulierten Filmdaten 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 importiert 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 lernen 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 die id für die SwiftUI-Ansichtsidentität.

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

Klicken Sie zum Testen der neuen Abfrage auf die Schaltfläche Ausführen (lokal), um die Abfrage in Ihrer lokalen Datenbank auszuführen. Die Liste der Filme aus der Datenbank sollte im Bereich Ergebnisse des Data Connect Execution-Terminals angezeigt werden.

Die Abfrage „ListMovies“ mit dem Startbildschirm der App verknüpfen

Nachdem Sie die Abfrage im Data Connect-Emulator getestet haben, können Sie sie von Ihrer App aus 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 zu 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 Abfrage listMoviesQuery() 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 Ausführen, um die App im iOS-Simulator zu starten.

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

Sie werden feststellen, dass in allen Bereichen der App (Hero-Bereich, Top-Filme und Merkliste) dieselbe Liste angezeigt wird. 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 zu aktualisieren – das ist das auffällige Karussell oben auf dem Startbildschirm – und auch im Bereich „Top-Filme“ unten.

Derzeit werden mit der Abfrage „ListMovies“ alle Filme abgerufen. Um die Darstellung für diese Bereiche zu optimieren, begrenzen Sie die Anzahl der Filme, die bei jeder Abfrage zurückgegeben werden. Die aktuelle Implementierung der ListMovies-Abfrage bietet noch keine integrierte Unterstützung für die Begrenzung von Ergebnissen. In diesem Abschnitt fügen Sie die Unterstützung für die Begrenzung und Sortierung hinzu.

ListMovies-Abfrage verbessern

Öffnen Sie queries.gql und aktualisieren Sie ListMovies so, dass die Sortierung und Begrenzung unterstützt 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 begrenzen, die von der Abfrage zurückgegeben werden, und den Ergebnissatz sowohl nach Altersfreigabe als auch nach Erscheinungsjahr sortieren.

Nachdem Sie diese Datei gespeichert haben, wird der Code innerhalb von 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.

Aktualisiere 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 Abfragereferenz für die Top-Filme ein und legen Sie den Filter auf die fünf Filme mit der höchsten Bewertung 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 abschließend das berechnete Attribut, das das Ergebnis dieser Abfrage mit der Benutzeroberfläche verbindet:

extension HomeScreen {
  ...

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

}

Beispiele ansehen

Starten Sie die App noch einmal, um die drei neuesten Filme im Hero-Bereich und die fünf bestbewerteten Filme im Bereich „Top-Filme“ zu sehen:

7. Film- und Schauspielerdetails anzeigen

Der Nutzer kann jetzt Filme durchsuchen. Wenn du auf eine Filmkarte tippst, werden dir einige Details zum Film angezeigt. Du hast aber vielleicht schon bemerkt, dass diese Details nicht wirklich detailliert sind.

Das liegt daran, dass wir nur so viele Details zu jedem Film abgerufen haben, wie für die Darstellung des Hero-Bereichs und des Bereichs „Top-Filme“ erforderlich waren: den Filmtitel, eine kurze Beschreibung und die Bild-URL.

Auf der Detailseite des Films möchten wir weitere Informationen zum Film anzeigen. In diesem Abschnitt erweitern Sie die App, damit auf der Detailseite die Schauspieler des Films und alle Rezensionen angezeigt werden können.

Dazu sind einige Schritte erforderlich:

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

Schema optimieren

Öffnen Sie dataconnect/schema/schema.gql in VS Code 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"
}

Mock-Daten für Nutzer hinzufügen

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

  1. Kopieren Sie finish/FriendlyFlix/dataconnect/moviededetails_insert.gql im Finder 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 Ausführen (lokal) angezeigt werden. Klicken Sie darauf, um die simulierten Filmdaten in Ihre Datenbank einzufügen.
  5. Prüfen Sie im Terminal für die Ausführung von Data Connect, ob die Daten erfolgreich hinzugefügt wurden.

Nachdem Sie die Daten zusammengestellt haben, fahren Sie mit dem nächsten Schritt fort, um die Abfrage zu definieren, mit der die Filmdetails abgerufen werden sollen.

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 Datenansicht „MovieDetailsView“ verknüpfen

Öffnen Sie in Xcode die Datei MovieDetailsView.swift und aktualisieren Sie die berechnete Eigenschaft movieDetails so, dass sie dem folgenden Code entspricht:

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 Ausführen, um die App im iOS-Simulator zu starten.

Tippe nach dem Start 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 erlauben 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 integrieren Sie Firebase Authentication, damit sich Nutzer in der App anmelden können.

Möglicherweise haben Sie die Schaltfläche für den Nutzeravatar bereits oben rechts auf dem Startbildschirm 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.

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

Firebase Authentication aktivieren

Aktivieren Sie in der Firebase Console für Ihr Projekt die Firebase-Authentifizierung. Aktivieren Sie dann den E-Mail-/Passwort-Authentifizierungsanbieter.

Suchen Sie in Ihrem lokalen Projektordner nach firebase.json und aktualisieren Sie es so, dass der Firebase Authentication-Emulator aktiviert wird.

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

Anschließend 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 über 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 hinzu:

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 Authentifizierungs-Handler, mit dem du über onSignUp ein Schließen registrieren kannst, das aufgerufen wird, wenn sich der Nutzer angemeldet hat.

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

Dem Schema eine Nutzerentität hinzufügen

Der Typ User definiert eine Nutzerentität. Nutzer können mit Filmen interagieren, indem sie Rezensionen verfassen oder Filme zu ihren Favoriten hinzufügen.

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

Nach der Anmeldung einen neuen Nutzer erstellen

Öffnen Sie in Xcode FriendlyFlixApp.swift und fügen Sie der Initialisiererfunktion 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 das für Sie generierte upsertUserMutation Firebase Data Connect verwendet, um einen neuen Nutzer einzufügen oder einen vorhandenen Nutzer mit derselben ID zu aktualisieren, wenn sich ein Nutzer mit Firebase Authentication erfolgreich registriert hat.

Beispiele ansehen

Melden Sie sich zuerst in der iOS-App an, um zu prüfen, ob das funktioniert:

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

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

  • Öffnen Sie in VS Code dataconnect/schema/schema.gql und klicken Sie bei der Entität User 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 Filmbewertungs-App, damit Nutzer ihre Lieblingsfilme verwalten können. Als Favoriten markierte Filme werden in der App im Bereich „Merkliste“ angezeigt.

Schema für die Unterstützung von Favoriten erweitern

Der Typ FavoriteMovie ist eine Join-Tabelle, die Mehrfachbeziehungen zwischen Nutzern und ihren Lieblingsfilmen verarbeitet. Jede Tabelle verknüpft eine User mit einer Movie.

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 er angeben, welche Filme das sind. Dazu müssen Sie zuerst zwei Mutationen hinzufügen, um einen Film als einen der Favoriten des Nutzers zu kennzeichnen 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 Filme zu den Favoriten hinzuzufügen:
## 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 verknüpfen

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

Um die von Ihnen erstellten Mutationen mit der Benutzeroberfläche der App zu verknüpfen, nehmen Sie in MovieCardView die folgenden Änderungen 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 aufgerufen, wenn der Nutzer in der 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: Sie müssen dafür sorgen, dass der UI-Status entsprechend widergespiegelt wird.

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

  1. Öffnen Sie in VS Code queries.gql in dataconnect/connector.
  2. Füge 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. Erstelle in Xcode eine Referenz auf die GetIfFavoritedMovie-Abfrage und implementiere die berechnete Eigenschaft, die angibt, ob der in 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 jedes Mal 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 implementieren Sie das Abrufen der Lieblingsfilme der Nutzer, damit sie diese auf ihrer Merkliste sehen können.

  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. Sie verbinden daher zuerst den Authentifizierungsstatus des Bildschirms mit der AuthenticationService der App.

  1. Fügen Sie Code hinzu, um von FavoriteMovieFavoriteMovies nach Movie und dann nach 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 dann isSignedIn so:
struct LibraryScreen: View {
  ...

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

}
  1. Importiere dann Firebase Data Connect und FriendlyFlixSDK und erhalte eine Referenz auf die GetUserFavoriteMovies-Abfrage:
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. Achten Sie darauf, dass 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()
                }
  ...

Beispiele ansehen

Sie können jetzt die App ausführen und die gerade implementierte Favoritenfunktion ausprobieren. Beachten Sie dabei 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 Ausführen, um die App im iOS-Simulator zu starten.
  2. Tippe nach dem Start der App auf eine Filmkarte, um die Filmdetails aufzurufen.
  3. Tippe auf das Herzsymbol, um den Film als Favoriten zu markieren. Das Herz sollte jetzt durchgehend angezeigt werden.
  4. Wiederholen Sie diesen Vorgang für einige Filme.
  5. Rufe den Tab „Mediathek“ auf. Es sollte jetzt eine Liste aller Filme angezeigt werden, die du als Favoriten markiert hast.

10. Glückwunsch

Herzlichen Glückwunsch, Sie haben Firebase Data Connect einer iOS-App hinzugefügt. Sie wissen jetzt, wie Sie Data Connect einrichten, Abfragen und Mutationen erstellen und die Nutzerauthentifizierung verarbeiten.

Optional: Für Produktion bereitstellen

Bisher wurden für diese 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 und alle Daten befinden sich in der Firebase Emulator Suite. In diesem Abschnitt erfahren Sie, wie Sie Ihr Firebase-Projekt so konfigurieren, dass diese App in der Produktion funktioniert.

Firebase Authentication aktivieren

  1. Klicken Sie in der Firebase Console im Bereich Authentifizierung 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 dabei eine Cloud SQL-PostgreSQL-Instanz erstellt. Das kann etwa 15 Minuten dauern. Sie können erst dann eine Bereitstellung vornehmen, wenn die Cloud SQL-Instanz bereit ist und mit Firebase Data Connect verknüpft wurde.

1. Klicken Sie in der Benutzeroberfläche der VS Code-Erweiterung für Firebase Data Connect auf In Produktion bereitstellen. 2. Möglicherweise müssen Sie Schemaänderungen prüfen und potenziell schädliche Änderungen genehmigen. Sie werden aufgefordert, Folgendes zu tun:firebase dataconnect:sql:difffirebase dataconnect:sql:migrate

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

Klicken Sie jetzt im Bereich „Firebase Data Connect“ auf „Ausführen (Produktion)“, genau wie bei den lokalen Emulatoren, um der Produktionsumgebung Daten hinzuzufügen.

Bevor Sie die iOS-App wieder ausführen, prüfen Sie, ob eine Verbindung zur Produktionsinstanz Ihres Projekts besteht:

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