1. 시작하기 전에
이 Codelab에서는 FlutterFire UI 패키지를 사용하여 Flutter 앱에 Firebase 인증을 추가하는 방법을 알아봅니다. 이 패키지를 사용하여 Flutter 앱에 이메일/비밀번호 인증과 Google 로그인 인증을 모두 추가합니다. 또한 Firebase 프로젝트를 설정하고 FlutterFire CLI를 사용하여 Flutter 앱에서 Firebase를 초기화하는 방법도 알아봅니다.
기본 요건
이 Codelab에서는 Flutter를 사용한 경험이 있다고 가정합니다. 그렇지 않은 경우 먼저 기본사항을 학습하는 것이 좋습니다. 다음 링크가 도움이 됩니다.
- Flutter 위젯 프레임워크 둘러보기로 이동
- 첫 Flutter 앱 작성, 1부 Codelab 사용해 보기
Firebase에 대한 경험이 어느 정도 있어야 하지만 Flutter 프로젝트에 Firebase를 추가한 적이 없다면 괜찮습니다. Firebase Console에 익숙하지 않거나 Firebase를 처음 사용하는 경우 먼저 다음 링크를 참조하세요.
만들 항목
이 Codelab에서는 인증에 Firebase를 사용하여 Flutter 앱의 인증 흐름을 빌드하는 방법을 안내합니다. 애플리케이션에는 로그인 화면, '등록' 화면, 비밀번호 복구 화면, 사용자 프로필 화면이 있습니다.
학습할 내용
이 Codelab에서 다루는 내용은 다음과 같습니다.
- Flutter 앱에 Firebase 추가
- Firebase Console 설정
- Firebase CLI를 사용하여 애플리케이션에 Firebase 추가
- FlutterFire CLI를 사용하여 Dart에서 Firebase 구성 생성
- Flutter 앱에 Firebase 인증 추가
- 콘솔에서 Firebase 인증 설정
firebase_ui_auth
패키지로 이메일 및 비밀번호 로그인 추가firebase_ui_auth
패키지로 사용자 등록 추가- '비밀번호 찾기' 페이지 추가
firebase_ui_auth
계정으로 Google 로그인 추가 중- 여러 로그인 제공업체와 호환되도록 앱 구성
firebase_ui_auth
패키지로 애플리케이션에 사용자 프로필 화면 추가
이 Codelab은 특히 firebase_ui_auth
패키지를 사용하여 강력한 인증 시스템을 추가하는 것과 관련이 있습니다. 위의 모든 기능이 포함된 이 전체 앱은 약 100줄의 코드로 구현할 수 있습니다.
필요한 사항
- Flutter에 대한 지식 및 설치된 SDK
- 텍스트 편집기 (JetBrains IDE, Android 스튜디오, VS Code는 Flutter에서 지원됨)
- Google Chrome 브라우저 또는 개발자가 선호하는 다른 Flutter 개발 타겟 (이 Codelab의 일부 터미널 명령어는 Chrome에서 앱을 실행한다고 가정합니다.)
2. Firebase 프로젝트 만들기 및 설정
먼저 Firebase 웹 콘솔에서 Firebase 프로젝트를 만들어야 합니다.
Firebase 프로젝트 만들기
- Firebase에 로그인합니다.
- Firebase Console에서 프로젝트 추가(또는 프로젝트 만들기)를 클릭하고 Firebase 프로젝트의 이름을 입력합니다(예: 'FlutterFire-UI-Codelab').
- 프로젝트 만들기 옵션을 클릭하여 진행합니다. 메시지가 표시되면 Firebase 약관에 동의합니다. 이 앱에는 애널리틱스를 사용하지 않으므로 Google 애널리틱스 설정을 건너뜁니다.
Firebase 프로젝트에 관해 자세히 알아보려면 Firebase 프로젝트 이해를 참고하세요.
Firebase 인증에 이메일 로그인 사용 설정
빌드 중인 앱은 Firebase 인증을 사용하여 사용자가 앱에 로그인할 수 있도록 합니다. 또한 신규 사용자가 Flutter 애플리케이션에서 등록할 수 있습니다.
Firebase 인증은 Firebase Console을 사용하여 사용 설정해야 하며 사용 설정한 후에는 특별한 구성이 필요합니다.
사용자가 웹 앱에 로그인하도록 허용하려면 먼저 이메일/비밀번호 로그인 방법을 사용해야 합니다. 나중에 Google 로그인 메서드를 추가합니다.
- Firebase Console에서 왼쪽 패널의 빌드 메뉴를 펼칩니다.
- 인증을 클릭한 후 시작하기 버튼을 클릭한 다음 로그인 방법 탭을 클릭합니다(또는 여기를 클릭하여 로그인 방법 탭으로 바로 이동).
- 로그인 제공업체 목록에서 이메일/비밀번호를 클릭하고 사용 설정 스위치를 켜짐 위치로 설정한 다음 저장을 클릭합니다.
3. Flutter 앱 설정
시작하기 전에 시작 코드를 다운로드하고 Firebase CLI를 설치해야 합니다.
시작 코드 가져오기
명령줄에서 GitHub 저장소를 클론합니다.
git clone https://github.com/flutter/codelabs.git flutter-codelabs
또는 GitHub의 CLI 도구가 설치되어 있는 경우:
gh repo clone flutter/codelabs flutter-codelabs
샘플 코드는 컴퓨터의 flutter-codelabs
디렉터리에 클론해야 합니다. 이 디렉터리에는 Codelab 모음의 코드가 포함되어 있습니다. 이 Codelab의 코드는 하위 디렉터리 flutter-codelabs/firebase-auth-flutterfire-ui
에 있습니다.
flutter-codelabs/firebase-auth-flutterfire-ui
디렉터리에는 두 개의 Flutter 프로젝트가 포함되어 있습니다. 하나는 complete
이고 다른 하나는 start
입니다. start
디렉터리에는 불완전한 프로젝트가 포함되어 있으며, 이 디렉터리에 가장 많은 시간을 할애하게 됩니다.
cd flutter-codelabs/firebase-auth-flutterfire-ui/start
앞으로 건너뛰거나 완료된 상태가 어떤지 확인하려면 complete라는 디렉터리에서 교차 참조하세요.
Codelab을 따라하면서 직접 코드를 추가하려면 flutter-codelabs/firebase-auth-flutterfire-ui/start
의 Flutter 앱으로 시작하고 Codelab을 진행하면서 해당 프로젝트에 코드를 추가해야 합니다. 해당 디렉터리를 열거나 원하는 IDE로 가져옵니다.
Firebase CLI 설치
Firebase CLI는 Firebase 프로젝트 관리를 위한 도구를 제공합니다. 잠시 후에 설치하게 될 FlutterFire CLI에는 CLI가 필요합니다.
CLI를 설치하는 방법에는 여러 가지가 있습니다. MacOS 또는 Linux를 사용하는 경우 가장 간단한 방법은 터미널에서 다음 명령어를 실행하는 것입니다.
curl -sL https://firebase.tools | bash
CLI를 설치한 후에는 Firebase로 인증해야 합니다.
- 다음 명령어를 실행하여 Google 계정으로 Firebase에 로그인합니다.
firebase login
- 이 명령어는 로컬 머신을 Firebase에 연결하고 Firebase 프로젝트에 대한 액세스 권한을 부여합니다.
- Firebase 프로젝트를 나열하여 CLI가 올바르게 설치되었고 사용자 계정에 액세스할 수 있는지 테스트합니다. 다음 명령어를 실행합니다.
firebase projects:list
- 표시된 목록은 Firebase Console에 나열된 Firebase 프로젝트와 같아야 합니다. 최소
flutterfire-ui-codelab.
이(가) 표시됩니다.
FlutterFire CLI 설치
FlutterFire CLI는 Flutter 앱에서 지원되는 모든 플랫폼에서 Firebase를 쉽게 설치할 수 있도록 도와주는 도구입니다. Firebase CLI를 기반으로 빌드되었습니다.
먼저 CLI를 설치합니다.
dart pub global activate flutterfire_cli
CLI가 설치되었는지 확인합니다. 다음 명령어를 실행하고 CLI가 도움말 메뉴를 출력하는지 확인합니다.
flutterfire -—help
Flutter 앱에 Firebase 프로젝트 추가
FlutterFire 구성
FlutterFire를 사용하여 Flutter 앱에서 Firebase를 사용하는 데 필요한 Dart 코드를 생성할 수 있습니다.
flutterfire configure
이 명령어를 실행하면 사용할 Firebase 프로젝트와 설정할 플랫폼을 선택하라는 메시지가 표시됩니다.
다음 스크린샷은 응답해야 하는 프롬프트를 보여줍니다.
- 사용할 프로젝트를 선택합니다. 이 경우
flutterfire-ui-codelab
를 사용합니다. - 사용하려는 플랫폼을 선택합니다. 이 Codelab에서는 웹, iOS, Android용 Flutter의 Firebase 인증을 구성하는 단계를 설명하지만 모든 옵션을 사용하도록 Firebase 프로젝트를 설정할 수 있습니다.
- 이 스크린샷은 프로세스 종료 시의 출력을 보여줍니다. Firebase에 익숙하다면 콘솔에서 플랫폼 애플리케이션 (예: Android 애플리케이션)을 만들 필요가 없었고 FlutterFire CLI가 이 작업을 완료했다는 사실을 아실 것입니다.
완료되면 텍스트 편집기에서 Flutter 앱을 확인합니다. FlutterFire CLI에서 firebase_options.dart
라는 새 파일을 생성했습니다. 이 파일에는 각 플랫폼에 필요한 Firebase 구성을 보유하는 정적 변수가 있는 FirebaseOptions라는 클래스가 포함되어 있습니다. flutterfire configure
를 실행할 때 모든 플랫폼을 선택한 경우 web
, android
, ios
, macos
라는 정적 값이 표시됩니다.
firebase_options.dart
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
// ignore: missing_enum_constant_in_switch
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
}
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에서는 Firebase 프로젝트의 특정 플랫폼에 대한 특정 빌드를 나타내는 데 애플리케이션이라는 단어를 사용합니다. 예를 들어 FlutterFire-ui-codelab이라는 Firebase 프로젝트에는 Android용, iOS용, MacOS용, 웹용 애플리케이션이 각각 하나씩 있습니다.
DefaultFirebaseOptions.currentPlatform
메서드는 Flutter에서 노출하는 TargetPlatform
enum을 사용하여 앱이 실행 중인 플랫폼을 감지한 다음 올바른 Firebase 애플리케이션에 필요한 Firebase 구성 값을 반환합니다.
Flutter 앱에 Firebase 패키지 추가
마지막 설정 단계는 Flutter 프로젝트에 관련 Firebase 패키지를 추가하는 것입니다. firebase_options.dart
파일에는 아직 추가되지 않은 Firebase 패키지를 사용하므로 오류가 있습니다. 터미널에서 flutter-codelabs/firebase-emulator-suite/start
의 Flutter 프로젝트 루트에 있는지 확인합니다. 그런 후 다음 세 가지 명령어를 실행합니다.
flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add firebase_ui_auth
현재로서는 이 패키지들만 필요합니다.
Firebase 초기화
추가된 패키지를 사용하려면 DefaultFirebaseOptions.currentPlatform,
가 main.dart
파일의 main
함수에서 코드를 업데이트합니다.
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
이 코드는 두 가지 작업을 실행합니다.
WidgetsFlutterBinding.ensureInitialized()
는 Flutter 프레임워크가 완전히 부팅될 때까지 애플리케이션 위젯 코드 실행을 시작하지 말라고 Flutter에 지시합니다. Firebase는 프레임워크가 실행되어야 하는 네이티브 플랫폼 채널을 사용합니다.Firebase.initializeApp
는 Flutter 앱과 Firebase 프로젝트 간의 연결을 설정합니다.DefaultFirebaseOptions.currentPlatform
는 생성된firebase_options.dart
파일에서 가져옵니다. 이 정적 값은 실행 중인 플랫폼을 감지하고 해당 Firebase 키를 전달합니다.
4. 초기 Firebase UI 인증 페이지 추가
인증용 Firebase UI는 애플리케이션의 전체 화면을 나타내는 위젯을 제공합니다. 이러한 화면은 로그인, 등록, 비밀번호 찾기, 사용자 프로필 등 애플리케이션 전체에서 다양한 인증 흐름을 처리합니다. 시작하려면 기본 애플리케이션의 인증 가드 역할을 하는 방문 페이지를 앱에 추가합니다.
Material 또는 Cupertino 앱
FlutterFire UI를 사용하려면 애플리케이션을 MaterialApp 또는 CupertinoApp으로 래핑해야 합니다. 선택에 따라 UI에 Material 또는 Cupertino 위젯의 차이가 자동으로 반영됩니다. 이 Codelab에서는 app.dart
의 앱에 이미 추가된 MaterialApp
를 사용합니다.
app.dart
import 'package:flutter/material.dart';
import 'auth_gate.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const AuthGate(),
);
}
}
인증 상태 확인
로그인 화면을 표시하려면 먼저 사용자가 현재 인증되었는지 확인해야 합니다. 이를 확인하는 가장 일반적인 방법은 Firebase 인증 플러그인을 사용하여 FirebaseAuth의 authStateChanges를 리슨하는 것입니다.
위의 코드 샘플에서 MaterialApp
는 build 메서드에서 AuthGate
위젯을 빌드하고 있습니다. (이는 맞춤 위젯이며 FlutterFire UI에서 제공하지 않습니다.)
authStateChanges
스트림을 포함하도록 위젯을 업데이트해야 합니다.
authStateChanges
API는 현재 사용자 (로그인한 경우) 또는 로그인하지 않은 경우 null을 포함하는 Stream
을 반환합니다. 애플리케이션에서 이 상태를 구독하려면 Flutter의 StreamBuilder 위젯을 사용하고 스트림을 전달하면 됩니다.
StreamBuilder
는 전달된 스트림의 데이터의 최신 스냅샷을 기반으로 자체 빌드되는 위젯입니다. 스트림에서 새 스냅샷을 내보낼 때 자동으로 다시 빌드됩니다.
auth_gate.dart
에서 코드를 업데이트합니다.
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});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [],
);
}
return const HomeScreen();
},
);
}
}
StreamBuilder.stream
에는 앞서 언급한 스트림인FirebaseAuth.instance.authStateChanged
가 전달되며, 이는 사용자가 인증한 경우 FirebaseUser
객체를 반환합니다. 그렇지 않으면null
을 반환합니다.- 다음으로 코드는
snapshot.hasData
를 사용하여 스트림의 값에User
객체가 포함되어 있는지 확인합니다. - 없으면
SignInScreen
위젯을 반환합니다. 현재 이 화면에서는 아무것도 할 수 없습니다. 다음 단계에서 업데이트됩니다. - 그렇지 않으면 인증된 사용자만 액세스할 수 있는 애플리케이션의 기본 부분인
HomeScreen
를 반환합니다.
SignInScreen
는 FlutterFire UI 패키지에서 가져온 위젯입니다. 이 내용은 이 Codelab의 다음 단계에서 다룹니다. 이 시점에서 앱을 실행하면 빈 로그인 화면이 표시됩니다.
5. 로그인 화면
FlutterFire UI에서 제공하는 SignInScreen
위젯은 다음 기능을 추가합니다.
- 사용자의 로그인 허용
- 사용자가 비밀번호를 잊어버린 경우 '비밀번호를 잊으셨나요?'를 탭하면 비밀번호 재설정 양식이 표시됩니다.
- 사용자가 아직 등록되지 않은 경우 '등록'을 탭하면 가입할 수 있는 다른 양식으로 이동합니다.
이 작업에는 코드 몇 줄만 있으면 됩니다. AuthGate 위젯의 코드를 호출합니다.
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});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(), // new
],
);
}
return const HomeScreen();
},
);
}
}
SignInScreen
위젯과 위젯의 providers
인수는 앞서 언급한 모든 기능을 가져오는 데 필요한 유일한 코드입니다. 이제 '이메일'과 '비밀번호' 텍스트 입력과 '로그인' 버튼이 있는 로그인 화면이 표시됩니다.
기능적이긴 하지만 스타일은 없습니다. 위젯은 로그인 화면의 모양을 맞춤설정하는 매개변수를 노출합니다. 예를 들어 회사 로고를 추가할 수 있습니다.
로그인 화면 맞춤설정
헤더 빌더
SignInScreen.headerBuilder
인수를 사용하여 로그인 양식 위에 원하는 위젯을 추가할 수 있습니다. 이 위젯은 휴대기기와 같이 좁은 화면에만 표시됩니다. 넓은 화면에서는 이 Codelab의 후반부에서 설명하는 SignInScreen.sideBuilder
를 사용할 수 있습니다.
다음 코드를 사용하여 auth_gate.dart
파일을 업데이트합니다.
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});
@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'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
headerBuilder 인수에는 FlutterFire UI 패키지에 정의된 HeaderBuilder 유형의 함수가 필요합니다.
typedef HeaderBuilder = Widget Function(
BuildContext context,
BoxConstraints constraints,
double shrinkOffset,
);
콜백이므로 사용할 수 있는 값(예: BuildContext
및 BoxConstraints
)을 노출하며 위젯을 반환해야 합니다. 어떤 위젯을 반환하든 화면 상단에 표시됩니다. 이 예에서 새 코드는 화면 상단에 이미지를 추가합니다. 이제 애플리케이션이 다음과 같이 표시됩니다.
자막 빌더
로그인 화면은 화면을 맞춤설정할 수 있는 세 가지 매개변수(subtitleBuilder
, footerBuilder
, sideBuilder
)를 추가로 노출합니다.
subtitleBuilder
는 콜백 인수에 AuthAction
유형의 작업이 포함된다는 점에서 약간 다릅니다. AuthAction
는 사용자가 있는 화면이 '로그인' 화면인지 '등록' 화면인지 감지하는 데 사용할 수 있는 enum입니다.
subtitleBuilder를 사용하도록 auth_gate.dart의 코드를 업데이트합니다.
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});
@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('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!'),
);
},
);
}
return const HomeScreen();
},
);
}
}
애플리케이션을 새로고침하면 다음과 같이 표시됩니다.
바닥글 작성 도구
footerBuilder 인수는 subtitleBuilder와 동일합니다. 이미지가 아닌 텍스트용이므로 BoxConstraints
또는 shrinkOffset
를 노출하지 않습니다. 그러나 위젯은 원하는 대로 추가할 수 있습니다.
이 코드를 사용하여 로그인 화면에 바닥글을 추가하세요.
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});
@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('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),
),
);
},
);
}
return const HomeScreen();
},
);
}}
측면 빌더
SignInScreen.sidebuilder 인수는 콜백을 허용하며, 이번에는 이 콜백의 인수는 BuildContext
및 double shrinkOffset
입니다. sideBuilder가 반환하는 위젯은 로그인 양식의 왼쪽에 표시되며 와이드 스크린에만 표시됩니다. 즉, 위젯은 데스크톱 및 웹 앱에만 표시됩니다.
내부적으로 FlutterFire UI는 중단점을 사용하여 헤더 콘텐츠를 표시해야 하는지 (모바일과 같은 긴 화면) 또는 측면 콘텐츠를 표시해야 하는지 (와이드 화면, 데스크톱 또는 웹) 결정합니다. 특히 화면 너비가 800픽셀을 초과하면 측면 빌더 콘텐츠가 표시되고 헤더 콘텐츠는 표시되지 않습니다. 화면의 너비가 800픽셀 미만이면 그 반대입니다.
auth_gate.dart의 코드를 업데이트하여 sideBuilder 위젯을 추가합니다.
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});
@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('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();
},
);
}
}
이제 창의 너비를 확장할 때 앱이 다음과 같이 표시됩니다 (Flutter 웹 또는 MacOS를 사용하는 경우).
사용자 생성
이제 이 화면의 모든 코드가 완성되었습니다. 하지만 로그인하기 전에 사용자를 만들어야 합니다. '등록' 화면을 사용하거나 Firebase Console에서 사용자를 만들 수 있습니다.
콘솔을 사용하려면 다음 안내를 따르세요.
- Firebase Console에서 '사용자' 표로 이동합니다.
- 여기를 클릭하세요
- 'flutterfire-ui-codelab'(또는 다른 이름을 사용한 경우 다른 프로젝트)을 선택합니다. 다음과 같은 표가 표시됩니다.
- '사용자 추가' 버튼을 클릭합니다.
- 새 사용자의 이메일 주소와 비밀번호를 입력합니다. 아래 이미지에 입력한 이메일과 비밀번호는 가짜일 수 있습니다. 가짜 이메일 주소를 사용할 경우 작동하지만 '비밀번호 찾기' 기능은 작동하지 않습니다.
- '사용자 추가'를 클릭합니다.
이제 Flutter 애플리케이션으로 돌아가 로그인 페이지를 통해 사용자를 로그인할 수 있습니다. 앱은 다음과 같이 표시됩니다.
6. 프로필 화면
FlutterFire UI는 ProfileScreen
위젯도 제공합니다. 이 위젯도 몇 줄의 코드로 많은 기능을 제공합니다.
ProfileScreen 위젯 추가
텍스트 편집기에서 home.dart
파일로 이동합니다. 다음 코드를 사용하여 업데이트합니다.
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: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
주목할 만한 새 코드는 IconButton.isPressed method.
에 전달된 콜백입니다. 이 IconButton
가 눌리면 애플리케이션이 새 익명의 경로를 만들고 해당 경로로 이동합니다. 이 경로에는 MaterialPageRoute.builder
콜백에서 반환된 ProfileScreen
위젯이 표시됩니다.
앱을 새로고침하고 오른쪽 상단 (앱 바)의 아이콘을 푸시하면 다음과 같은 페이지가 표시됩니다.
FlutterFire UI 페이지에서 제공하는 표준 UI입니다. 모든 버튼과 텍스트 필드는 Firebase 인증에 연결되어 즉시 사용할 수 있습니다. 예를 들어 '이름' 텍스트 필드에 이름을 입력하면 FlutterFire UI에서 FirebaseAuth.instance.currentUser?.updateDisplayName
메서드를 호출하여 Firebase에 이름을 저장합니다.
로그아웃
지금은 '로그아웃' 버튼을 눌러도 앱이 변경되지 않습니다. 그러면 로그아웃되지만 AuthGate 위젯으로 다시 이동하지 않습니다. 이를 구현하려면 ProfileScreen.actions 매개변수를 사용합니다.
먼저 home.dart의 코드를 업데이트합니다.
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: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
이제 ProfileScreen
의 인스턴스를 만들 때 작업 목록도 ProfileScreen.actions
인수에 전달합니다. 이러한 작업은 FlutterFireUiAction
유형입니다. FlutterFireUiAction
의 하위유형인 클래스가 많이 있으며 일반적으로 이러한 클래스를 사용하여 앱에 다양한 인증 상태 변경에 반응하도록 지시합니다. SignedOutAction은 Firebase 인증 상태가 null인 currentUser로 변경될 때 개발자가 제공하는 콜백 함수를 호출합니다.
SignedOutAction이 트리거될 때 Navigator.of(context).pop()
를 호출하는 콜백을 추가하면 앱이 이전 페이지로 이동합니다. 이 예시 앱에는 로그인한 사용자가 없는 경우 로그인 페이지를 표시하고 사용자가 있는 경우 홈페이지를 표시하는 영구 경로가 하나만 있습니다. 이는 사용자가 로그아웃할 때 발생하므로 앱에 로그인 페이지가 표시됩니다.
프로필 페이지 맞춤설정
로그인 페이지와 마찬가지로 프로필 페이지도 맞춤설정할 수 있습니다. 첫째, 현재 페이지에서는 사용자가 프로필 페이지에 있으면 홈페이지로 돌아갈 수 없습니다. ProfileScreen 위젯에 AppBar를 제공하여 이 문제를 해결합니다.
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: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
ProfileScreen.appBar
인수는 Flutter Material 패키지의 AppBar
위젯을 허용하므로 빌드하고 Scaffold
에 전달한 다른 AppBar
처럼 취급할 수 있습니다. 이 예에서는 '뒤로' 버튼을 자동으로 추가하는 기본 기능이 유지되고 이제 화면에 제목이 있습니다.
프로필 화면에 자녀 추가하기
ProfileScreen 위젯에는 하위 요소라는 선택적 인수도 있습니다. 이 인수는 위젯 목록을 허용하며, 해당 위젯은 ProfileScreen을 빌드하는 데 이미 내부적으로 사용되는 Column 위젯 내부에 세로로 배치됩니다. ProfileScreen 빌드 메서드의 이 Column 위젯은 전달한 하위 요소를 '로그아웃' 버튼 위에 배치합니다.
로그인 화면과 유사하게 여기에 회사 로고가 표시되도록 home.dart의 코드를 업데이트합니다.
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: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
앱을 새로고침하면 화면에 다음과 같이 표시됩니다.
7. 멀티플랫폼 Google 인증 로그인
FlutterFire UI는 Google, 트위터, Facebook, Apple, GitHub와 같은 서드 파티 제공업체로 인증하기 위한 위젯과 기능도 제공합니다.
Google 인증과 통합하려면 네이티브 인증 흐름을 처리하는 공식 firebase_ui_oauth_google 플러그인과 종속 항목을 설치합니다. 터미널에서 Flutter 프로젝트의 루트로 이동하여 다음 명령어를 입력합니다.
flutter pub add google_sign_in flutter pub add firebase_ui_oauth_google
Google 로그인 제공업체 사용 설정
그런 다음 Firebase Console에서 Google 제공업체를 사용 설정합니다.
- 콘솔에서 인증 로그인 제공업체 화면으로 이동합니다.
- '새 제공업체 추가'를 클릭합니다.
- 'Google'을 선택합니다.
- '사용'이라고 라벨이 지정된 스위치를 전환하고 '저장'을 누릅니다.
- 구성 파일 다운로드에 관한 정보가 포함된 모달이 표시되면 '완료'를 클릭합니다.
- Google 로그인 제공업체가 추가되었는지 확인합니다.
Google 로그인 버튼 추가
Google 로그인을 사용 설정한 상태에서 양식화된 Google 로그인 버튼을 표시하는 데 필요한 위젯을 로그인 페이지에 추가합니다. auth_gate.dart 파일로 이동하여 코드를 다음과 같이 업데이트합니다.
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'; // new
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
GoogleProvider(clientId: "YOUR_WEBCLIENT_ID"), // new
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('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();
},
);
}
}
여기서 유일하게 새로운 코드는 SignInScreen 위젯 구성에 GoogleProvider(clientId: "YOUR_WEBCLIENT_ID")
를 추가한 것입니다.
추가한 후 앱을 새로고침하면 Google 로그인 버튼이 표시됩니다.
로그인 버튼 구성
추가 구성이 없으면 버튼이 작동하지 않습니다. Flutter Web으로 개발하는 경우 이 작업을 실행하기 위해 추가해야 하는 유일한 단계입니다. 다른 플랫폼에는 추가 단계가 필요한데, 이 단계는 약간 다루겠습니다.
- Firebase Console에서 인증 제공업체 페이지로 이동합니다.
- Google 제공업체를 클릭합니다.
- '웹 SDK 구성' 확장 패널을 클릭합니다.
- '웹 클라이언트 ID' 에서 값을 복사합니다.
- 텍스트 편집기로 돌아가서 이 ID를 이름이
clientId
인 매개변수에 전달하여auth_gate.dart
파일의GoogleProvider
인스턴스를 업데이트합니다.
GoogleProvider(
clientId: "YOUR_WEBCLIENT_ID"
)
웹 클라이언트 ID를 입력한 후 앱을 새로고침합니다. 'Google 계정으로 로그인' 버튼을 누르면 웹을 사용하는 경우 Google 로그인 흐름을 안내하는 새 창이 표시됩니다. 처음에는 다음과 같이 표시됩니다.
iOS 구성
iOS에서 이 기능을 사용하려면 추가 구성 프로세스가 필요합니다.
- Firebase Console에서 프로젝트 설정 화면으로 이동합니다. 다음과 같은 Firebase 앱이 나열된 카드가 표시됩니다.
- iOS를 클릭합니다. 애플리케이션 이름은 저와 다릅니다.
flutter-codelabs/firebase-auth-flutterfire-ui/start
프로젝트를 사용하여 이 Codelab을 따라 했다면 '완료'라고 표시된 부분에 '시작'이라고 표시됩니다. - 'GoogleServices-Info.plist' 버튼을 클릭하여 필요한 구성 파일을 다운로드합니다.
- 다운로드한 파일을 라는 디렉터리로 드래그 앤 드롭합니다.Flutter 프로젝트의
/ios/Runner
- 프로젝트 루트에서 다음 터미널 명령어를 실행하여 Xcode를 엽니다.
open ios/Runner.xcworkspace
- Runner 디렉터리를 마우스 오른쪽 버튼으로 클릭하고 Add Files to 'Runner'를 선택합니다.
- 파일 관리자에서 GoogleService-Info.plist를 선택합니다.
- 텍스트 편집기 (Xcode 아님)로 돌아가서 아래의 CFBundleURLTypes 속성을 [my_project]/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 -->
- 웹 설정에 추가한
GoogleProvider.clientId
를 Firebase iOS 클라이언트 ID와 연결된 클라이언트 ID로 바꿔야 합니다. 먼저firebase_options.dart
파일에서iOS
상수의 일부로 이 ID를 찾을 수 있습니다.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',
);
- 이 값을
AuthGate
위젯의GoogleProvider.clientId
인수에 붙여넣습니다.
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';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
GoogleProvider(clientId: "YOUR IOS CLIENT ID"), // replace String
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('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();
},
);
}
}
Flutter 앱이 이미 iOS에서 실행 중인 경우 완전히 종료한 다음 애플리케이션을 다시 실행해야 합니다. 그렇지 않으면 iOS에서 앱을 실행합니다.
8. 수고하셨습니다.
Flutter용 Firebase 인증 UI Codelab을 완료했습니다. 이 Codelab의 완료된 코드는 github의 'complete' 디렉터리(Flutter Codelabs)에서 확인할 수 있습니다.
학습한 내용
- Firebase를 사용하도록 Flutter 앱 설정
- Firebase Console에서 Firebase 프로젝트 설정
- FlutterFire CLI
- Firebase CLI
- Firebase 인증 사용
- FlutterFire UI를 사용하여 Flutter 앱에서 Firebase 인증을 쉽게 처리
다음 단계
- Flutter에서 Firestore 및 인증을 사용하는 방법 자세히 알아보기: Flutter용 Firebase 알아보기 Codelab
- Flutter 애플리케이션을 빌드하는 데 사용할 수 있는 다른 Firebase 도구를 살펴보세요.
- Cloud Storage
- Cloud Functions
- 실시간 데이터베이스
자세히 알아보기
- Firebase 사이트: firebase.google.com
- Flutter 사이트: flutter.dev
- FlutterFire Firebase Flutter 위젯: firebase.flutter.dev
- Firebase YouTube 채널
- Flutter YouTube 채널
Sparky가 여러분과 함께 축하해 주세요.