Dodawanie procesu uwierzytelniania użytkowników do aplikacji Flutter za pomocą FirebaseUI

1. Zanim zaczniesz

Z tego laboratorium dowiesz się, jak dodać uwierzytelnianie Firebase do aplikacji Flutter za pomocą pakietu FlutterFire UI. Dzięki temu pakietowi dodasz do aplikacji Flutter uwierzytelnianie za pomocą adresu e-mail i hasła oraz uwierzytelnianie za pomocą logowania przez Google. Dowiesz się też, jak skonfigurować projekt Firebase i użyć interfejsu wiersza poleceń FlutterFire do zainicjowania Firebase w aplikacji Flutter.

Wymagania wstępne

W tym ćwiczeniu z programowania zakładamy, że masz już pewne doświadczenie w korzystaniu z Fluttera. Jeśli nie, najpierw warto poznać podstawy. Przydatne mogą być te linki:

Powinieneś też mieć pewne doświadczenie w korzystaniu z Firebase, ale nie musisz mieć za sobą dodawania Firebase do projektu Flutter. Jeśli nie znasz konsoli Firebase lub dopiero zaczynasz korzystać z Firebase, najpierw zapoznaj się z tymi artykułami:

Co utworzysz

W tym laboratorium kodowania dowiesz się, jak utworzyć przepływ uwierzytelniania dla aplikacji na Fluttera za pomocą Firebase Authentication. Aplikacja będzie miała ekran logowania, ekran rejestracji, ekran odzyskiwania hasła i ekran profilu użytkownika.

6604fc9157f2c6ae.png eab9509a41074930.png da49189a5838e0bb.png b2ccfb3632b77878.png

Czego się nauczysz

W tym ćwiczeniu dowiesz się:

  • Dodawanie Firebase do aplikacji Flutter
  • Konfigurowanie konsoli Firebase
  • Dodawanie Firebase do aplikacji za pomocą wiersza poleceń Firebase
  • Generowanie konfiguracji Firebase w Dart za pomocą wiersza poleceń FlutterFire
  • Dodawanie Uwierzytelniania Firebase do aplikacji we Flutterze
  • Konfigurowanie Uwierzytelniania Firebase w konsoli
  • Dodawanie logowania za pomocą adresu e-mail i hasła za pomocą pakietu firebase_ui_auth
  • Dodawanie rejestracji użytkowników za pomocą pakietu firebase_ui_auth
  • Dodawanie strony „Nie pamiętasz hasła?”
  • Dodawanie logowania przez Google za pomocą firebase_ui_auth
  • Skonfiguruj aplikację do współpracy z wieloma dostawcami logowania.
  • Dodawanie ekranu profilu użytkownika do aplikacji za pomocą pakietu firebase_ui_auth

Ten samouczek dotyczy dodawania niezawodnego systemu uwierzytelniania za pomocą pakietu firebase_ui_auth. Jak zobaczysz, całą tę aplikację ze wszystkimi wymienionymi wyżej funkcjami można zaimplementować za pomocą około 100 wierszy kodu.

Czego potrzebujesz

  • Praktyczna znajomość Fluttera i zainstalowany pakiet SDK.
  • edytor tekstu (Flutter obsługuje środowiska IDE JetBrains, Android Studio i VS Code);
  • przeglądarka Google Chrome lub inne preferowane środowisko docelowe do tworzenia aplikacji we Flutterze. (Niektóre polecenia terminala w tym laboratorium zakładają, że aplikacja jest uruchomiona w Chrome).

2. Tworzenie i konfigurowanie projektu Firebase

Pierwszym zadaniem, które musisz wykonać, jest utworzenie projektu Firebase w konsoli internetowej Firebase.

Tworzenie projektu Firebase

  1. Zaloguj się w konsoli Firebase, korzystając ze swojego konta Google.
  2. Kliknij przycisk, aby utworzyć nowy projekt, a potem wpisz jego nazwę (np. FlutterFire-UI-Codelab).
  3. Kliknij Dalej.
  4. Po wyświetleniu monitu przeczytaj i zaakceptuj warunki usługi Firebase, a potem kliknij Dalej.
  5. (Opcjonalnie) Włącz w konsoli Firebase pomoc AI (nazywaną „Gemini w Firebase”).
  6. W tym samouczku nie potrzebujesz Google Analytics, więc wyłącz opcję Google Analytics.
  7. Kliknij Utwórz projekt, poczekaj, aż projekt zostanie udostępniony, a następnie kliknij Dalej.

Więcej informacji o projektach Firebase znajdziesz w artykule Projekty w Firebase.

Włączanie logowania za pomocą adresu e-mail w usłudze Uwierzytelnianie Firebase

Tworzona aplikacja korzysta z Uwierzytelniania Firebase, aby umożliwić użytkownikom logowanie się w niej. Umożliwia też nowym użytkownikom rejestrację z poziomu aplikacji Flutter.

Uwierzytelnianie Firebase musi być włączone w konsoli Firebase i po włączeniu wymaga specjalnej konfiguracji.

Aby umożliwić użytkownikom logowanie się w aplikacji internetowej, najpierw użyj metody logowania E-mail/hasło. Później dodasz metodę Logowanie przez Google.

  1. W konsoli Firebase rozwiń menu Build (Kompilacja) w panelu po lewej stronie.
  2. Kliknij Uwierzytelnianie, a następnie przycisk Rozpocznij i kartę Metoda logowania (lub przejdź bezpośrednio do karty Metoda logowania).
  3. Na liście Dostawcy logowania kliknij E-mail/hasło, ustaw przełącznik Włącz w pozycji włączonej, a następnie kliknij Zapisz.

58e3e3e23c2f16a4.png

3. Konfigurowanie aplikacji Flutter

Zanim zaczniemy, musisz pobrać kod początkowy i zainstalować wiersz poleceń Firebase.

Pobieranie kodu startowego

Sklonuj repozytorium GitHub z wiersza poleceń:

git clone https://github.com/flutter/codelabs.git flutter-codelabs

Jeśli masz zainstalowane narzędzie CLI GitHuba:

gh repo clone flutter/codelabs flutter-codelabs

Przykładowy kod należy sklonować do katalogu flutter-codelabs na komputerze, który zawiera kod kolekcji ćwiczeń z programowania. Kod do tego laboratorium znajduje się w podkatalogu flutter-codelabs/firebase-auth-flutterfire-ui.

Katalog flutter-codelabs/firebase-auth-flutterfire-ui zawiera 2 projekty Fluttera. Jeden to complete, a drugi to start. Katalog start zawiera niekompletny projekt i to w nim spędzisz najwięcej czasu.

cd flutter-codelabs/firebase-auth-flutterfire-ui/start

Jeśli chcesz przejść dalej lub zobaczyć, jak coś powinno wyglądać po ukończeniu, zajrzyj do katalogu o nazwie complete, aby sprawdzić, czy wszystko się zgadza.

Jeśli chcesz wykonać ćwiczenie (w Codelabs) i samodzielnie dodać kod, zacznij od aplikacji Flutter na stronie flutter-codelabs/firebase-auth-flutterfire-ui/start i dodawaj kod do tego projektu w trakcie ćwiczenia. Otwórz lub zaimportuj ten katalog w preferowanym środowisku IDE.

Zainstaluj wiersz poleceń Firebase

Wiersz poleceń Firebase udostępnia narzędzia do zarządzania projektami Firebase. Wiersz poleceń jest wymagany w przypadku wiersza poleceń FlutterFire, który zainstalujesz za chwilę.

CLI można zainstalować na wiele sposobów. Wszystkie dostępne opcje dla Twojego systemu operacyjnego znajdziesz na stronie firebase.google.com/docs/cli.

Po zainstalowaniu wiersza poleceń musisz uwierzytelnić się w Firebase.

  1. Zaloguj się w Firebase za pomocą konta Google, uruchamiając to polecenie:
    firebase login
    
  2. To polecenie łączy komputer lokalny z Firebase i przyznaje Ci dostęp do projektów Firebase.
  3. Sprawdź, czy interfejs CLI jest prawidłowo zainstalowany i ma dostęp do Twojego konta, wyświetlając listę projektów Firebase. Uruchom to polecenie:
    firebase projects:list
    
  4. Wyświetlona lista powinna być taka sama jak lista projektów Firebase w konsoli Firebase. Powinno się wyświetlić co najmniej flutterfire-ui-codelab.

Instalowanie interfejsu wiersza poleceń FlutterFire

Wiersz poleceń FlutterFire to narzędzie, które ułatwia proces instalacji Firebase na wszystkich obsługiwanych platformach w aplikacji Flutter. Jest ono oparte na wierszu poleceń Firebase.

Najpierw zainstaluj interfejs wiersza poleceń:

dart pub global activate flutterfire_cli

Sprawdź, czy interfejs CLI został zainstalowany. Uruchom to polecenie i sprawdź, czy interfejs wiersza poleceń wyświetla menu pomocy.

flutterfire --help

Dodawanie projektu Firebase do aplikacji Flutter

Konfigurowanie FlutterFire

Możesz użyć FlutterFire, aby wygenerować potrzebny kod Dart do korzystania z Firebase w aplikacji Flutter.

flutterfire configure

Po uruchomieniu tego polecenia pojawi się prośba o wybranie projektu Firebase, którego chcesz użyć, oraz platform, które chcesz skonfigurować.

Na zrzutach ekranu poniżej widać, na jakie pytania musisz odpowiedzieć.

  1. Wybierz projekt, którego chcesz użyć. W takim przypadku użyj flutterfire-ui-codelab1359cdeb83204baa.png
  2. Wybierz platformy, których chcesz używać. W tym laboratorium znajdziesz instrukcje konfigurowania uwierzytelniania Firebase w Flutterze na potrzeby internetu, iOS i Androida, ale możesz skonfigurować projekt Firebase tak, aby korzystać ze wszystkich opcji. 301c9534f594f472.png
  3. Ten zrzut ekranu przedstawia dane wyjściowe na końcu procesu. Jeśli znasz Firebase, zauważysz, że nie musisz tworzyć w konsoli aplikacji na platformy (np. aplikacji na Androida), ponieważ zrobił to za Ciebie interfejs wiersza poleceń FlutterFire. 12199a85ade30459.png

Gdy to zrobisz, otwórz aplikację Flutter w edytorze tekstu. Interfejs wiersza poleceń FlutterFire zmodyfikował plik o nazwie firebase_options.dart. Ten plik zawiera klasę o nazwie FirebaseOptions, która ma zmienne statyczne przechowujące konfigurację Firebase potrzebną na każdej platformie. Jeśli podczas uruchamiania polecenia flutterfire configure wybrano wszystkie platformy, zobaczysz wartości statyczne o nazwach web, android, iosmacos.

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',
  );
}

Firebase używa słowa „aplikacja” w odniesieniu do konkretnej wersji na konkretną platformę w projekcie Firebase. Na przykład projekt Firebase o nazwie FlutterFire-ui-codelab zawiera kilka aplikacji: jedną na Androida, jedną na iOS, jedną na macOS i jedną internetową.

Metoda DefaultFirebaseOptions.currentPlatform używa wyliczenia TargetPlatform udostępnianego przez Fluttera, aby wykryć platformę, na której działa aplikacja, a następnie zwraca wartości konfiguracji Firebase potrzebne do prawidłowego działania aplikacji Firebase.

Dodawanie pakietów Firebase do aplikacji Flutter

Ostatnim krokiem konfiguracji jest dodanie odpowiednich pakietów Firebase do projektu Flutter. Plik firebase_options.dart powinien zawierać błędy, ponieważ korzysta z pakietów Firebase, które nie zostały jeszcze dodane. W terminalu upewnij się, że jesteś w katalogu głównym projektu Flutter w flutter-codelabs/firebase-emulator-suite/start. Następnie uruchom te 3 polecenia:

flutter pub add firebase_core firebase_auth firebase_ui_auth

Na tym etapie potrzebujesz tylko tych pakietów.

Inicjowanie Firebase

Aby użyć dodanych pakietów i DefaultFirebaseOptions.currentPlatform,, zaktualizuj kod w funkcji main w pliku 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));
}

Ten kod wykonuje 2 czynności.

  1. WidgetsFlutterBinding.ensureInitialized() informuje Fluttera, aby nie uruchamiał kodu widżetu aplikacji, dopóki platforma Flutter nie zostanie w pełni uruchomiona. Firebase korzysta z kanałów platformy natywnej, które wymagają działania platformy.
  2. Firebase.initializeApp konfiguruje połączenie między aplikacją Flutter a projektem Firebase. DefaultFirebaseOptions.currentPlatform jest importowany z wygenerowanego przez nas pliku firebase_options.dart. Ta wartość statyczna wykrywa, na której platformie działasz, i przekazuje odpowiednie klucze Firebase.

4. Dodawanie początkowej strony uwierzytelniania w interfejsie Firebase

Interfejs Firebase UI do uwierzytelniania udostępnia widżety, które reprezentują całe ekrany w aplikacji. Te ekrany obsługują różne procesy uwierzytelniania w aplikacji, takie jak logowanie, rejestracja, zapomniane hasło, profil użytkownika i inne. Na początek dodaj do aplikacji stronę docelową, która będzie działać jako zabezpieczenie uwierzytelniania głównej aplikacji.

Aplikacja Material lub Cupertino

Interfejs FlutterFire wymaga, aby aplikacja była opakowana w komponent MaterialApp lub CupertinoApp. W zależności od wyboru interfejs automatycznie odzwierciedli różnice między widżetami Material Design i Cupertino. W tym laboratorium użyj MaterialApp, który został już dodany do aplikacji w app.dart.

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

Sprawdzanie stanu uwierzytelniania

Zanim wyświetlisz ekran logowania, musisz sprawdzić, czy użytkownik jest uwierzytelniony. Najczęstszym sposobem sprawdzenia tego jest nasłuchiwanie FirebaseAuthauthStateChanges za pomocą wtyczki uwierzytelniania Firebase.

W przykładowym kodzie powyżej MaterialApp tworzy widżet AuthGate w metodzie build. (Jest to widżet niestandardowy, który nie jest dostarczany przez FlutterFire UI).

Ten widżet musi zostać zaktualizowany, aby uwzględniał strumień authStateChanges.

Interfejs authStateChanges API zwraca obiekt Stream z bieżącym użytkownikiem (jeśli jest zalogowany) lub wartość null, jeśli nie jest zalogowany. Aby zasubskrybować ten stan w naszej aplikacji, możesz użyć widżetu StreamBuilder w Flutterze i przekazać do niego strumień.

StreamBuilder to widżet, który tworzy się na podstawie najnowszej migawki danych ze strumienia, który mu przekazujesz. Jest ona automatycznie przebudowywana, gdy Stream emituje nowy zrzut.

Zaktualizuj kod w 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 jest przekazywany FirebaseAuth.instance.authStateChanged, czyli wspomniany wyżej strumień, który zwraca obiekt Firebase User, jeśli użytkownik został uwierzytelniony, a w przeciwnym razie zwraca null.
  • Następnie kod używa funkcji snapshot.hasData, aby sprawdzić, czy wartość ze strumienia zawiera obiekt User.
  • Jeśli nie, zwróci widżet SignInScreen. Na razie ten ekran nie będzie wykonywać żadnych działań. Zostanie zaktualizowany w następnym kroku.
  • W przeciwnym razie zwraca HomeScreen, czyli główną część aplikacji, do której dostęp mają tylko uwierzytelnieni użytkownicy.

SignInScreen to widżet pochodzący z pakietu FlutterFire UI. Na tym skupimy się w następnym kroku tego laboratorium. Gdy w tym momencie uruchomisz aplikację, powinien pojawić się pusty ekran logowania.

5. Ekran logowania

Widżet SignInScreen udostępniany przez FlutterFire UI dodaje te funkcje:

  • Zezwalanie użytkownikom na logowanie się
  • Jeśli użytkownicy zapomną hasła, mogą kliknąć „Nie pamiętasz hasła?” i przejść do formularza resetowania hasła.
  • Jeśli użytkownik nie jest jeszcze zarejestrowany, może kliknąć „Zarejestruj się” i wypełnić formularz rejestracyjny.

Wymaga to tylko kilku wierszy kodu. Wywołaj kod w widżecie AuthGate:

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

Widżet SignInScreen i jego argument providers to jedyny kod wymagany do uzyskania wszystkich wymienionych wyżej funkcji. Powinien pojawić się ekran logowania z polami tekstowymi „e-mail” i „hasło” oraz przyciskiem „Zaloguj się”.

Działa, ale nie ma stylu. Widżet udostępnia parametry, które pozwalają dostosować wygląd ekranu logowania. Możesz na przykład dodać logo firmy.

Dostosowywanie ekranu logowania

headerBuilder

Za pomocą argumentu SignInScreen.headerBuilder możesz dodać dowolne widżety nad formularzem logowania. Ten widżet jest wyświetlany tylko na wąskich ekranach, np. na urządzeniach mobilnych. Na szerokich ekranach możesz używać elementu SignInScreen.sideBuilder, o którym piszemy w dalszej części tego laboratorium.

Zaktualizuj plik lib/auth_gate.dart za pomocą tego kodu:

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,
);

Jest to wywołanie zwrotne, więc udostępnia wartości, których możesz użyć, takie jak BuildContextBoxConstraints, i wymaga zwrócenia widżetu. Wybrany widżet wyświetli się u góry ekranu. W tym przykładzie nowy kod dodaje obraz u góry ekranu. Aplikacja powinna teraz wyglądać tak.

73d7548d91bbd2ab.png

Kreator napisów

Ekran logowania udostępnia 3 dodatkowe parametry, które pozwalają go dostosować: subtitleBuilder, footerBuildersideBuilder.

Funkcja subtitleBuilder różni się nieco tym, że argumenty wywołania zwrotnego obejmują działanie, które jest typu AuthAction. AuthAction to wyliczenie, którego możesz użyć, aby wykryć, czy użytkownik znajduje się na ekranie „Zaloguj się” czy „Zarejestruj się”.

Zaktualizuj kod w pliku auth_gate.dart, aby używać w nim tabeli subtitleBuilder.

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

Argument footerBuilder jest taki sam jak subtitleBuilder. Nie ujawnia ona BoxConstraints ani shrinkOffset, ponieważ jest przeznaczona do tekstu, a nie do obrazów. Możesz oczywiście dodać dowolny widżet.

Dodaj stopkę do ekranu logowania za pomocą tego kodu.

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

Argument SignInScreen.sidebuilder przyjmuje wywołanie zwrotne, a tym razem argumentami tego wywołania zwrotnego są BuildContextdouble shrinkOffset. Widżet, który sideBuilder zwraca, będzie wyświetlany po lewej stronie formularza logowania i tylko na szerokich ekranach. Oznacza to, że widżet będzie wyświetlany tylko na komputerach i w aplikacjach internetowych.

Wewnętrznie FlutterFire UI używa punktu przerwania, aby określić, czy ma być wyświetlana treść nagłówka (na wysokich ekranach, np. na urządzeniach mobilnych), czy treść boczna (na szerokich ekranach, np. na komputerach lub w internecie). Jeśli ekran ma szerokość większą niż 800 pikseli, wyświetlana jest treść z bocznego narzędzia do tworzenia, a treść nagłówka nie jest wyświetlana. Jeśli ekran ma mniej niż 800 pikseli szerokości, jest odwrotnie.

Zaktualizuj kod w pliku auth_gate.dart, aby dodać widżety sideBuilder.

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

Po rozszerzeniu okna aplikacja powinna wyglądać tak (jeśli używasz Fluttera w internecie lub na macOS).

8dc60b4e5d7dd2d0.png

Tworzenie konta użytkownika

Na tym etapie cały kod tego ekranu jest gotowy. Zanim jednak się zalogujesz, musisz utworzyć użytkownika. Możesz to zrobić na ekranie „Zarejestruj” lub utworzyć użytkownika w konsoli Firebase.

Aby użyć konsoli:

  1. Otwórz tabelę „Użytkownicy” w konsoli Firebase. Wybierz „flutterfire-ui-codelab” lub inny projekt, jeśli używasz innej nazwy. Wyświetli się ta tabela: f038fd9a58ed60d9.png
  2. Kliknij przycisk „Dodaj użytkownika”. 2d78390d4c5dbbfa.png
  3. Wpisz adres e-mail i hasło nowego użytkownika. Może to być fałszywy adres e-mail i hasło, jak na obrazie poniżej. To zadziała, ale jeśli użyjesz fałszywego adresu e-mail, funkcja „Nie pamiętam hasła” nie będzie działać. 62ba0feb33d54add.png
  4. Kliknij „Dodaj użytkownika” 32b236b3ef94d4c7.png.

Teraz możesz wrócić do aplikacji Flutter i zalogować użytkownika na stronie logowania. Aplikacja powinna wyglądać tak:

dd43d260537f3b1a.png

6. Ekran profilu

Interfejs FlutterFire UI udostępnia też widżet ProfileScreen, który zapewnia wiele funkcji w kilku wierszach kodu.

Dodaj widżet ProfileScreen

Otwórz plik home.dart w edytorze tekstu. Zaktualizuj go za pomocą tego kodu:

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(),
          ],
        ),
      ),
    );
  }
}

Nowy kod notatki to wywołanie zwrotne przekazane do metody IconButton.isPressed. Gdy naciśniesz IconButton, aplikacja utworzy nową anonimową trasę i przejdzie do niej. Na tej trasie wyświetli się widżet ProfileScreen, który jest zwracany przez wywołanie zwrotne MaterialPageRoute.builder.

Ponownie załaduj aplikację i kliknij ikonę w prawym górnym rogu (na pasku aplikacji). Wyświetli się strona podobna do tej:

36487fc4ab4f26a7.png

Jest to standardowy interfejs udostępniany na stronie FlutterFire UI. Wszystkie przyciski i pola tekstowe są połączone z usługą Uwierzytelnianie Firebase i działają od razu po wyjęciu z pudełka. Możesz na przykład wpisać nazwę w polu tekstowym „Name”, a FlutterFire UI wywoła metodę FirebaseAuth.instance.currentUser?.updateDisplayName, która zapisze tę nazwę w Firebase.

Wyloguj się

Jeśli teraz naciśniesz przycisk „Wyloguj się”, aplikacja nie ulegnie zmianie. Spowoduje to wylogowanie, ale nie nastąpi powrót do widżetu AuthGate. Aby to zrobić, użyj parametru ProfileScreen.actions.

Najpierw zaktualizuj kod w pliku 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(),
          ],
        ),
      ),
    );
  }
}

Teraz podczas tworzenia instancji ProfileScreen przekazujesz też listę działań do argumentu ProfileScreen.actions. Są to działania typu FlutterFireUiAction. Istnieje wiele różnych klas, które są podtypami FlutterFireUiAction. Ogólnie rzecz biorąc, używasz ich, aby poinformować aplikację, że ma reagować na różne zmiany stanu uwierzytelniania. SignedOutAction wywołuje funkcję wywołania zwrotnego, którą podajesz, gdy stan uwierzytelniania Firebase zmieni się na currentUser o wartości null.

Dodając wywołanie zwrotne, które wywołuje Navigator.of(context).pop(), gdy SignedOutAction zostanie aktywowany, aplikacja przejdzie na poprzednią stronę. W tej przykładowej aplikacji jest tylko 1 stała ścieżka, która wyświetla ekran logowania, jeśli użytkownik nie jest zalogowany, a stronę główną, jeśli jest zalogowany. Dzieje się to, gdy użytkownik się wylogowuje, więc aplikacja wyświetla ekran logowania.

Dostosowywanie strony profilu

Podobnie jak ekran logowania, stronę profilu można dostosować. Po pierwsze, na naszej obecnej stronie nie ma możliwości powrotu na stronę główną, gdy użytkownik jest na stronie profilu. Aby to naprawić, dodaj do widżetu ProfileScreen element AppBar.

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(),
          ],
        ),
      ),
    );
  }
}

Argument ProfileScreen.appBar przyjmuje widżet AppBar z pakietu Flutter Material, więc można go traktować jak każdy inny widżet AppBar, który został utworzony i przekazany do widżetu Scaffold. W tym przykładzie zachowana jest domyślna funkcja automatycznego dodawania przycisku „Wstecz”, a ekran ma teraz tytuł.

Dodawanie dzieci na ekranie profilu

Widżet ProfileScreen ma też opcjonalny argument o nazwie children. Ten argument akceptuje listę widżetów, które zostaną umieszczone pionowo w widżecie Column używanym wewnętrznie do tworzenia ProfileScreen. Ten widżet Column w metodzie ProfileScreen umieści przekazane elementy podrzędne nad przyciskiem „Wyloguj się”.

Zaktualizuj kod w home.dart, aby wyświetlać tutaj logo firmy, podobnie jak na ekranie logowania.

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(),
          ],
        ),
      ),
    );
  }
}

Załaduj ponownie aplikację. Na ekranie zobaczysz:

ebe5792b765dbf87.png

7. Logowanie w Google na wielu platformach

Pakiet FlutterFire UI udostępnia też widżety i funkcje do uwierzytelniania za pomocą dostawców zewnętrznych, takich jak Google, Twitter, Facebook, Apple i GitHub.

Aby zintegrować uwierzytelnianie w Google, zainstaluj oficjalną wtyczkę firebase_ui_oauth_google i jej zależności, które będą obsługiwać natywny proces uwierzytelniania. W terminalu przejdź do katalogu głównego projektu Fluttera i wpisz to polecenie:

flutter pub add google_sign_in firebase_ui_oauth_google

Włącz dostawcę Logowania przez Google

Następnie włącz dostawcę Google w konsoli Firebase:

  1. W konsoli otwórz ekran Dostawcy logowania do uwierzytelniania.
  2. Kliknij „Dodaj nowego dostawcę”. 8286fb28be94bf30.png
  3. Wybierz „Google”. c4e28e6f4974be7f.png
  4. Przesuń przełącznik oznaczony jako „Włącz” i kliknij „Zapisz”. e74ff86990763826.png
  5. Jeśli pojawi się okno z informacjami o pobieraniu plików konfiguracyjnych, kliknij „Gotowe”.
  6. Sprawdź, czy dostawca logowania przez Google został dodany. 5329ce0543c90d95.png

Dodawanie przycisku logowania przez Google

Po włączeniu logowania przez Google dodaj do ekranu logowania widżet potrzebny do wyświetlania stylizowanego przycisku logowania przez Google. Otwórz plik auth_gate.dart i zaktualizuj kod, aby wyglądał tak:

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

Jedyną nowością w tym kodzie jest dodanie GoogleProvider(clientId: "YOUR_WEBCLIENT_ID") do konfiguracji widżetu SignInScreen.

Po dodaniu tego kodu ponownie załaduj aplikację. Zobaczysz przycisk logowania przez Google.

aca71a46a011bfb5.png

Konfigurowanie przycisku logowania

Przycisk nie działa bez dodatkowej konfiguracji. Jeśli tworzysz aplikację za pomocą Flutter Web, to jedyny krok, który musisz wykonać, aby to zadziałało. Inne platformy wymagają dodatkowych czynności, o których wspomnimy za chwilę.

  1. Otwórz stronę Dostawcy uwierzytelniania w konsoli Firebase.
  2. Kliknij dostawcę Google. 9b3a325c5eca6e49.png
  3. Kliknij panel rozwijany „Konfiguracja SDK dla klienta internetowego”.
  4. Skopiuj wartość z pola „Identyfikator klienta internetowego”. 711a79f0d931c60f.png
  5. Wróć do edytora tekstu i zaktualizuj instancję GoogleProvider w pliku auth_gate.dart, przekazując ten identyfikator do parametru nazwanego clientId.
GoogleProvider(
   clientId: "YOUR_WEBCLIENT_ID"
)

Po wpisaniu identyfikatora klienta internetowego ponownie załaduj aplikację. Gdy naciśniesz przycisk „Zaloguj się przez Google”, pojawi się nowe okno (jeśli używasz internetu), które przeprowadzi Cię przez proces logowania w Google. Początkowo wygląda to tak:

14e73e3c9de704bb.png

Konfigurowanie iOS

Aby to działało na iOS, wymagany jest dodatkowy proces konfiguracji.

  1. Otwórz ekran Ustawienia projektu w konsoli Firebase. Wyświetli się karta z listą aplikacji Firebase, która będzie wyglądać tak: fefa674acbf213cc.png
  2. Wybierz iOS. Pamiętaj, że nazwa Twojej aplikacji będzie inna niż ta widoczna na zrzucie ekranu. Jeśli w tym samouczku korzystasz z projektu flutter-codelabs/firebase-auth-flutterfire-ui/start, w miejscu, w którym na zrzucie ekranu widnieje napis „complete”, u Ciebie będzie widniał napis „start”.
  3. Kliknij przycisk z symbolem GoogleServices-Info.plist, aby pobrać potrzebny plik konfiguracyjny. f89b3192871dfbe3.png
  4. Przeciągnij pobrany plik do katalogu o nazwie /ios/Runner w projekcie Flutter.
  5. Otwórz Xcode, uruchamiając to polecenie w terminalu z katalogu głównego projektu: open ios/Runner.xcworkspace
  6. Kliknij prawym przyciskiem myszy katalog Runner i wybierz Add Files to "Runner" (Dodaj pliki do „Runner”). 858986063a4c5201.png
  7. W menedżerze plików kliknij GoogleService-Info.plist.
  8. Wróć do edytora tekstu (innego niż Xcode) i dodaj do pliku ios/Runner/Info.plist te atrybuty: CFBundleURLTypes.
    <!-- 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 -->
    
  9. Musisz zastąpić znak GoogleProvider.clientId dodany w konfiguracji internetowej identyfikatorem klienta powiązanym z identyfikatorem klienta Firebase na iOS. Najpierw znajdziesz ten identyfikator w pliku firebase_options.dart jako część stałej iOS. Skopiuj wartość przekazaną do iOSClientId.
    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',
    );
    
  10. Wklej tę wartość do zmiennej clientId w pliku lib/main.dart.

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

Jeśli aplikacja Flutter jest już uruchomiona na iOS, musisz ją całkowicie zamknąć, a potem uruchomić ponownie. W przeciwnym razie uruchom aplikację w iOS.

8. Gratulacje!

Udało Ci się ukończyć ćwiczenie Firebase Auth UI for Flutter . Gotowy kod do tego ćwiczenia z programowania znajdziesz w firebase-auth-flutterfire-ui/complete katalogu na GitHubie.

Omówione zagadnienia

  • Konfigurowanie aplikacji Flutter do korzystania z Firebase
  • Konfigurowanie projektu Firebase w konsoli Firebase
  • FlutterFire CLI
  • wiersz poleceń Firebase
  • Korzystanie z Uwierzytelniania Firebase
  • Korzystanie z FlutterFire UI do obsługi uwierzytelniania Firebase w aplikacji Flutter

Następne kroki

Więcej informacji

Sparky jest tutaj, aby świętować z Tobą!

2a0ad195769368b1.gif