1. Hinweis
In diesem Codelab erfahren Sie, wie Sie Ihrer Flutter-App mit dem FlutterFire UI-Paket die Firebase-Authentifizierung hinzufügen. Mit diesem Paket fügen Sie einer Flutter-App sowohl die E-Mail- und Passwort-Authentifizierung als auch die Google Sign-In-Authentifizierung hinzu. Außerdem erfahren Sie, wie Sie ein Firebase-Projekt einrichten und Firebase mit der FlutterFire CLI in Ihrer Flutter-App initialisieren.
Vorbereitung
In diesem Codelab wird davon ausgegangen, dass Sie bereits Erfahrung mit Flutter haben. Falls nicht, sollten Sie sich zuerst mit den Grundlagen vertraut machen. Die folgenden Links sind hilfreich:
- Flutter-Widget-Framework kennenlernen
- Codelab Erste Flutter-App erstellen – Teil 1 ausprobieren
Sie sollten auch einige Erfahrungen mit Firebase haben. Es ist aber in Ordnung, wenn Sie noch nie Firebase zu einem Flutter-Projekt hinzugefügt haben. Wenn Sie mit der Firebase Console nicht vertraut sind oder Firebase noch nicht kennen, sehen Sie sich zuerst die folgenden Links an:
Was du erstellen wirst
In diesem Codelab erfahren Sie, wie Sie mit Firebase Authentication den Authentifizierungsablauf für eine Flutter-App erstellen. Die Anwendung hat einen Anmeldebildschirm, einen Registrierungsbildschirm, einen Bildschirm zur Passwortwiederherstellung und einen Bildschirm für das Nutzerprofil.
Lerninhalte
In diesem Codelab werden folgende Themen behandelt:
- Firebase zu einer Flutter-App hinzufügen
- Firebase Console einrichten
- Firebase mit der Firebase CLI Ihrer Anwendung hinzufügen
- Firebase-Konfiguration in Dart mit der FlutterFire CLI generieren
- Firebase-Authentifizierung zu Ihrer Flutter-App hinzufügen
- Firebase Authentication in der Console einrichten
- Anmeldung per E-Mail-Adresse und Passwort mit dem
firebase_ui_auth
-Paket hinzufügen - Nutzerregistrierung mit dem
firebase_ui_auth
-Paket hinzufügen - Seite „Passwort vergessen?“ hinzufügen
- Google Log-in mit
firebase_ui_auth
hinzufügen - Ihre App für die Verwendung mit mehreren Anmeldeanbietern konfigurieren
- Mit dem
firebase_ui_auth
-Paket Ihrer Anwendung einen Bildschirm für das Nutzerprofil hinzufügen
In diesem Codelab geht es speziell darum, ein robustes Authentifizierungssystem mit dem firebase_ui_auth
-Paket hinzuzufügen. Wie Sie sehen, kann diese gesamte App mit allen oben genannten Funktionen mit etwa 100 Codezeilen implementiert werden.
Voraussetzungen
- Grundkenntnisse in Flutter und das installierte SDK
- Einen Texteditor (JetBrains IDEs, Android Studio und VS Code werden von Flutter unterstützt)
- Google Chrome-Browser oder Ihr bevorzugtes Entwicklungsziel für Flutter Bei einigen Terminalbefehlen in diesem Codelab wird davon ausgegangen, dass Sie Ihre App in Chrome ausführen.
2. Firebase-Projekt erstellen und einrichten
Als Erstes müssen Sie ein Firebase-Projekt in der Firebase Web Console erstellen.
Firebase-Projekt erstellen
- Melden Sie sich in Firebase an.
- Klicken Sie in der Firebase Console auf Projekt hinzufügen (oder Projekt erstellen) und geben Sie einen Namen für Ihr Firebase-Projekt ein, z. B. FlutterFire-UI-Codelab.
- Klicken Sie sich durch die Optionen für die Projekterstellung. Akzeptieren Sie die Firebase-Nutzungsbedingungen, wenn Sie dazu aufgefordert werden. Überspringen Sie die Einrichtung von Google Analytics, da Sie Analytics für diese App nicht verwenden werden.
Weitere Informationen zu Firebase-Projekten finden Sie unter Firebase-Projekte.
E-Mail-Anmeldung für Firebase Authentication aktivieren
In der von Ihnen erstellten App können sich Nutzer mit Firebase Authentication anmelden. Außerdem können sich neue Nutzer über die Flutter-Anwendung registrieren.
Firebase Authentication muss in der Firebase Console aktiviert und anschließend speziell konfiguriert werden.
Damit Nutzer sich in der Web-App anmelden können, verwenden Sie zuerst die Anmeldemethode E-Mail/Passwort. Später fügen Sie die Methode Google-Anmeldung hinzu.
- Maximieren Sie in der Firebase Console im linken Bereich das Menü Build.
- Klicken Sie auf Authentifizierung, dann auf die Schaltfläche Jetzt starten und dann auf den Tab Anmeldemethode. Sie können auch direkt zum Tab Anmeldemethode wechseln.
- Klicken Sie in der Liste Anbieter für Anmeldungen auf E-Mail-Adresse/Passwort, aktivieren Sie den Schalter Aktivieren und klicken Sie dann auf Speichern.
3. Flutter-App einrichten
Sie müssen den Startercode herunterladen und die Firebase CLI installieren, bevor wir beginnen.
Startcode abrufen
Klonen Sie das GitHub-Repository über die Befehlszeile:
git clone https://github.com/flutter/codelabs.git flutter-codelabs
Alternativ können Sie das Befehlszeilentool von GitHub verwenden:
gh repo clone flutter/codelabs flutter-codelabs
Der Beispielcode sollte in das Verzeichnis flutter-codelabs
auf Ihrem Computer geklont werden, das den Code für eine Sammlung von Codelabs enthält. Der Code für dieses Codelab befindet sich im Unterverzeichnis flutter-codelabs/firebase-auth-flutterfire-ui
.
Das Verzeichnis flutter-codelabs/firebase-auth-flutterfire-ui
enthält zwei Flutter-Projekte. Eine heißt complete
und die andere start
. Das Verzeichnis start
enthält ein unvollständiges Projekt. Hier verbringen Sie die meiste Zeit.
cd flutter-codelabs/firebase-auth-flutterfire-ui/start
Wenn Sie vorspulen oder sehen möchten, wie etwas fertig aussehen sollte, sehen Sie sich das Verzeichnis „complete“ an.
Wenn Sie dem Codelab folgen und selbst Code hinzufügen möchten, sollten Sie mit der Flutter-App unter flutter-codelabs/firebase-auth-flutterfire-ui/start
beginnen und dem Projekt im Laufe des Codelabs Code hinzufügen. Öffnen Sie dieses Verzeichnis oder importieren Sie es in Ihre bevorzugte IDE.
Firebase CLI installieren
Die Firebase CLI bietet Tools zum Verwalten Ihrer Firebase-Projekte. Die Befehlszeile ist für die FlutterFire CLI erforderlich, die Sie gleich installieren.
Es gibt verschiedene Möglichkeiten, die Befehlszeile zu installieren. Eine Liste aller verfügbaren Optionen für Ihr Betriebssystem finden Sie unter firebase.google.com/docs/cli.
Nach der Installation der Befehlszeile müssen Sie sich bei Firebase authentifizieren.
- Melden Sie sich mit Ihrem Google-Konto in Firebase an. Führen Sie dazu den folgenden Befehl aus:
firebase login
- Mit diesem Befehl wird Ihr lokaler Computer mit Firebase verbunden und Sie erhalten Zugriff auf Ihre Firebase-Projekte.
- Prüfen Sie, ob die Befehlszeile richtig installiert ist und Zugriff auf Ihr Konto hat, indem Sie Ihre Firebase-Projekte auflisten. Führen Sie dazu diesen Befehl aus:
firebase projects:list
- Die angezeigte Liste sollte mit den Firebase-Projekten in der Firebase Console übereinstimmen. Sie sollten mindestens
flutterfire-ui-codelab.
FlutterFire CLI installieren
Die FlutterFire CLI ist ein Tool, mit dem Sie die Installation von Firebase auf allen unterstützten Plattformen in Ihrer Flutter-App vereinfachen können. Sie basiert auf der Firebase CLI.
Installieren Sie zuerst die Befehlszeile:
dart pub global activate flutterfire_cli
Prüfen Sie, ob die Befehlszeile installiert wurde. Führen Sie den folgenden Befehl aus und prüfen Sie, ob die Befehlszeile das Hilfemenü ausgibt.
flutterfire --help
Firebase-Projekt Ihrer Flutter-App hinzufügen
FlutterFire konfigurieren
Mit FlutterFire können Sie den erforderlichen Dart-Code generieren, um Firebase in Ihrer Flutter-App zu verwenden.
flutterfire configure
Wenn Sie diesen Befehl ausführen, werden Sie aufgefordert, auszuwählen, welches Firebase-Projekt Sie verwenden und welche Plattformen Sie einrichten möchten.
Die folgenden Screenshots zeigen die Prompts, die Sie beantworten müssen.
- Wählen Sie das Projekt aus, das Sie verwenden möchten. Verwenden Sie in diesem Fall
flutterfire-ui-codelab
.
- Wählen Sie die Plattformen aus, die Sie verwenden möchten. In diesem Codelab finden Sie Schritte zum Konfigurieren der Firebase-Authentifizierung für Flutter für Web, iOS und Android. Sie können Ihr Firebase-Projekt jedoch so einrichten, dass alle Optionen verwendet werden.
- Auf diesem Screenshot ist die Ausgabe am Ende des Prozesses zu sehen. Wenn Sie mit Firebase vertraut sind, werden Sie feststellen, dass Sie keine Plattformanwendungen (z. B. eine Android-Anwendung) in der Console erstellen mussten, sondern dass die FlutterFire-Befehlszeile dies für Sie erledigt hat.
Wenn Sie fertig sind, sehen Sie sich die Flutter-App in Ihrem Texteditor an. Die FlutterFire-Befehlszeile hat eine Datei namens firebase_options.dart
geändert. Diese Datei enthält eine Klasse namens FirebaseOptions
mit statischen Variablen, die die für jede Plattform erforderliche Firebase-Konfiguration enthalten. Wenn Sie beim Ausführen von flutterfire configure
alle Plattformen ausgewählt haben, sehen Sie die statischen Werte web
, android
, ios
und macos
.
lib/firebase_options.dart
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyCqFjCV_9CZmYeIvcK9FVy4drmKUlSaIWY',
appId: '1:963656261848:web:7219f7fca5fc70afb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
authDomain: 'flutterfire-ui-codelab.firebaseapp.com',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
measurementId: 'G-DGF0CP099H',
);
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyDconZaCQpkxIJ5KQBF-3tEU0rxYsLkIe8',
appId: '1:963656261848:android:c939ccc86ab2dcdbb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
iosBundleId: 'com.example.complete',
);
static const FirebaseOptions macos = FirebaseOptions(
apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
iosBundleId: 'com.example.complete',
);
}
In Firebase bezieht sich das Wort „Anwendung“ auf einen bestimmten Build für eine bestimmte Plattform in einem Firebase-Projekt. Das Firebase-Projekt FlutterFire-ui-codelab enthält beispielsweise mehrere Anwendungen: eine für Android, eine für iOS, eine für macOS und eine für das Web.
Die Methode DefaultFirebaseOptions.currentPlatform
verwendet das von Flutter bereitgestellte TargetPlatform
-Enum, um die Plattform zu ermitteln, auf der Ihre App ausgeführt wird, und gibt dann die Firebase-Konfigurationswerte zurück, die für die richtige Firebase-Anwendung erforderlich sind.
Firebase-Pakete zur Flutter-App hinzufügen
Im letzten Einrichtungsschritt fügen Sie Ihrem Flutter-Projekt die relevanten Firebase-Pakete hinzu. Die Datei firebase_options.dart
sollte Fehler enthalten, da sie auf Firebase-Paketen basiert, die noch nicht hinzugefügt wurden. Achten Sie darauf, dass Sie sich im Stammverzeichnis des Flutter-Projekts unter flutter-codelabs/firebase-emulator-suite/start
befinden. Führen Sie dann die drei folgenden Befehle aus:
flutter pub add firebase_core firebase_auth firebase_ui_auth
Das sind die einzigen Pakete, die Sie derzeit benötigen.
Firebase initialisieren
Um die hinzugefügten Pakete und DefaultFirebaseOptions.currentPlatform,
zu verwenden, aktualisieren Sie den Code in der Funktion main
in der Datei main.dart
.
lib/main.dart
import 'package:firebase_core/firebase_core.dart'; // Add this import
import 'package:flutter/material.dart';
import 'app.dart';
import 'firebase_options.dart'; // And this import
// TODO(codelab user): Get API key
const clientId = 'YOUR_CLIENT_ID';
void main() async {
// Add from here...
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
// To here.
runApp(const MyApp(clientId: clientId));
}
Dieser Code hat zwei Funktionen.
WidgetsFlutterBinding.ensureInitialized()
weist Flutter an, den Code des Anwendungs-Widgets erst auszuführen, wenn das Flutter-Framework vollständig gestartet wurde. Firebase verwendet native Plattformkanäle, für die das Framework ausgeführt werden muss.Firebase.initializeApp
richtet eine Verbindung zwischen Ihrer Flutter-App und Ihrem Firebase-Projekt ein. DieDefaultFirebaseOptions.currentPlatform
wird aus der generiertenfirebase_options.dart
-Datei importiert. Anhand dieses statischen Werts wird erkannt, auf welcher Plattform Sie die App ausführen, und die entsprechenden Firebase-Schlüssel werden übergeben.
4. Erste Firebase UI-Authentifizierungsseite hinzufügen
Firebase UI for Auth bietet Widgets, die ganze Bildschirme in Ihrer Anwendung darstellen. Auf diesen Bildschirmen werden verschiedene Authentifizierungsabläufe in Ihrer Anwendung verarbeitet, z. B. Anmeldung, Registrierung, Passwort vergessen und Nutzerprofil. Fügen Sie Ihrer App zuerst eine Landingpage hinzu, die als Authentifizierungsschutz für die Hauptanwendung dient.
Material- oder Cupertino-App
Für die FlutterFire-Benutzeroberfläche muss Ihre Anwendung in MaterialApp
oder CupertinoApp
eingewickelt sein. Je nach Auswahl werden die Unterschiede zwischen Material- und Cupertino-Widgets automatisch in der Benutzeroberfläche berücksichtigt. Verwenden Sie für dieses Codelab MaterialApp
, das der App in app.dart
bereits hinzugefügt wurde.
lib/app.dart
import 'package:flutter/material.dart';
import 'auth_gate.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: AuthGate(clientId: clientId),
);
}
}
Authentifizierungsstatus prüfen
Bevor Sie einen Anmeldebildschirm anzeigen können, müssen Sie feststellen, ob der Nutzer authentifiziert ist. Am einfachsten kannst du das mit dem Firebase Auth-Plug-in prüfen.FirebaseAuth
authStateChanges
Im Codebeispiel oben erstellt MaterialApp
in der Methode build
ein AuthGate
-Widget. (Dies ist ein benutzerdefiniertes Widget, das nicht von der FlutterFire-Benutzeroberfläche bereitgestellt wird.)
Dieses Widget muss aktualisiert werden, um den authStateChanges
-Stream einzubinden.
Die authStateChanges
API gibt einen Stream
mit dem aktuellen Nutzer zurück (falls er angemeldet ist) oder „null“, wenn er nicht angemeldet ist. Um diesen Status in unserer Anwendung zu abonnieren, können Sie das StreamBuilder-Widget von Flutter verwenden und den Stream an das Widget übergeben.
StreamBuilder
ist ein Widget, das auf Grundlage des aktuellen Daten-Snapshots aus einem übergebenen Stream erstellt wird. Er wird automatisch neu erstellt, wenn Stream
einen neuen Snapshot ausgibt.
Aktualisieren Sie den Code in auth_gate.dart
.
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider; // Add this import
import 'package:firebase_ui_auth/firebase_ui_auth.dart'; // And this import
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>( // Modify from here...
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(providers: []);
}
return const HomeScreen();
},
); // To here.
}
}
StreamBuilder.stream
wirdFirebaseAuth.instance.authStateChanged
übergeben, der oben genannte Stream, der ein Firebase-User
-Objekt zurückgibt, wenn sich der Nutzer authentifiziert hat, andernfallsnull
.- Als Nächstes wird mit
snapshot.hasData
geprüft, ob der Wert aus dem Stream dasUser
-Objekt enthält. - Andernfalls wird ein
SignInScreen
-Widget zurückgegeben. Im Moment passiert auf diesem Bildschirm noch nichts. Er wird im nächsten Schritt aktualisiert. - Andernfalls wird
HomeScreen
zurückgegeben, der Hauptteil der Anwendung, auf den nur authentifizierte Nutzer zugreifen können.
Das SignInScreen
ist ein Widget aus dem FlutterFire UI-Paket. Darauf konzentrieren wir uns im nächsten Schritt dieses Codelabs. Wenn Sie die App jetzt ausführen, sollte ein leerer Anmeldebildschirm angezeigt werden.
5. Anmeldebildschirm
Das SignInScreen
-Widget von FlutterFire UI bietet folgende Funktionen:
- Ermöglicht die Anmeldung von Nutzern
- Wenn Nutzer ihr Passwort vergessen haben, können sie auf „Passwort vergessen?“ tippen und werden zu einem Formular weitergeleitet, über das sie ihr Passwort zurücksetzen können.
- Wenn ein Nutzer noch nicht registriert ist, kann er auf „Registrieren“ tippen. Daraufhin wird ein anderes Formular geöffnet, über das er sich registrieren kann.
Auch dafür sind nur ein paar Codezeilen erforderlich. Erinnern Sie sich an den Code im AuthGate
-Widget:
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(providers: [EmailAuthProvider()]); // Modify this line
}
return const HomeScreen();
},
);
}
}
Das SignInScreen
-Widget und sein providers
-Argument sind der einzige Code, der für alle oben genannten Funktionen erforderlich ist. Jetzt sollte ein Anmeldebildschirm mit den Textfeldern „E-Mail-Adresse“ und „Passwort“ sowie der Schaltfläche „Anmelden“ angezeigt werden.
Sie ist zwar funktionsfähig, aber es fehlt ihr das gewisse Etwas. Das Widget bietet Parameter, mit denen sich das Aussehen des Anmeldebildschirms anpassen lässt. Sie können beispielsweise das Logo Ihres Unternehmens hinzufügen.
Anmeldebildschirm anpassen
headerBuilder
Mit dem Argument SignInScreen.headerBuilder
können Sie beliebige Widgets über dem Anmeldeformular hinzufügen. Dieses Widget wird nur auf schmalen Bildschirmen wie Mobilgeräten angezeigt. Auf breiten Bildschirmen können Sie SignInScreen.sideBuilder
verwenden, was später in diesem Codelab erläutert wird.
Aktualisieren Sie die Datei lib/auth_gate.dart
mit dem folgenden Code:
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen( // Modify from here...
providers: [EmailAuthProvider()],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
); // To here.
}
return const HomeScreen();
},
);
}
}```
The headerBuilder argument requires a function of the type HeaderBuilder, which
is defined in the FlutterFire UI package.
```dart
typedef HeaderBuilder = Widget Function(
BuildContext context,
BoxConstraints constraints,
double shrinkOffset,
);
Da es sich um einen Rückruf handelt, werden Werte wie BuildContext
und BoxConstraints
zur Verfügung gestellt und Sie müssen ein Widget zurückgeben. Das zurückgegebene Widget wird oben auf dem Bildschirm angezeigt. In diesem Beispiel wird mit dem neuen Code oben auf dem Bildschirm ein Bild eingefügt. Ihre Anwendung sollte jetzt so aussehen.
Untertitel-Tool
Auf dem Anmeldebildschirm sind drei weitere Parameter zu sehen, mit denen Sie den Bildschirm anpassen können: subtitleBuilder
, footerBuilder
und sideBuilder
.
Der subtitleBuilder
unterscheidet sich geringfügig dadurch, dass die Rückrufargumente eine Aktion vom Typ AuthAction
enthalten. AuthAction
ist ein Enum, mit dem du erkennen kannst, ob sich der Nutzer auf dem Anmelde- oder Registrierungsbildschirm befindet.
Aktualisieren Sie den Code in „auth_gate.dart“, um die subtitleBuilder
zu verwenden.
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [EmailAuthProvider()],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) { // Add from here...
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
}, // To here.
);
}
return const HomeScreen();
},
);
}
}
Fußzeilen-Builder
Das Argument „footerBuilder“ ist mit dem Argument „subtitleBuilder“ identisch. BoxConstraints
oder shrinkOffset
werden nicht angezeigt, da er eher für Text als für Bilder gedacht ist. Sie können natürlich jedes gewünschte Widget hinzufügen.
Fügen Sie mit diesem Code eine Fußzeile auf dem Anmeldebildschirm hinzu.
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [EmailAuthProvider()],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) { // Add from here...
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
}, // To here.
);
}
return const HomeScreen();
},
);
}
}
Side Builder
Das Argument „SignInScreen.sidebuilder“ akzeptiert einen Callback. Diesmal sind die Argumente für diesen Callback BuildContext
und double shrinkOffset
. Das von sideBuilder
zurückgegebene Widget wird links neben dem Anmeldeformular angezeigt und nur auf Breitbildbildschirmen. Das bedeutet, dass das Widget nur auf Computern und in Web-Apps angezeigt wird.
Intern verwendet die FlutterFire-Benutzeroberfläche einen Wendepunkt, um zu bestimmen, ob der Inhalt des Headers (auf hohen Bildschirmen wie Mobilgeräten) oder der Seiteninhalt (auf breiten Bildschirmen, Desktop oder Web) angezeigt werden soll. Wenn ein Bildschirm mehr als 800 Pixel breit ist, werden die Inhalte des Seiten-Builders angezeigt, die Kopfzeileninhalte jedoch nicht. Ist der Bildschirm weniger als 800 Pixel breit, ist das Gegenteil der Fall.
Aktualisieren Sie den Code in „auth_gate.dart“, um sideBuilder
-Widgets hinzuzufügen.
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [EmailAuthProvider()],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
Wenn Sie die Breite des Fensters maximieren, sollte Ihre App jetzt so aussehen (wenn Sie Flutter Web oder macOS verwenden).
Nutzer erstellen
Der gesamte Code für diesen Bildschirm ist jetzt fertig. Bevor Sie sich anmelden können, müssen Sie jedoch einen Nutzer erstellen. Sie können dies über den Bildschirm „Registrieren“ tun oder einen Nutzer in der Firebase Console erstellen.
So verwenden Sie die Console:
- Rufen Sie in der Firebase Console die Tabelle Nutzer auf. Wählen Sie „flutterfire-ui-codelab“ oder ein anderes Projekt aus, falls Sie einen anderen Namen verwendet haben. Sie sehen dann diese Tabelle:
- Klicken Sie auf die Schaltfläche „Nutzer hinzufügen“.
- Geben Sie eine E-Mail-Adresse und ein Passwort für den neuen Nutzer ein. Dies können eine gefälschte E-Mail-Adresse und ein gefälschtes Passwort sein, wie im Bild unten dargestellt. Das funktioniert, aber die Funktion „Passwort vergessen“ funktioniert nicht, wenn Sie eine gefälschte E-Mail-Adresse verwenden.
- Klicken Sie auf „Nutzer hinzufügen“
.
Sie können jetzt zu Ihrer Flutter-Anwendung zurückkehren und einen Nutzer über die Anmeldeseite anmelden. Ihre App sollte so aussehen:
6. Profilbildschirm
Die FlutterFire-Benutzeroberfläche bietet auch ein ProfileScreen
-Widget, mit dem Sie mit wenigen Codezeilen viele Funktionen nutzen können.
Widget „ProfileScreen
“ hinzufügen
Rufen Sie die Datei home.dart
in Ihrem Texteditor auf. Aktualisieren Sie ihn mit diesem Code:
lib/home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => const ProfileScreen(),
),
);
},
),
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
SizedBox(width: 250, child: Image.asset('assets/dash.png')),
Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
const SignOutButton(),
],
),
),
);
}
}
Der neue Code ist der Callback, der an die IconButton.isPressed
-Methode übergeben wird. Wenn diese IconButton
gedrückt wird, erstellt Ihre Anwendung eine neue anonyme Route und wechselt zu dieser. Auf dieser Route wird das ProfileScreen
-Widget angezeigt, das vom MaterialPageRoute.builder
-Callback zurückgegeben wird.
Lade die App neu und drücke auf das Symbol oben rechts in der App-Leiste. Daraufhin wird eine Seite wie diese angezeigt:
Dies ist die Standard-UI, die von der FlutterFire-UI-Seite bereitgestellt wird. Alle Schaltflächen und Textfelder sind mit Firebase Auth verbunden und funktionieren sofort. Wenn Sie beispielsweise einen Namen in das Textfeld „Name“ eingeben, wird über die FlutterFire-Benutzeroberfläche die FirebaseAuth.instance.currentUser?.updateDisplayName
-Methode aufgerufen, die diesen Namen in Firebase speichert.
Abmelden
Wenn Sie derzeit auf die Schaltfläche „Abmelden“ klicken, ändert sich die App nicht. Sie werden abgemeldet, aber nicht zum AuthGate-Widget zurückgeleitet. Verwenden Sie dazu den Parameter „ProfileScreen.actions“.
Aktualisieren Sie zuerst den Code in „home.dart“.
lib/home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
}),
],
),
),
);
},
),
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
SizedBox(width: 250, child: Image.asset('assets/dash.png')),
Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
const SignOutButton(),
],
),
),
);
}
}
Wenn Sie jetzt eine Instanz von ProfileScreen
erstellen, übergeben Sie dem Argument ProfileScreen.actions
auch eine Liste von Aktionen. Diese Aktionen haben den Typ FlutterFireUiAction
. Es gibt viele verschiedene Klassen, die Untertypen von FlutterFireUiAction
sind. Sie geben Ihrer App im Allgemeinen an, auf verschiedene Änderungen des Authentifizierungsstatus zu reagieren. „SignedOutAction“ ruft eine Callback-Funktion auf, die Sie angeben, wenn sich der Firebase-Authentifizierungsstatus in „currentUser is null“ ändert.
Wenn Sie einen Callback hinzufügen, der Navigator.of(context).pop()
aufruft, wenn SignedOutAction
ausgelöst wird, wird in der App zur vorherigen Seite gewechselt. In dieser Beispiel-App gibt es nur eine permanente Route, auf der der Anmeldebildschirm angezeigt wird, wenn kein Nutzer angemeldet ist, und die Startseite, wenn ein Nutzer angemeldet ist. Da dies passiert, wenn sich der Nutzer abmeldet, wird in der App der Anmeldebildschirm angezeigt.
Profilseite anpassen
Ähnlich wie der Anmeldebildschirm kann auch die Profilseite angepasst werden. Erstens: Auf der aktuellen Seite gibt es keine Möglichkeit, zur Startseite zurückzukehren, wenn sich ein Nutzer auf der Profilseite befindet. Beheben Sie das Problem, indem Sie dem Widget „ProfileScreen“ eine App-Leiste hinzufügen.
lib/home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
appBar: AppBar(title: const Text('User Profile')),
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
}),
],
),
),
);
},
),
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
SizedBox(width: 250, child: Image.asset('assets/dash.png')),
Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
const SignOutButton(),
],
),
),
);
}
}
Das Argument ProfileScreen.appBar
akzeptiert ein AppBar
-Widget aus dem Flutter Material-Paket. Es kann also wie jedes andere von Ihnen erstellte AppBar
behandelt und an ein Scaffold
übergeben werden. In diesem Beispiel wird die Standardfunktion beibehalten, eine Schaltfläche „Zurück“ automatisch hinzuzufügen, und der Bildschirm hat jetzt einen Titel.
Kinder zum Profilbildschirm hinzufügen
Das ProfileScreen
-Widget hat auch ein optionales Argument namens „children“. Dieses Argument akzeptiert eine Liste von Widgets. Diese Widgets werden vertikal in einem Column
-Widget platziert, das bereits intern zum Erstellen des ProfileScreen
verwendet wird. Dieses Column
-Widget in der ProfileScreen
-Build-Methode platziert die von Ihnen übergebenen untergeordneten Elemente über der Schaltfläche „Abmelden“.
Aktualisieren Sie den Code in home.dart
, damit hier das Firmenlogo angezeigt wird, ähnlich wie auf dem Anmeldebildschirm.
lib/home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
appBar: AppBar(title: const Text('User Profile')),
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
}),
],
children: [
const Divider(),
Padding(
padding: const EdgeInsets.all(2),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
),
],
),
),
);
},
),
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
SizedBox(width: 250, child: Image.asset('assets/dash.png')),
Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
const SignOutButton(),
],
),
),
);
}
}
Wenn Sie die App neu laden, wird Folgendes auf dem Bildschirm angezeigt:
7. Multiplattform-Anmeldung über Google Auth
Die FlutterFire UI bietet außerdem Widgets und Funktionen für die Authentifizierung bei Drittanbietern wie Google, Twitter, Facebook, Apple und GitHub.
Wenn Sie die Google-Authentifizierung einbinden möchten, installieren Sie das offizielle Plug-in firebase_ui_oauth_google und die zugehörigen Abhängigkeiten. Dieses Plug-in verarbeitet den nativen Authentifizierungsablauf. Rufen Sie im Terminal das Stammverzeichnis Ihres Flutter-Projekts auf und geben Sie den folgenden Befehl ein:
flutter pub add google_sign_in firebase_ui_oauth_google
Google Log-in-Anbieter aktivieren
Aktivieren Sie als Nächstes den Google-Anbieter in der Firebase Console:
- Rufen Sie in der Console den Bildschirm Anbieter für Anmeldungen auf.
- Klicken Sie auf „Neuen Anbieter hinzufügen“.
- Wählen Sie „Google“ aus.
- Aktivieren Sie die Option „Aktivieren“ und klicken Sie auf „Speichern“.
- Wenn ein modales Fenster mit Informationen zum Herunterladen von Konfigurationsdateien angezeigt wird, klicken Sie auf „Fertig“.
- Prüfen Sie, ob der Google-Anmeldeanbieter hinzugefügt wurde.
Schaltfläche für Google Log-in hinzufügen
Wenn die Google-Anmeldung aktiviert ist, fügen Sie dem Anmeldebildschirm das Widget hinzu, das eine stilisierte Schaltfläche für die Google-Anmeldung anzeigt. Rufen Sie die Datei auth_gate.dart
auf und ändern Sie den Code in Folgendes:
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart'; // Add this import
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
GoogleProvider(clientId: clientId), // Add this line
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
Der einzige neue Code hier ist die Hinzufügung von GoogleProvider(clientId: "YOUR_WEBCLIENT_ID")
zur SignInScreen
-Widget-Konfiguration.
Aktualisieren Sie nun Ihre App. Daraufhin wird die Schaltfläche „Über Google anmelden“ angezeigt.
Anmeldeschaltfläche konfigurieren
Die Schaltfläche funktioniert ohne zusätzliche Konfiguration nicht. Wenn Sie mit Flutter Web entwickeln, ist dies der einzige Schritt, den Sie hinzufügen müssen, damit dies funktioniert. Bei anderen Plattformen sind zusätzliche Schritte erforderlich, die wir gleich erläutern.
- Rufen Sie in der Firebase Console die Seite „Authentifizierungsanbieter“ auf.
- Klicken Sie auf den Google-Anbieter.
- Klicken Sie auf das maximierte Steuerfeld „Web-SDK-Konfiguration“.
- Kopieren Sie den Wert aus „Webclient-ID“.
- Kehren Sie zu Ihrem Texteditor zurück und aktualisieren Sie die Instanz von
GoogleProvider
in der Dateiauth_gate.dart
, indem Sie diese ID an den ParameterclientId
übergeben.
GoogleProvider(
clientId: "YOUR_WEBCLIENT_ID"
)
Laden Sie die App neu, nachdem Sie die Web-Client-ID eingegeben haben. Wenn Sie die Schaltfläche „Über Google anmelden“ drücken, wird in der Webversion ein neues Fenster angezeigt, in dem Sie durch den Anmeldevorgang bei Google geführt werden. Zuerst sieht es so aus:
iOS konfigurieren
Damit dies auf iOS-Geräten funktioniert, ist ein zusätzlicher Konfigurationsvorgang erforderlich.
- Rufen Sie in der Firebase Console den Bildschirm „Projekteinstellungen“ auf. Sie sehen dann eine Karte mit Ihren Firebase-Apps, die so aussieht:
- Wähle „iOS“ aus. Der Name Ihrer Anwendung unterscheidet sich vom Namen im Screenshot. Wenn Sie das Projekt
flutter-codelabs/firebase-auth-flutterfire-ui/start
verwendet haben, um dieses Codelab zu verfolgen, steht anstelle von „complete“ (fertig) „start“ (starten) auf dem Screenshot. - Klicken Sie auf die Schaltfläche mit der Aufschrift
GoogleServices-Info.plist
, um die erforderliche Konfigurationsdatei herunterzuladen. - Ziehen Sie die heruntergeladene Datei in das Verzeichnis
/ios/Runner
in Ihrem Flutter-Projekt. - Öffnen Sie Xcode. Führen Sie dazu im Stammverzeichnis Ihres Projekts den folgenden Terminalbefehl aus:
open ios/Runner.xcworkspace
- Klicken Sie mit der rechten Maustaste auf das Verzeichnis „Runner“ und wählen Sie „Dateien zu ‚Runner‘ hinzufügen“ aus.
- Wählen Sie im Dateimanager
GoogleService-Info.plist
aus. - Fügen Sie in Ihrem Texteditor (nicht Xcode) die folgenden
CFBundleURLTypes
-Attribute der Dateiios/Runner/Info.plist
hinzu.<!-- Put me in the [my_project]/ios/Runner/Info.plist file --> <!-- Google Sign-in Section --> <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleTypeRole</key> <string>Editor</string> <key>CFBundleURLSchemes</key> <array> <!-- TODO Replace this value: --> <!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID --> <string>com.googleusercontent.apps.861823949799-vc35cprkp249096uujjn0vvnmcvjppkn</string> </array> </dict> </array> <!-- End of the Google Sign-in Section -->
- Ersetzen Sie die
GoogleProvider.clientId
, die Sie in der Webkonfiguration hinzugefügt haben, durch die Client-ID, die mit Ihrer Firebase-iOS-Client-ID verknüpft ist. Sie finden diese ID zuerst in der Dateifirebase_options.dart
als Teil der KonstanteiOS
. Kopieren Sie den aniOSClientId
übergebenen Wert.static const FirebaseOptions ios = FirebaseOptions( apiKey: 'YOUR API KEY', appId: 'YOUR APP ID', messagingSenderId: '', projectId: 'PROJECT_ID', storageBucket: 'PROJECT_ID.firebasestorage.app', iosClientId: 'IOS CLIENT ID', // Find your iOS client Id here. iosBundleId: 'com.example.BUNDLE', );
- Fügen Sie diesen Wert in die Variable
clientId
in der Dateilib/main.dart
ein.
lib/main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'app.dart';
import 'firebase_options.dart';
const clientId = 'YOUR_CLIENT_ID'; // Replace this value with your Client ID.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
runApp(const MyApp(clientId: clientId));
}
Wenn Ihre Flutter-App bereits unter iOS ausgeführt wird, müssen Sie sie vollständig beenden und dann noch einmal ausführen. Andernfalls führen Sie die App unter iOS aus.
8. Glückwunsch!
Sie haben das Codelab zur Firebase Auth-Benutzeroberfläche für Flutter abgeschlossen . Den vollständigen Code für dieses Codelab finden Sie im Verzeichnis firebase-auth-flutterfire-ui/complete
auf GitHub.
Behandelte Themen
- Flutter-App für die Verwendung von Firebase einrichten
- Firebase-Projekt in der Firebase Console einrichten
- FlutterFire CLI
- Firebase CLI
- Firebase Authentication verwenden
- FlutterFire-Benutzeroberfläche zum Verwalten der Firebase-Authentifizierung in Ihrer Flutter-App verwenden
Nächste Schritte
- Weitere Informationen zur Verwendung von Firestore und Authentifizierung in Flutter: Codelab zu Firebase für Flutter
- Weitere Firebase-Tools für die Entwicklung Ihrer Flutter-Anwendung:
Weitere Informationen
- Firebase-Website: firebase.google.com
- Flutter-Website: flutter.dev
- FlutterFire Firebase-Flutter-Widgets: firebase.flutter.dev
- Firebase-YouTube-Kanal
- YouTube-Kanal von Flutter
Sparky ist da, um mit dir zu feiern!