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

1. Zanim zaczniesz

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

Wymagania wstępne

To ćwiczenie z programowania zakłada, że masz już pewne doświadczenie w używaniu Fluttera. Jeśli nie, warto najpierw zapoznać się z podstawami. Te linki mogą być przydatne:

Powinieneś/powinnaś też mieć pewne doświadczenie w korzystaniu z Firebase, ale nie ma problemu, jeśli nie dodawałeś/dodawałaś tej usługi do projektu Flutter. Jeśli nie znasz konsoli Firebase lub dopiero zaczynasz korzystać z tej platformy, zapoznaj się najpierw z tymi artykułami:

Co utworzysz

W tym laboratorium programistycznym znajdziesz instrukcje tworzenia przepływu uwierzytelniania w aplikacji Flutter za pomocą Firebase for Authentication. Aplikacja będzie zawierać 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 omawiamy:

  • Dodawanie Firebase do aplikacji Flutter
  • Konfiguracja konsoli Firebase
  • Dodawanie Firebase do aplikacji za pomocą wiersza poleceń Firebase
  • Generowanie konfiguracji Firebase w języku Dart za pomocą wiersza poleceń FlutterFire
  • Dodawanie Uwierzytelniania Firebase do aplikacji Flutter
  • Konfigurowanie Uwierzytelniania Firebase w konsoli
  • Dodawanie logowania za pomocą adresu e-mail i hasła w pakiecie firebase_ui_auth
  • Dodawanie rejestracji użytkownika w pakiecie 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 warsztat dotyczy głównie dodawania niezawodnego systemu uwierzytelniania za pomocą pakietu firebase_ui_auth. Jak zobaczysz, całą aplikację ze wszystkimi wymienionymi funkcjami można zaimplementować za pomocą około 100 wierszy kodu.

Czego potrzebujesz

  • Znajomość Fluttera i zainstalowanego pakietu SDK.
  • edytor tekstu (Flutter obsługuje JetBrains IDE, Android Studio i VS Code);
  • przeglądarka Google Chrome lub inny preferowany cel programowania dla Fluttera. (niektóre polecenia terminala w tym CodeLab będą zakładać, że aplikacja jest uruchamiana 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 Firebase.
  2. W konsoli Firebase kliknij Dodaj projekt (lub Utwórz projekt) i wpisz nazwę projektu Firebase (np. „FlutterFire-UI-Codelab”). df42a5e3d9584b48.png
  3. Przejrzyj opcje tworzenia projektu. Zaakceptuj warunki korzystania z Firebase, jeśli pojawi się taka prośba. Pomiń konfigurowanie Google Analytics, ponieważ nie będziesz używać tej usługi w przypadku tej aplikacji. d1fcec48bf251eaa.png

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

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

Aplikacja, którą tworzysz, korzysta z usługi Uwierzytelnianie Firebase, aby umożliwić użytkownikom logowanie się w niej. Umożliwia też nowym użytkownikom rejestrację w aplikacji Flutter.

Uwierzytelnianie Firebase musi zostać włączone w konsoli Firebase, a 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ę Logowania przez Google.

  1. W konsoli Firebase rozwiń w panelu po lewej stronie menu Kompilacja.
  2. Kliknij Uwierzytelnianie, a następnie kliknij 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 zaczniesz, musisz pobrać kod startowy i zainstalować wiersz poleceń Firebase.

Pobieranie kodu startowego

Sklonuj repozytorium GitHub z poziomu wiersza poleceń:

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

Jeśli masz zainstalowane narzędzie wiersza poleceń GitHub:

gh repo clone flutter/codelabs flutter-codelabs

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

Katalog flutter-codelabs/firebase-auth-flutterfire-ui zawiera 2 projekty Fluttera. Jedna to complete, a druga start. Katalog start zawiera niekompletny projekt, na którym spędzisz najwięcej czasu.

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

Jeśli chcesz przejść do następnego zadania lub sprawdzić, jak powinno wyglądać zadanie po jego ukończeniu, zajrzyj do katalogu o nazwie complete.

Jeśli chcesz wykonać ćwiczenie Codelab i sam dodać kod, zacznij od aplikacji Flutter (flutter-codelabs/firebase-auth-flutterfire-ui/start) i dodawaj kod do tego projektu w trakcie wykonywania ćwiczenia. Otwórz ten katalog lub zaimportuj go do preferowanego środowiska IDE.

Zainstaluj wiersz poleceń Firebase

Wiersz poleceń Firebase zawiera narzędzia do zarządzania projektami Firebase. Interfejs wiersza poleceń jest wymagany do interfejsu wiersza poleceń FlutterFire, który zainstalujesz za chwilę.

Istnieją różne sposoby instalacji CLI. Wszystkie dostępne opcje dla swojego systemu operacyjnego znajdziesz na stronie firebase.google.com/docs/cli.

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

  1. Zaloguj się w Firebase za pomocą konta Google, uruchamiając to polecenie:
    firebase login
    
  2. To polecenie łączy Twój komputer lokalny z Firebase i daje Ci dostęp do projektów Firebase.
  3. Sprawdź, czy wiersz poleceń jest prawidłowo zainstalowany i czy 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 projekty Firebase wymienione w konsoli Firebase. Powinieneś zobaczyć co najmniej flutterfire-ui-codelab.

Instalowanie interfejsu wiersza poleceń FlutterFire

FlutterFire CLI 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 wiersza poleceń 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ć kod Dart potrzebny do korzystania z Firebase w aplikacji Flutter.

flutterfire configure

Gdy to polecenie zostanie wykonane, pojawi się prośba o wybranie projektu Firebase, którego chcesz użyć, i platform, które chcesz skonfigurować.

Na poniższych zrzutach ekranu widać prompty, na które musisz odpowiedzieć.

  1. Wybierz projekt, którego chcesz użyć. W tym przypadku użyj flutterfire-ui-codelab1359cdeb83204baa.png
  2. Wybierz platformy, których chcesz używać. W tym laboratorium programistycznym znajdziesz instrukcje konfigurowania uwierzytelniania Firebase dla Fluttera na potrzeby wersji internetowej, iOS i Androida, ale możesz też skonfigurować projekt Firebase tak, aby korzystał ze wszystkich opcji. 301c9534f594f472.png
  3. Ten zrzut ekranu przedstawia dane wyjściowe po zakończeniu procesu. Jeśli znasz Firebase, zauważysz, że nie musisz tworzyć aplikacji platformowych (np. aplikacji na Androida) w konsoli. Za Ciebie zrobił to 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. Plik zawiera klasę o nazwie FirebaseOptions, która ma zmienne statyczne zawierające konfigurację Firebase wymaganą na każdej platformie. Jeśli podczas wykonywania zapytania 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 przypadku konkretnej kompilacji na określoną 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ą na internet.

Metoda DefaultFirebaseOptions.currentPlatform używa enumeracji TargetPlatform udostępnianej przez Fluttera, aby wykryć platformę, na której działa aplikacja, a następnie zwraca wartości konfiguracji Firebase potrzebne do prawidłowego zastosowania 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 znajdujesz się w katalogu głównym projektu Flutter w pozycji 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 są to jedyne potrzebne pakiety.

Inicjowanie Firebase

Aby używać dodanych pakietów i funkcji 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 działania.

  1. WidgetsFlutterBinding.ensureInitialized() informuje Fluttera, aby nie uruchamiał kodu widżetu aplikacji, dopóki nie uruchomi się całkowicie framework Fluttera. Firebase korzysta z kanałów natywnych platform, które wymagają uruchomionego frameworku.
  2. Firebase.initializeApp łączy aplikację Flutter z projektem Firebase. Wartość DefaultFirebaseOptions.currentPlatform jest importowana z wygenerowanego pliku firebase_options.dart. Ta wartość statyczna wykrywa, na jakiej platformie działasz, i przekazuje odpowiednie klucze Firebase.

4. Dodawanie początkowej strony uwierzytelniania w interfejsie Firebase

Interfejs Firebase dla usługi Uwierzytelnianie zawiera widżety, które reprezentują całe ekrany w aplikacji. Te ekrany obsługują różne procesy uwierzytelniania w aplikacji, takie jak logowanie, rejestracja, hasło zostało zapomniane czy profil użytkownika. Aby rozpocząć, dodaj do aplikacji stronę docelowa, która będzie pełnić funkcję zabezpieczenia uwierzytelniania dla aplikacji głównej.

Materiał lub aplikacja Cupertino

Aby korzystać z interfejsu FlutterFire, musisz owinąć aplikację w komponent MaterialApp lub CupertinoApp. W zależności od wybranej opcji interfejs będzie automatycznie odzwierciedlał różnice między widżetami Material i Cupertino. W tym ćwiczeniu użyj MaterialApp, który został już dodany do aplikacji w wersji 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 odsłuchanie FirebaseAuthauthStateChanges za pomocą wtyczki uwierzytelniania Firebase.

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

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

Interfejs API authStateChanges zwraca Stream z bieżącym użytkownikiem (jeśli jest zalogowany) lub null, jeśli tak nie jest. Aby subskrybować 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 sam się tworzy na podstawie najnowszego zrzutu danych ze strumienia, który mu przekazujesz. Jest ona automatycznie odtwarzana, gdy Stream wyemituje 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 przekazuje FirebaseAuth.instance.authStateChanged, czyli wspomniany wcześniej strumień, który zwróci obiekt Firebase User, jeśli użytkownik jest uwierzytelniony, w przeciwnym razie zwróci null.
  • Następnie kod używa funkcji snapshot.hasData, aby sprawdzić, czy wartość ze strumienia zawiera obiekt User.
  • Jeśli nie ma żadnego, zwróci widżet SignInScreen. Na razie ten ekran nie będzie miał żadnego zastosowania. 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 interfejsu użytkownika FlutterFire. Na tym skupimy się w następnym kroku tego ćwiczenia. Gdy uruchomisz aplikację, powinien pojawić się pusty ekran logowania.

5. Ekran logowania

Widżet SignInScreen udostępniany przez interfejs FlutterFire UI umożliwia:

  • Zezwalanie użytkownikom na logowanie
  • Jeśli użytkownik zapomni hasło, może kliknąć „Nie pamiętam hasła?”, aby przejść do formularza resetowania hasła.
  • Jeśli użytkownik nie jest jeszcze zarejestrowany, może kliknąć „Zarejestruj się” i zostanie przekierowany do innego formularza, który pozwoli mu się zarejestrować.

To wymaga tylko kilku linii kodu. Przypomnij 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();
      },
    );
  }
}

Widget SignInScreen i jego argument providers to jedyny kod wymagany do uzyskania wszystkich wymienionych funkcji. Powinien wyświetlić się ekran logowania z polami tekstowymi „E-mail” i „Hasło” oraz przyciskiem „Zaloguj się”.

Chociaż jest funkcjonalna, brakuje jej stylu. Widget udostępnia parametry, które umożliwiają dostosowanie wyglądu ekranu logowania. Możesz na przykład dodać logo swojej firmy.

Dostosowywanie ekranu logowania

headerBuilder

Za pomocą argumentu SignInScreen.headerBuilder możesz dodawać 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żyć SignInScreen.sideBuilder, o którym mowa w dalszej części tego Codelab.

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 funkcja zwracająca wartość, która udostępnia wartości, których możesz użyć, np. BuildContextBoxConstraints, oraz wymaga zwrócenia widżetu. Wyświetli się wybrany widżet u góry ekranu. W tym przykładzie nowy kod dodaje obraz u góry ekranu. Twoja aplikacja powinna teraz wyglądać tak.

73d7548d91bbd2ab.png

Subtitle Builder

Ekran logowania zawiera 3 dodatkowe parametry, które umożliwiają jego dostosowywanie: subtitleBuilder, footerBuilder i sideBuilder.

Funkcja subtitleBuilder różni się nieznacznie tym, że argumenty wywołania zwrotnego zawierają działanie o typie AuthAction. AuthAction to typ enumeracji, który umożliwia wykrycie, czy użytkownik znajduje się na ekranie logowania czy rejestracji.

Zaktualizuj kod w pliku auth_gate.dart, aby używać funkcji 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 argument subtitleBuilder. Nie zawiera ona tagów BoxConstraints ani shrinkOffset, ponieważ jest przeznaczona do tekstu, a nie 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 akceptuje wywołanie zwrotne, a tym razem argumentami tego wywołania są BuildContextdouble shrinkOffset. Widżet zwracany przez funkcję sideBuilder będzie wyświetlany po lewej stronie formularza logowania i tylko na szerokich ekranach. Oznacza to, że widżet będzie wyświetlany tylko w aplikacjach internetowych i na komputerach.

Wewnętrznie interfejs FlutterFire używa punktu przełamania, aby określić, czy ma być wyświetlana zawartość nagłówka (na wysokich ekranach, np. na urządzeniach mobilnych) czy zawartość boczna (na szerokich ekranach, na komputerach lub w przeglądarce). Jeśli ekran ma więcej niż 800 pikseli szerokości, wyświetla się zawartość modułu Side Builder, a nie nagłówka. Jeśli ekran ma mniej niż 800 pikseli, 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 rozwinięciu okna aplikacja powinna wyglądać tak (jeśli używasz Fluttera w wersji internetowej lub na macOS).

8dc60b4e5d7dd2d0.png

Tworzenie konta użytkownika

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

Aby korzystać z konsoli:

  1. W konsoli Firebase otwórz tabelę „Użytkownicy”. Wybierz „flutterfire-ui-codelab” lub inny projekt, jeśli użyłeś 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 fałszywe hasło, jak widać na obrazku poniżej. To zadziała, ale funkcja „Nie pamiętam hasła” nie będzie działać, jeśli użyjesz fałszywego adresu e-mail. 62ba0feb33d54add.png
  4. Kliknij „Dodaj użytkownika” 32b236b3ef94d4c7.png

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

dd43d260537f3b1a.png

6. Ekran profilu

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

Dodawanie widżetu ProfileScreen

W edytorze tekstu przejdź do pliku home.dart. 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 to funkcja wywołania zwrotnego przekazana do metody IconButton.isPressed. Gdy naciśniesz IconButton, aplikacja utworzy nową anonimową trasę i przejdzie na nią. Ta ścieżka wyświetli widżet ProfileScreen, który jest zwracany z trybu z powrotem MaterialPageRoute.builder.

Ponownie uruchom aplikację i kliknij ikonę w prawym górnym rogu (na pasku aplikacji). Pojawi się strona:

36487fc4ab4f26a7.png

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

Wyloguj się

Jeśli teraz naciśniesz przycisk „Wyloguj”, aplikacja nie ulegnie zmianie. Spowoduje to wylogowanie, ale nie wrócisz do widżetu AuthGate. Aby to zaimplementować, 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, gdy tworzysz instancję ProfileScreen, przekazujesz jej również listę działań do argumentu ProfileScreen.actions. Te działania są typu FlutterFireUiAction. Istnieje wiele różnych klas, które są podtypami klasy FlutterFireUiAction. Zazwyczaj służą one do określania sposobu reakcji aplikacji na różne zmiany stanu uwierzytelniania. Funkcja SignedOutAction wywołuje funkcję wywołania zwrotnego, którą jej przekazujesz, gdy stan uwierzytelniania Firebase zmienia się na null dla bieżącego użytkownika.

Dodanie wywołania zwrotnego, które wywołuje funkcję Navigator.of(context).pop(), gdy zostanie wywołana funkcja SignedOutAction, spowoduje przejście aplikacji do poprzedniej strony. W tym przykładzie aplikacji jest tylko 1 stała ścieżka, która wyświetla ekran logowania, jeśli użytkownik nie jest zalogowany, lub stronę główną, jeśli jest zalogowany. Ponieważ dzieje się to, gdy użytkownik się wyloguje, aplikacja wyświetli 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 znajdzie się na stronie profilu. Aby rozwiązać ten problem, dodaj do widżetu ProfileScreen pasek aplikacji.

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 dowolny inny widżet AppBar, który został utworzony i przekazany do Scaffold. W tym przykładzie zachowano domyślną funkcję automatycznego dodawania przycisku „Wstecz”, a ekran ma teraz tytuł.

Dodawanie dzieci na ekranie profilu

Widget ProfileScreen ma też opcjonalny argument o nazwie children. Ten argument akceptuje listę widżetów, które są umieszczane pionowo w widżecie Column, które jest już używane wewnętrznie do tworzenia widżetu ProfileScreen. Ten widget Column w metodzie tworzenia ProfileScreen umieści przekazywane przez Ciebie elementy nad przyciskiem „Wyloguj”.

Zaktualizuj kod w miejscu home.dart, aby wyświetlić 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 przez Google na wielu platformach

FlutterFire UI udostępnia też widżety i funkcje umożliwiające uwierzytelnianie się u dostawców zewnętrznych, takich jak Google, Twitter, Facebook, Apple i GitHub.

Aby zintegrować się z uwierzytelnianiem Google, zainstaluj oficjalny wtyczek firebase_ui_oauth_google i jego zależności, które będą obsługiwać natywny proces uwierzytelniania. W terminalu przejdź do katalogu głównego projektu Flutter 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 z uwierzytelnianiem.
  2. Kliknij „Dodaj nowego dostawcę”. 8286fb28be94bf30.png
  3. Wybierz „Google”. c4e28e6f4974be7f.png
  4. Przesuń przełącznik „Włącz” i kliknij „Zapisz”. e74ff86990763826.png
  5. Jeśli pojawi się okno z informacjami o pobieraniu plików konfiguracji, kliknij „Gotowe”.
  6. Sprawdź, czy dostawca logowania Google został dodany. 5329ce0543c90d95.png

Dodawanie przycisku logowania przez Google

Gdy logowanie się w Google jest włączone, dodaj na ekranie logowania widżet, który wyświetla stylizowany przycisk logowania 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();
      },
    );
  }
}

Jedynym nowym kodem jest GoogleProvider(clientId: "YOUR_WEBCLIENT_ID") dodany do konfiguracji widżetu SignInScreen.

Po dodaniu tego elementu ponownie załaduj aplikację. Zobaczysz przycisk logowania w Google.

aca71a46a011bfb5.png

Konfigurowanie przycisku logowania

Przycisk nie działa bez dodatkowej konfiguracji. Jeśli tworzysz aplikację za pomocą Flutter Web, to jest jedyny krok, który musisz wykonać. Inne platformy wymagają wykonania dodatkowych czynności, które opisujemy poniżej.

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

Po wpisaniu identyfikatora klienta internetowego ponownie załaduj aplikację. Jeśli korzystasz z wersji internetowej, po naciśnięciu przycisku „Zaloguj się przez Google” pojawi się nowe okno, które przeprowadzi Cię przez proces logowania w Google. Początkowo wygląda to tak:

14e73e3c9de704bb.png

Konfigurowanie iOS

Aby funkcja działała na iOS, musisz wykonać dodatkowy proces konfiguracji.

  1. konsoli Firebase otwórz ekran Ustawienia projektu. Na karcie zobaczysz 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ż widoczna na zrzucie ekranu. Jeśli podczas wykonywania tego ćwiczenia korzystasz z projektu flutter-codelabs/firebase-auth-flutterfire-ui/start, w miejscu „complete” (ukończono) zobaczysz „start” (rozpoczęto).
  3. Aby pobrać potrzebny plik konfiguracji, kliknij przycisk GoogleServices-Info.plist. f89b3192871dfbe3.png
  4. Przeciągnij pobrany plik do katalogu /ios/Runner w projekcie Flutter.
  5. Otwórz Xcode, uruchamiając to polecenie w terminalu w katalogu głównym projektu: open ios/Runner.xcworkspace
  6. Kliknij prawym przyciskiem myszy katalog Runner i wybierz Dodaj pliki do „Runner”. 858986063a4c5201.png
  7. W menedżerze plików wybierz GoogleService-Info.plist.
  8. W edytorze tekstu (który nie jest Xcode) dodaj atrybuty CFBundleURLTypes podane poniżej do pliku ios/Runner/Info.plist.
    <!-- 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ć wartość GoogleProvider.clientId dodaną w konfiguracji internetowej identyfikatorem klienta powiązanym z Twoim identyfikatorem klienta Firebase na iOS. Najpierw możesz znaleźć 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ść w 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 ponownie uruchomić. W przeciwnym razie uruchom aplikację na iOS.

8. Gratulacje!

Udało Ci się ukończyć ćwiczenie dotyczące interfejsu Firebase Auth dla Fluttera . Gotowy kod tego ćwiczenia z programowania znajdziesz w katalogu firebase-auth-flutterfire-ui/complete na GitHubie.

Omówione zagadnienia

  • Konfigurowanie aplikacji Flutter pod kątem używania Firebase
  • Konfigurowanie projektu Firebase w konsoli Firebase
  • FlutterFire CLI
  • wiersz poleceń Firebase
  • Korzystanie z Uwierzytelniania Firebase
  • Zarządzanie uwierzytelnianiem Firebase w aplikacji Flutter za pomocą interfejsu FlutterFire

Następne kroki

Więcej informacji

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

2a0ad195769368b1.gif