Google은 흑인 공동체를 위한 인종적 평등을 추구하기 위해 노력하고 있습니다. 자세히 알아보기

Flutter용 Firebase 알아보기

이 코드 랩, 당신은의 몇 가지 기본 사항 알아 보겠습니다 중포 기지를 안드로이드 및 iOS 용 플러터 모바일 애플 리케이션을 만들 수 있습니다.

전제 조건

이 코드 랩은 떨림을 잘 알고있는 가정, 당신은 설치 한 떨림 SDK편집기를 .

당신이 만들 것

이 코드랩에서는 Flutter를 사용하여 Android, iOS, 웹 및 macOS에서 이벤트 RSVP 및 방명록 채팅 앱을 빌드합니다. Firebase 인증으로 사용자를 인증하고 Cloud Firestore를 사용하여 데이터를 동기화합니다.

필요한 것

다음 기기 중 하나를 사용하여 이 코드랩을 실행할 수 있습니다.

위 항목 외에도 다음이 필요합니다.

  • Chrome과 같이 선택한 브라우저.
  • 개의 IDE 또는 같은 당신의 선택의 텍스트 편집기, 안드로이드 스튜디오 또는 VS 코드 다트와 떨림 플러그인으로 구성.
  • 최신 stable 버전 플러터 (또는 beta 당신이 가장자리에 살고 즐길 경우).
  • Firebase 프로젝트를 만들고 관리하기 위한 Gmail 계정과 같은 Google 계정입니다.
  • Codelab의 샘플 코드입니다. 코드를 얻는 방법은 다음 단계를 참조하십시오.

GitHub에서 프로젝트의 초기 버전을 다운로드하여 시작하겠습니다.

복제 GitHub의 저장소 명령 줄에서을 :

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

또한, 당신이있는 경우 GitHub의의 CLI 도구를 설치 :

gh repo clone flutter/codelabs flutter-codelabs

샘플 코드로 복제해야 flutter-codelabs 코드 랩의 컬렉션에 대한 코드를 포함하는 디렉토리. 이 코드 랩에 대한 코드에 flutter-codelabs/firebase-get-to-know-flutter .

아래의 디렉토리 구조 flutter-codelabs/firebase-get-to-know-flutter 는 각각의 이름이 단계의 끝에 있어야 할 곳에의 일련의 스냅 샷입니다. 이것은 2단계이므로 일치하는 파일을 찾는 것은 다음과 같이 쉽습니다.

cd flutter-codelabs/firebase-get-to-know-flutter/step_02

앞으로 건너뛰고 싶거나 단계 후의 모습을 보려면 관심 있는 단계의 이름을 따서 명명된 디렉토리를 살펴보십시오.

시작 앱 가져오기

열기는 가져 오거나 flutter-codelabs/firebase-get-to-know-flutter/step_02 선호하는 IDE로 디렉토리. 이 디렉토리에는 아직 작동하지 않는 Flutter 모임 앱으로 구성된 코드랩의 시작 코드가 포함되어 있습니다.

작업할 파일 찾기

이 앱의 코드는 여러 디렉터리에 분산되어 있습니다. 이 기능 분할은 기능별로 코드를 그룹화하여 작업하기 쉽도록 설계되었습니다.

프로젝트에서 다음 파일을 찾습니다.

  • lib/main.dart :이 파일은 주 진입 점 및 응용 프로그램 위젯이 포함되어 있습니다.
  • lib/src/widgets.dart :이 파일은 도움말 표준화 위젯 소수의 응용 프로그램의 스타일이 포함되어 있습니다. 이들은 스타터 앱의 화면을 구성하는 데 사용됩니다.
  • lib/src/authentication.dart :이 파일의 부분적인 구현이 포함되어 FirebaseUI 인증 중포 기지 이메일 기반의 인증을위한 로그인 사용자 경험을 제공하는 위젯 세트를. 인증 흐름을 위한 이러한 위젯은 아직 시작 앱에서 사용되지 않지만 곧 연결할 것입니다.

나머지 응용 프로그램을 구축하는 데 필요한 추가 파일을 추가합니다.

검토 lib/main.dart 파일을

이 응용 프로그램은 활용 google_fonts 전체 응용 프로그램을 통해 Roboto로에게 기본 글꼴을 할 수있게하는 패키지. 동기를 독자들에게 운동을 탐구하는 것입니다 fonts.google.com을 당신이 응용 프로그램의 다른 부분이 발견 글꼴을 사용합니다.

당신의 도우미 위젯 활용하고 lib/src/widgets.dart 의 형태로 Header , ParagraphIconAndDetail . 이 위젯에 설명 된 페이지 레이아웃에 혼란을 줄일 HomePage 중복 코드를 제거하여. 이것은 일관된 모양과 느낌을 가능하게 하는 추가적인 이점이 있습니다.

Android, iOS, 웹 및 macOS에서 앱이 어떻게 표시되는지는 다음과 같습니다.

앱 미리보기

이벤트 정보를 표시하는 것은 게스트에게 유용하지만 이벤트를 표시하는 것만으로는 누구에게나 그다지 유용하지 않습니다. 이 앱에 몇 가지 동적 기능을 추가해 보겠습니다. 이를 위해서는 Firebase를 앱에 연결해야 합니다. Firebase를 시작하려면 Firebase 프로젝트를 만들고 설정해야 합니다.

Firebase 프로젝트 만들기

  1. 로그인 중포 기지 .
  2. 중포 기지 콘솔에서 클릭 프로젝트 추가 (또는 프로젝트를 생성) 및 중포 기지 프로젝트 중포 기지 - 떨림 - 코드 랩의 이름을 지정합니다.

4395e4e67c08043a.png

  1. 프로젝트 생성 옵션을 클릭합니다. 메시지가 표시되면 Firebase 약관에 동의합니다. 이 앱에 Analytics를 사용하지 않을 것이기 때문에 Google Analytics 설정을 건너뛰십시오.

b7138cde5f2c7b61.png

중포 기지 프로젝트에 대한 자세한 내용은 다음 페이지를 참조 중포 기지 프로젝트를 이해합니다 .

빌드 중인 앱은 웹 앱에 사용할 수 있는 여러 Firebase 제품을 사용합니다.

  • 인증 중포 기지는 사용자가 앱에 로그인 할 수 있습니다.
  • 클라우드 경우 FireStore는 클라우드에 구조화 된 데이터를 저장할 때 데이터가 변경 즉시 알림을받을 수 있습니다.
  • 중포 기지 보안 규칙 데이터베이스를 고정합니다.

이러한 제품 중 일부는 특별한 구성이 필요하거나 Firebase 콘솔을 사용하여 활성화해야 합니다.

이메일 중포 기지 인증을위한 로그인에 사용

사용자가 웹 앱에 로그인 할 수 있도록하려면이 코드 랩에 대한 방법에 로그인 이메일 / 비밀번호 사용합니다 :

  1. 중포 기지 콘솔에서, 왼쪽 패널에서 빌드 메뉴를 확장합니다.
  2. 인증을 클릭 한 다음 가져 오기 시작 버튼을 누른 다음 방법 로그인 탭을 클릭합니다 (또는 여기를 클릭하여 로그인-의 방법 탭으로 바로 이동합니다).
  3. 위치에있는 스위치를 사용하고 저장을 클릭 설정, 공급자 로그인 목록에서 이메일 / 비밀번호를 클릭합니다. 58e3e3e23c2f16a4.png

Cloud Firestore 사용

웹 응용 프로그램은 사용하는 클라우드 경우 FireStore을 채팅 메시지를 저장하고 새 채팅 메시지를 수신 할 수 있습니다.

Cloud Firestore 활성화:

  1. 중포 기지 콘솔의 빌드 섹션에서 클라우드 경우 FireStore을 클릭합니다.
  2. 데이터베이스 만들기를 클릭합니다. 99e8429832d23fa3.png
  1. 테스트 모드 옵션에서 시작을 선택합니다. 보안 규칙에 대한 면책 ​​조항을 읽으십시오. 테스트 모드를 사용하면 개발 중에 데이터베이스에 자유롭게 쓸 수 있습니다. 다음을 클릭합니다. 6be00e26c72ea032.png
  1. 데이터베이스 위치를 선택합니다(기본값만 사용할 수 있음). 이 위치는 나중에 변경할 수 없습니다. 278656eefcfb0216.png
  2. 사용을 클릭합니다.

Flutter와 함께 Firebase를 사용하려면 FlutterFire 라이브러리를 올바르게 활용하도록 Flutter 프로젝트를 구성하는 프로세스를 따라야 합니다.

  • 에 FlutterFire 종속성 추가 pubspec.yaml
  • Firebase 프로젝트에 원하는 플랫폼 등록
  • 플랫폼별 구성 파일을 다운로드하고 코드에 추가합니다.

당신의 떨림 응용 프로그램의 최상위 디렉토리에서라는 하위 디렉토리가 iosandroid . 이 디렉토리에는 iOS 및 Android 각각에 대한 플랫폼별 구성 파일이 있습니다.

종속성 구성

이 앱에서 사용 중인 두 가지 Firebase 제품(Firebase Auth 및 Cloud Firestore)에 FlutterFire 라이브러리를 추가해야 합니다. 편집 pubspec.yaml 다음과 같은 종속성을 추가 :

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  cloud_firestore: ^1.0.0 # new
  firebase_auth: ^1.0.0   # new
  google_fonts: ^2.0.0
  provider: ^5.0.0        # new

필수 패키지를 추가하는 동안 Firebase를 적절하게 활용하도록 iOS, Android, macOS 및 웹 러너 프로젝트도 구성해야 합니다. 또한 사용하는 provider 디스플레이 로직과 비즈니스 로직의 분리를 가능하게 할 것이다 패키지를.

iOS 구성

  1. 에서 중포 기지 콘솔 왼쪽 탐색 모음에서 프로젝트 개요를 선택하고 앱에 중포 기지를 추가하여 시작에서 아이폰 OS 버튼을 클릭합니다.

다음 대화 상자가 표시되어야 합니다.

c42139f18fb9a2ee.png

  1. 제공하는 중요한 값은 아이폰 OS 번들 ID입니다. 다음 세 단계를 수행하여 번들 ID를 얻습니다.
  1. 명령줄 도구에서 Flutter 앱의 최상위 디렉터리로 이동합니다.
  2. 명령 실행 open ios/Runner.xcworkspace 엑스 코드를 엽니 다.
  1. 엑스 코드에서 다음과 같이 오른쪽 창에서 일반 탭을 보여주고, 대상에서 주자를 선택, 왼쪽 창에서 최상위 러너을 클릭합니다. 번들 식별자 값을 복사합니다.

9d67acd88c718763.png

  1. 의 중포 기지 대화 상자로 이동 아이폰 OS 번들 ID 필드에 복사 된 번들 식별자를 붙여 등록 앱을 클릭합니다.
  1. 중포 기지에서 계속 구성 파일 다운로드의 지시에 따라 GoogleService-Info.plist .
  2. Xcode로 돌아갑니다. 공지 러너 (위의 이미지에 도시)는 또한 러너라는 하위 폴더를 가지고있다.
  3. 드래그 GoogleService-Info.plist러너 하위 폴더에 (방금 다운로드 한) 파일을.
  4. 엑스 코드에 표시되는 대화 상자에서 마침을 클릭합니다.
  5. 앞으로는 필요하지 않으므로 이 시점에서 자유롭게 Xcode를 종료하십시오.
  6. Firebase 콘솔로 돌아갑니다. 설치 단계에서 다음을 클릭합니다 나머지 단계를 건너 뛰고 중포 기지 콘솔의 기본 페이지로 돌아갑니다.

iOS용 Flutter 앱 구성을 완료했습니다. 자세한 내용은 다음을 참조하십시오 FlutterFire 아이폰 OS 설치 설명서를 .

안드로이드 구성

  1. 에서 중포 기지 콘솔 왼쪽 탐색 모음에서 프로젝트 개요를 선택하고 앱에 중포 기지를 추가하여 시작에서 안드로이드 버튼을 클릭합니다.

다음 대화 상자가 표시됩니다. 8254fc299e82f528.png

  1. 제공하는 중요한 값은 안드로이드 패키지 이름입니다. 다음 두 단계를 수행하면 패키지 이름을 얻습니다.
  1. 당신의 떨림 응용 프로그램 디렉토리에서 파일 열기 android/app/src/main/AndroidManifest.xml .
  2. 에서 manifest 요소의 문자열 값 찾을 package 속성을. 이 값은 안드로이드 패키지 이름 (같은 것입니다 com.yourcompany.yourproject ). 이 값을 복사합니다.
  3. 중포 기지 대화 상자에서, 안드로이드 패키지 이름 필드에 복사 된 패키지 이름을 붙여 넣습니다.
  4. 이 코드 랩에 대한 디버그 서명 인증서의 SHA-1을 필요로하지 않습니다. 공백으로 둡니다.
  5. 등록 앱을 클릭합니다.
  6. 중포 기지에 계속, 구성 파일 다운로드 지침에 따라 google-services.json .
  7. 당신의 떨림 응용 프로그램 디렉토리로 이동하고, 이동 google-services.json 에 (방금 다운로드 한) 파일을 android/app 디렉토리.
  8. Firebase 콘솔로 돌아가서 나머지 단계를 건너뛰고 Firebase 콘솔의 기본 페이지로 돌아갑니다.
  9. 편집 당신의 android/build.gradle 추가하는 google-services 의존 플러그인 :

안드로이드/빌드.gradle

dependencies {
        classpath 'com.android.tools.build:gradle:4.1.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.3.5'  // new
}
  1. 편집 당신의 android/app/build.gradle 에이블하기 google-services 플러그인을 :

안드로이드/앱/빌드.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply plugin: 'com.google.gms.google-services'  // new
  1. Firebase를 사용하려면 Multidex를 활성화해야 하며, 이를 수행하는 한 가지 방법은 지원되는 최소 SDK를 21 이상으로 설정하는 것입니다. 편집 당신의 android/app/build.gradle 업데이트하려면 minSdkVersion :

안드로이드/앱/빌드.gradle

defaultConfig {
    applicationId "com.example.gtk_flutter"
    minSdkVersion 21  // Updated
    targetSdkVersion 30
    versionCode flutterVersionCode.toInteger()
    versionName flutterVersionName
}

Android용 Flutter 앱 구성을 완료했습니다. 자세한 내용은 다음을 참조하십시오 FlutterFire 안드로이드 설치 설명서를 .

웹용으로 구성

  1. 에서 중포 기지 콘솔 왼쪽 탐색 모음에서 프로젝트 개요를 선택하고 앱에 중포 기지를 추가하여 시작하기 아래에있는 버튼을 클릭합니다.

25b14deff9e589ce.png

  1. 이 응용 프로그램에게 별명을주고, 등록 응용 프로그램 버튼을 클릭합니다. 로컬에서만 실행할 것이기 때문에 이 튜토리얼에서는 Firebase 호스팅을 끈 상태로 두겠습니다. 여기에서 Firebase 호스팅에 대해 자세히 알아보세요. 9c697cc1b309c806.png
  2. 편집 귀하의 본문에 web/index.html 파일은 다음과 같습니다. 추가해야합니다 firebaseConfig 이전 단계에서 데이터를.

웹/인덱스.html

<body>
  <script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('flutter-first-frame', function () {
        navigator.serviceWorker.register('flutter_service_worker.js');
      });
    }
  </script>

  <!-- Add from here -->
  <script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-app.js"></script>
  <script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-auth.js"></script>
  <script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-firestore.js"></script>
  <script>
    // Your web app's Firebase configuration
    var firebaseConfig = {
      // Replace this with your firebaseConfig
    };
    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);
  </script>
  <!-- to here. -->

  <script src="main.dart.js" type="application/javascript"></script>
</body>

웹용 Flutter 앱 구성을 완료했습니다. 자세한 내용은 다음을 참조하십시오 FlutterFire 웹 설치 설명서를 .

macOS 구성

macOS의 구성 단계는 iOS와 거의 동일합니다. 우리는 재사용 구성 파일에가는 GoogleService-Info.plist 아이폰 OS가 위의 단계에서.

  1. 명령 실행 open macos/Runner.xcworkspace 엑스 코드를 엽니 다.
  1. 드래그 GoogleService-Info.plist 러너 하위 폴더에 파일을. 이것은 위의 구성 아이폰 OS 단계에서 작성되었습니다. c2b9229a605fd738.png
  2. 에서 macos/Runner/DebugProfile.entitlements 파일, 추가 com.apple.security.network.client 자격을, 그리고 그것을 설정 true . 8bee5665e35d3f34.png
  3. 에서 macos/Runner/Release.entitlements 파일도 추가 com.apple.security.network.client 자격을, 그리고 그것을 설정 true . 41e2e23b7928546a.png
  4. 앞으로는 필요하지 않으므로 이 시점에서 자유롭게 Xcode를 종료하십시오.

macOS용 Flutter 앱 구성을 완료했습니다. 자세한 내용은 다음을 참조하십시오 FlutterFire 맥 OS 설치 설명서플러터에 대한 데스크톱 지원 페이지를.

이제 앱에 중포 기지를 추가 한 것을, 당신은 사용 레지스터 사람들이 있다는 RSVP 버튼을 설정할 수 있습니다 중포 기지 인증을 . Android 네이티브, iOS 네이티브 및 웹의 경우 사전 빌드된 FirebaseUI 인증 패키지가 있지만 Flutter의 경우 이 기능을 빌드해야 합니다.

2단계에서 검색한 프로젝트에는 대부분의 인증 흐름에 대한 사용자 인터페이스를 구현하는 위젯 세트가 포함되어 있습니다. Firebase 인증을 애플리케이션에 통합하는 비즈니스 로직을 구현합니다.

공급자와 비즈니스 로직

당신은 사용하고자하는 provider 떨림 위젯 응용 프로그램의 나무에 걸쳐 중앙 집중화 된 애플리케이션 상태 개체를 사용할 수 있도록 패키지를. 상단의 수입을 수정, 시작하려면 lib/main.dart :

라이브러리/메인.다트

import 'package:firebase_core/firebase_core.dart'; // new
import 'package:firebase_auth/firebase_auth.dart'; // new
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';           // new

import 'src/authentication.dart';                  // new
import 'src/widgets.dart';

import 라인은 중포 기지 코어 및 인증의에서 풀 소개 provider 위젯 트리를 통해 응용 프로그램 상태 개체를 사용할 수 있도록하기 위해 사용하는 패키지를, 그리고에서 인증 위젯 포함 lib/src .

이 응용 프로그램의 상태 개체, ApplicationState 이 단계에 대한 두 가지 주요 책임을 가지고 있지만, 나중에 단계에서 응용 프로그램에 더 많은 기능을 추가로 추가 책임을 얻을 것입니다. 첫 번째 책임에 대한 호출로 중포 기지 라이브러리를 초기화하는 것입니다 Firebase.initializeApp() , 다음 인증 흐름의 처리가있다. 의 끝에 다음 클래스를 추가 lib/main.dart :

라이브러리/메인.다트

class ApplicationState extends ChangeNotifier {
  ApplicationState() {
    init();
  }

  Future<void> init() async {
    await Firebase.initializeApp();

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
      } else {
        _loginState = ApplicationLoginState.loggedOut;
      }
      notifyListeners();
    });
  }

  ApplicationLoginState _loginState = ApplicationLoginState.loggedOut;
  ApplicationLoginState get loginState => _loginState;

  String? _email;
  String? get email => _email;

  void startLoginFlow() {
    _loginState = ApplicationLoginState.emailAddress;
    notifyListeners();
  }

  void verifyEmail(
    String email,
    void Function(FirebaseAuthException e) errorCallback,
  ) async {
    try {
      var methods =
          await FirebaseAuth.instance.fetchSignInMethodsForEmail(email);
      if (methods.contains('password')) {
        _loginState = ApplicationLoginState.password;
      } else {
        _loginState = ApplicationLoginState.register;
      }
      _email = email;
      notifyListeners();
    } on FirebaseAuthException catch (e) {
      errorCallback(e);
    }
  }

  void signInWithEmailAndPassword(
    String email,
    String password,
    void Function(FirebaseAuthException e) errorCallback,
  ) async {
    try {
      await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: email,
        password: password,
      );
    } on FirebaseAuthException catch (e) {
      errorCallback(e);
    }
  }

  void cancelRegistration() {
    _loginState = ApplicationLoginState.emailAddress;
    notifyListeners();
  }

  void registerAccount(String email, String displayName, String password,
      void Function(FirebaseAuthException e) errorCallback) async {
    try {
      var credential = await FirebaseAuth.instance
          .createUserWithEmailAndPassword(email: email, password: password);
      await credential.user!.updateProfile(displayName: displayName);
    } on FirebaseAuthException catch (e) {
      errorCallback(e);
    }
  }

  void signOut() {
    FirebaseAuth.instance.signOut();
  }
}

이 수업에서 몇 가지 핵심 사항을 언급할 가치가 있습니다. 사용자가 인증되지 않은 상태에서 시작하고 앱은 사용자의 이메일 주소를 요청하는 양식을 표시합니다. 해당 이메일 주소가 파일에 있는지 여부에 따라 앱은 사용자 등록을 요청하거나 비밀번호를 요청한 다음 모든 것이 잘 작동한다고 가정하면 사용자 인증됩니다.

로그인에 문제가 있는 기존 계정이 있는 사용자의 경우를 처리하지 않기 때문에 이것이 FirebaseUI 인증 흐름의 완전한 구현이 아니라는 점에 유의해야 합니다. 이 추가 기능을 구현하는 것은 동기부여 독자.

인증 흐름 통합

이제 응용 프로그램 상태의 시작을 가지고는 응용 프로그램 초기화에 응용 프로그램 상태를 와이어로 인증 흐름을 추가하는 시간 HomePage . 비아 응용 프로그램 상태를 통합하는 주 진입 점을 업데이트 provider 패키지 :

라이브러리/메인.다트

void main() {
  // Modify from here
  runApp(
    ChangeNotifierProvider(
      create: (context) => ApplicationState(),
      builder: (context, _) => App(),
    ),
  );
  // to here.
}

받는 사람 수정 main 기능은 사용하여 응용 프로그램 상태 개체를 인스턴스화에 대한 책임 바이더 패키지하게 ChangeNotifierProvider 위젯을. 응용 프로그램 상태 개체가 확장 때문에이 특정 공급자 클래스를 사용하는 ChangeNotifier 하고 이것이 가능 provider 종속 된 위젯을 다시 표시하는 방법을 알고 패키지를. 마지막으로 응용 프로그램 상태 통합 Authentication 업데이트하여 HomePagebuild 방법 :

라이브러리/메인.다트

class HomePage extends StatelessWidget {
  HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Firebase Meetup'),
      ),
      body: ListView(
        children: <Widget>[
          Image.asset('assets/codelab.png'),
          SizedBox(height: 8),
          IconAndDetail(Icons.calendar_today, 'October 30'),
          IconAndDetail(Icons.location_city, 'San Francisco'),
          // Add from here
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Authentication(
              email: appState.email,
              loginState: appState.loginState,
              startLoginFlow: appState.startLoginFlow,
              verifyEmail: appState.verifyEmail,
              signInWithEmailAndPassword: appState.signInWithEmailAndPassword,
              cancelRegistration: appState.cancelRegistration,
              registerAccount: appState.registerAccount,
              signOut: appState.signOut,
            ),
          ),
          // to here
          Divider(
            height: 8,
            thickness: 1,
            indent: 8,
            endIndent: 8,
            color: Colors.grey,
          ),
          Header("What we'll be doing"),
          Paragraph(
            'Join us for a day full of Firebase Workshops and Pizza!',
          ),
        ],
      ),
    );
  }
}

당신은 인스턴스화 Authentication 위젯을, 그리고 그것을 포장 Consumer 위젯. 소비자는 것이 일반적인 방법 위젯 provider 패키지가 트리 응용 프로그램 상태 변경의 일부를 재 구축 할 수 있습니다. Authentication 인증 UI 당신이 지금 것 테스트입니다 위젯.

인증 흐름 테스트

cdf2d25e436bd48d.png

다음은 사용자가 RSVP 버튼을 탭하여 이메일 양식을 시작할 수 있는 인증 흐름의 시작입니다.

2a2cd6d69d172369.png

이메일을 입력하면 시스템은 사용자가 이미 등록되어 있는지 확인합니다. 이 경우 사용자에게 비밀번호를 묻는 메시지가 표시되고, 사용자가 등록되지 않은 경우 등록 양식을 진행합니다.

e5e65065dba36b54.png

오류 처리 흐름을 확인하려면 짧은 암호(6자 미만)를 입력해 보십시오. 사용자가 등록된 경우 대신 암호가 표시됩니다.

fbb3ea35fb4f67a.png

이 페이지에서 잘못된 암호를 입력하여 이 페이지의 오류 처리를 확인하십시오. 마지막으로, 사용자가 로그인하면 사용자에게 다시 로그아웃할 수 있는 기능을 제공하는 로그인 경험이 표시됩니다.

4ed811a25b0cf816.png

이를 통해 인증 흐름을 구현했습니다. 축하 해요!

사용자가 온다는 것을 아는 것도 좋지만, 게스트에게 앱에서 할 수 있는 다른 일을 주자. 방명록에 메시지를 남길 수 있다면 어떨까요? 그들은 왜 그들이 오고 싶어하는지 또는 누구를 만나고 싶은지 공유할 수 있습니다.

사용자가 응용 프로그램에서 쓰는 채팅 메시지를 저장하려면 사용합니다 클라우드 경우 FireStore을 .

데이터 모델

Cloud Firestore는 NoSQL 데이터베이스이며 데이터베이스에 저장된 데이터는 컬렉션, 문서, 필드, 하위 컬렉션으로 나뉩니다. 당신은라는 최상위 컬렉션에서 문서로 채팅의 각 메시지를 저장합니다 guestbook .

7c20dc8424bb1d84.png

Firestore에 메시지 추가

이 섹션에서는 사용자가 데이터베이스에 새 메시지를 작성하는 기능을 추가합니다. 먼저 UI 요소(양식 필드 및 보내기 버튼)를 추가한 다음 이러한 요소를 데이터베이스에 연결하는 코드를 추가합니다.

첫째, 대한 수입을 추가 cloud_firestore 패키지와 dart:async .

라이브러리/메인.다트

import 'dart:async';                                    // new
import 'package:cloud_firestore/cloud_firestore.dart';  // new
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';

import 'src/authentication.dart';
import 'src/widgets.dart';

메시지 필드와 전송 버튼의 UI 요소를 구성하려면 위젯 새로운 상태 추가 GuestBook 맨 아래에 lib/main.dart .

라이브러리/메인.다트

class GuestBook extends StatefulWidget {
  GuestBook({required this.addMessage});
  final FutureOr<void> Function(String message) addMessage;

  @override
  _GuestBookState createState() => _GuestBookState();
}

class _GuestBookState extends State<GuestBook> {
  final _formKey = GlobalKey<FormState>(debugLabel: '_GuestBookState');
  final _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Form(
        key: _formKey,
        child: Row(
          children: [
            Expanded(
              child: TextFormField(
                controller: _controller,
                decoration: const InputDecoration(
                  hintText: 'Leave a message',
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Enter your message to continue';
                  }
                  return null;
                },
              ),
            ),
            SizedBox(width: 8),
            StyledButton(
              onPressed: () async {
                if (_formKey.currentState!.validate()) {
                  await widget.addMessage(_controller.text);
                  _controller.clear();
                }
              },
              child: Row(
                children: [
                  Icon(Icons.send),
                  SizedBox(width: 4),
                  Text('SEND'),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

여기에 몇 가지 관심 지점이 있습니다. 먼저, upi가 메시지에 실제로 일부 콘텐츠가 있는지 확인하고 콘텐츠가 없는 경우 사용자에게 오류 메시지를 표시할 수 있도록 Form을 인스턴스화합니다. 양식을 확인하는 방법은 양식 뒤에 양식 상태를 액세스 포함, 이것은 당신이 사용 GlobalKey . 키에 대한 자세한 내용은하고 사용하는 방법을 참조하십시오 "사용 키를"플러터 위젯 (101) 에피소드 .

또한 위젯이 배치되는 방식을 참고, 당신은이 Row 으로, TextFormFieldStyledButton 자체가 포함하고, Row . 또한주의 TextFormField 에 싸여 Expanded 위젯이 강제로 TextFormField 행에 여분의 공간을 차지합니다. 더 나은이가 필요한 이유를 읽어 보시기 바랍니다 이해하기 이해 제약 .

이제 사용자가 방명록에 추가할 일부 텍스트를 입력할 수 있는 위젯이 있으므로 화면에 가져와야 합니다. 이렇게하려면, 편집의 몸 HomePage 의 하단에 다음 두 줄을 추가 할 수 ListView 의 어린이 :

Header("What we'll be doing"),
Paragraph(
  'Join us for a day full of Firebase Workshops and Pizza!',
),
// Add the following two lines.
Header('Discussion'),
GuestBook(addMessage: (String message) => print(message)),

이것은 위젯을 표시하는 데 충분하지만 유용한 작업을 수행하는 데는 충분하지 않습니다. 이 코드가 작동하도록 곧 업데이트할 것입니다.

앱 미리보기

보내기 버튼을 클릭하면 사용자는 아래의 코드를 트리거합니다. 그것은에 메시지 입력 필드의 내용을 추가 guestbook 데이터베이스의 모음입니다. 즉, addMessageToGuestBook 방법은 행 (자동으로 생성 된 ID)와 새 문서 메시지 내용에 추가 guestbook 컬렉션.

참고 FirebaseAuth.instance.currentUser.uid 모든 로그인에 대한 사용자 중포 기지 인증을 제공하는 자동 생성 된 고유 ID에 대한 참조입니다.

받는 또 다른 변화를 확인 lib/main.dart 파일을. 추가 addMessageToGuestBook 방법을. 다음 단계에서 사용자 인터페이스와 이 기능을 함께 연결합니다.

라이브러리/메인.다트

class ApplicationState extends ChangeNotifier {

  // Current content of ApplicationState elided ...

  // Add from here
  Future<DocumentReference> addMessageToGuestBook(String message) {
    if (_loginState != ApplicationLoginState.loggedIn) {
      throw Exception('Must be logged in');
    }

    return FirebaseFirestore.instance.collection('guestbook').add(<String, dynamic>{
      'text': message,
      'timestamp': DateTime.now().millisecondsSinceEpoch,
      'name': FirebaseAuth.instance.currentUser!.displayName,
      'userId': FirebaseAuth.instance.currentUser!.uid,
    });
  }
  // To here
}

UI를 데이터베이스에 연결하기

사용자가 방명록에 추가하려는 텍스트를 입력할 수 있는 UI가 있고 Cloud Firestore에 항목을 추가하는 코드가 있습니다. 이제 두 개를 연결하기만 하면 됩니다. 에서 lib/main.dart 받는 다음과 같이 변경하기 HomePage 위젯을.

라이브러리/메인.다트

class HomePage extends StatelessWidget {
  HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Firebase Meetup'),
      ),
      body: ListView(
        children: <Widget>[
          Image.asset('assets/codelab.png'),
          SizedBox(height: 8),
          IconAndDetail(Icons.calendar_today, 'October 30'),
          IconAndDetail(Icons.location_city, 'San Francisco'),
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Authentication(
              email: appState.email,
              loginState: appState.loginState,
              startLoginFlow: appState.startLoginFlow,
              verifyEmail: appState.verifyEmail,
              signInWithEmailAndPassword: appState.signInWithEmailAndPassword,
              cancelRegistration: appState.cancelRegistration,
              registerAccount: appState.registerAccount,
              signOut: appState.signOut,
            ),
          ),
          Divider(
            height: 8,
            thickness: 1,
            indent: 8,
            endIndent: 8,
            color: Colors.grey,
          ),
          Header("What we'll be doing"),
          Paragraph(
            'Join us for a day full of Firebase Workshops and Pizza!',
          ),
          // Modify from here
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                if (appState.loginState == ApplicationLoginState.loggedIn) ...[
                  Header('Discussion'),
                  GuestBook(
                    addMessage: (String message) =>
                        appState.addMessageToGuestBook(message),
                  ),
                ],
              ],
            ),
          ),
          // To here.
        ],
      ),
    );
  }
}

이 단계를 시작할 때 다시 추가한 두 줄을 전체 구현으로 교체했습니다. 다시 사용하는 Consumer<ApplicationState> 당신이 표현하고있는 나무의 부분에 응용 프로그램 상태를 사용할 수 있도록. 이를 통해 UI에 메시지를 입력하는 누군가에 반응하고 이를 데이터베이스에 게시할 수 있습니다. 다음 섹션에서는 추가된 메시지가 데이터베이스에 게시되는지 테스트합니다.

메시지 전송 테스트

  1. 앱에 로그인했는지 확인합니다.
  2. 예 : "안녕!"이라고 메시지를 입력 한 후 보내기를 클릭합니다.

이 작업은 메시지를 Cloud Firestore 데이터베이스에 씁니다. 그러나 아직 데이터 검색을 구현해야 하기 때문에 실제 Flutter 앱에서 메시지를 볼 수 없습니다. 다음 단계에서 수행합니다.

하지만 Firebase 콘솔에서 새로 추가된 메시지를 볼 수 있습니다.

중포 기지 콘솔에서의 데이터베이스 대시 보드 , 당신은 볼 수 guestbook 새로 추가 한 메시지 모음. 메시지를 계속 보내면 방명록 모음에 다음과 같은 많은 문서가 포함됩니다.

Firebase 콘솔

713870af0b3b63c.png

게스트가 데이터베이스에 메시지를 쓸 수 있다는 것은 멋진 일이지만 아직 앱에서는 볼 수 없습니다. 수정하자!

메시지 동기화

메시지를 표시하려면 데이터가 변경될 때 트리거되는 리스너를 추가한 다음 새 메시지를 표시하는 UI 요소를 만들어야 합니다. 앱에서 새로 추가된 메시지를 수신 대기하는 코드를 애플리케이션 상태에 추가합니다.

그냥 위의 GuestBook 다음과 같은 값 클래스 위젯. 이 클래스는 Cloud Firestore에 저장 중인 데이터의 구조화된 보기를 제공합니다.

라이브러리/메인.다트

class GuestBookMessage {
  GuestBookMessage({required this.name, required this.message});
  final String name;
  final String message;
}

의 섹션에서 ApplicationState 당신이 국가와 게터를 정의, 다음과 같은 새로운 줄을 추가 :

라이브러리/메인.다트

  ApplicationLoginState _loginState = ApplicationLoginState.loggedOut;
  ApplicationLoginState get loginState => _loginState;

  String? _email;
  String? get email => _email;

  // Add from here
  StreamSubscription<QuerySnapshot>? _guestBookSubscription;
  List<GuestBookMessage> _guestBookMessages = [];
  List<GuestBookMessage> get guestBookMessages => _guestBookMessages;
  // to here.

그리고 마지막으로, 초기화 섹션에서 ApplicationState 의 사용자의 로그 및 탈퇴들이 로그 아웃 할 때 때 문서 컬렉션을 통해 쿼리에 가입하려면 다음을 추가합니다.

라이브러리/메인.다트

  Future<void> init() async {
    await Firebase.initializeApp();

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
        // Add from here
        _guestBookSubscription = FirebaseFirestore.instance
            .collection('guestbook')
            .orderBy('timestamp', descending: true)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          snapshot.docs.forEach((document) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'],
                message: document.data()['text'],
              ),
            );
          });
          notifyListeners();
        });
        // to here.
      } else {
        _loginState = ApplicationLoginState.loggedOut;
        // Add from here
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
        // to here.
      }
      notifyListeners();
    });
  }

이 섹션은 여기에 중요하다 당신이 이상의 쿼리 구성 곳이다 guestbook 수집을하고, 핸들이 가입하고이 컬렉션에 탈퇴. 당신은 당신이있는 메시지의 로컬 캐시 재구성 스트림, 듣고 guestbook 수집을하고, 나중에 가입을 취소 할 수 있습니다 또한이 구독에 대한 참조를 저장합니다. 여기에서 많은 일이 진행 중이며 더 명확한 멘탈 모델을 얻을 때 어떤 일이 발생하는지 검사하는 디버거에서 시간을 할애할 가치가 있습니다.

자세한 내용은 참조 클라우드 경우 FireStore 문서를 .

에서 GuestBook 사용자 인터페이스에이 변화하는 상태를 연결해야 위젯. 구성의 일부로 메시지 목록을 추가하여 위젯을 수정합니다.

라이브러리/메인.다트

class GuestBook extends StatefulWidget {
  // Modify the following line
  GuestBook({required this.addMessage, required this.messages});
  final FutureOr<void> Function(String message) addMessage;
  final List<GuestBookMessage> messages; // new

  @override
  _GuestBookState createState() => _GuestBookState();
}

다음으로, 우리는이 새로운 구성 노출 _GuestBookState 수정하여 build 다음과 같은 방법을.

라이브러리/메인.다트

class _GuestBookState extends State<GuestBook> {
  final _formKey = GlobalKey<FormState>(debugLabel: '_GuestBookState');
  final _controller = TextEditingController();

  @override
  // Modify from here
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // to here.
        Padding(
          padding: const EdgeInsets.all(8.0),
          child: Form(
            key: _formKey,
            child: Row(
              children: [
                Expanded(
                  child: TextFormField(
                    controller: _controller,
                    decoration: const InputDecoration(
                      hintText: 'Leave a message',
                    ),
                    validator: (value) {
                      if (value == null || value.isEmpty) {
                        return 'Enter your message to continue';
                      }
                      return null;
                    },
                  ),
                ),
                SizedBox(width: 8),
                StyledButton(
                  onPressed: () async {
                    if (_formKey.currentState!.validate()) {
                      await widget.addMessage(_controller.text);
                      _controller.clear();
                    }
                  },
                  child: Row(
                    children: [
                      Icon(Icons.send),
                      SizedBox(width: 4),
                      Text('SEND'),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
        // Modify from here
        SizedBox(height: 8),
        for (var message in widget.messages)
          Paragraph('${message.name}: ${message.message}'),
        SizedBox(height: 8),
        // to here.
      ],
    );
  }
}

당신은과 빌드 방법의 이전 내용 포장 Column 의 말미에 다음 위젯을하고, Column 당신은 추가의 아이들 에 대한 수집을 새로 생성하는 Paragraph 메시지 목록에서 각 메시지를.

마지막으로, 당신은 지금의 몸 업데이트 할 필요가 HomePage 올바르게 구성하기 위해 GuestBook 새로운으로 messages 매개 변수입니다.

라이브러리/메인.다트

Consumer<ApplicationState>(
  builder: (context, appState, _) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      if (appState.loginState == ApplicationLoginState.loggedIn) ...[
        Header('Discussion'),
        GuestBook(
          addMessage: (String message) =>
              appState.addMessageToGuestBook(message),
          messages: appState.guestBookMessages, // new
        ),
      ],
    ],
  ),
),

메시지 동기화 테스트

Cloud Firestore는 데이터베이스에 가입한 클라이언트와 데이터를 자동으로 즉시 동기화합니다.

  1. 데이터베이스에서 이전에 생성한 메시지가 앱에 표시되어야 합니다. 새 메시지를 자유롭게 작성하십시오. 그들은 즉시 나타나야 합니다.
  2. 여러 창이나 탭에서 작업 공간을 열면 메시지가 탭 간에 실시간으로 동기화됩니다.
  3. (선택 사항), 삭제, 수정, 또는 중포 기지 콘솔의 데이터베이스 섹션에서 직접 새 메시지를 추가 수동으로 시도 할 수 있습니다; 모든 변경 사항이 UI에 표시되어야 합니다.

축하합니다! 앱에서 Cloud Firestore 문서를 읽고 있습니다!

앱 p를 검토

처음에 테스트 모드를 사용하도록 Cloud Firestore를 설정했습니다. 즉, 데이터베이스가 읽기 및 쓰기를 위해 열려 있습니다. 그러나 개발 초기 단계에서만 테스트 모드를 사용해야 합니다. 모범 사례로 앱을 개발할 때 데이터베이스에 대한 보안 규칙을 설정해야 합니다. 보안은 앱의 구조와 동작에 필수적이어야 합니다.

보안 규칙을 사용하면 데이터베이스의 문서 및 컬렉션에 대한 액세스를 제어할 수 있습니다. 유연한 규칙 구문을 사용하면 전체 데이터베이스에 대한 모든 쓰기에서 특정 문서에 대한 작업에 이르기까지 모든 항목과 일치하는 규칙을 만들 수 있습니다.

Firebase 콘솔에서 Cloud Firestore에 대한 보안 규칙을 작성할 수 있습니다.

  1. 중포 기지 콘솔의 개발 섹션에서 데이터베이스를 클릭 한 다음 규칙 탭을 선택 (또는 여기를 클릭하여 규칙 탭으로 바로 이동합니다).
  2. 공개된 규칙에 대한 경고와 함께 다음 기본 보안 규칙이 표시되어야 합니다.

7767a2d2e64e7275.png

컬렉션 식별

먼저 앱이 데이터를 쓰는 컬렉션을 식별합니다.

에서 match /databases/{database}/documents , 당신이 보호하려는 컬렉션을 확인 :

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
     // You'll add rules here in the next step.
  }
}

보안 규칙 추가

인증 UID를 각 방명록 문서의 필드로 사용했기 때문에 인증 UID를 얻고 문서에 쓰려는 사람이 인증 UID와 일치하는지 확인할 수 있습니다.

아래와 같이 규칙 세트에 읽기 및 쓰기 규칙을 추가합니다.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
      allow read: if request.auth.uid != null;
      allow write:
        if request.auth.uid == request.resource.data.userId;
    }
  }
}

이제 방명록의 경우 로그인한 사용자만 메시지(모든 메시지!)를 읽을 수 있지만 메시지 작성자만 메시지를 편집할 수 있습니다.

유효성 검사 규칙 추가

모든 예상 필드가 문서에 있는지 확인하기 위해 데이터 유효성 검사를 추가합니다.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
      allow read: if request.auth.uid != null;
      allow write:
      if request.auth.uid == request.resource.data.userId
          && "name" in request.resource.data
          && "text" in request.resource.data
          && "timestamp" in request.resource.data;
    }
  }
}

참석자의 RSVP 상태 기록

현재 앱은 이벤트에 관심이 있는 사람들이 채팅을 시작할 수 있도록 허용합니다. 또한 누군가가 오는지 알 수 있는 유일한 방법은 채팅에 게시하는 것입니다. 얼마나 많은 사람들이 오고 있는지 조직하고 사람들에게 알리도록 합시다.

애플리케이션 상태에 몇 가지 새로운 기능을 추가할 것입니다. 첫 번째는 로그인한 사용자가 참석 여부를 지정할 수 있는 기능입니다. 두 번째 기능은 실제로 몇 명이 참석하는지에 대한 카운터입니다.

에서 lib/main.dart ,이 상태와 상호 작용하는 UI 코드를 가능하게하여 접근 섹션에 다음을 추가합니다

라이브러리/메인.다트

int _attendees = 0;
int get attendees => _attendees;

Attending _attending = Attending.unknown;
StreamSubscription<DocumentSnapshot>? _attendingSubscription;
Attending get attending => _attending;
set attending(Attending attending) {
  final userDoc = FirebaseFirestore.instance
      .collection('attendees')
      .doc(FirebaseAuth.instance.currentUser!.uid);
  if (attending == Attending.yes) {
    userDoc.set({'attending': true});
  } else {
    userDoc.set({'attending': false});
  }
}

업데이트 ApplicationStateinit 방법은 다음과 같습니다 :

라이브러리/메인.다트

  Future<void> init() async {
    await Firebase.initializeApp();

    // Add from here
    FirebaseFirestore.instance
        .collection('attendees')
        .where('attending', isEqualTo: true)
        .snapshots()
        .listen((snapshot) {
      _attendees = snapshot.docs.length;
      notifyListeners();
    });
    // To here

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
        _guestBookSubscription = FirebaseFirestore.instance
            .collection('guestbook')
            .orderBy('timestamp', descending: true)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          snapshot.docs.forEach((document) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'],
                message: document.data()['text'],
              ),
            );
          });
          notifyListeners();
        });
        // Add from here
        _attendingSubscription = FirebaseFirestore.instance
            .collection('attendees')
            .doc(user.uid)
            .snapshots()
            .listen((snapshot) {
          if (snapshot.data() != null) {
            if (snapshot.data()!['attending']) {
              _attending = Attending.yes;
            } else {
              _attending = Attending.no;
            }
          } else {
            _attending = Attending.unknown;
          }
          notifyListeners();
        });
        // to here
      } else {
        _loginState = ApplicationLoginState.loggedOut;
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
        _attendingSubscription?.cancel(); // new
      }
      notifyListeners();
    });
  }

위의 내용은 참석자 수를 확인하기 위해 항상 구독 중인 쿼리와 사용자가 참석 중인지 확인하기 위해 사용자가 로그인한 동안에만 활성화되는 두 번째 쿼리를 추가합니다. 다음으로, 다음에 다음 열거를 추가 GuestBookMessage 선언 :

라이브러리/메인.다트

enum Attending { yes, no, unknown }

이제 이전의 라디오 버튼처럼 작동하는 새 위젯을 정의할 것입니다. 예 또는 아니오가 선택되지 않은 불확실한 상태에서 시작하지만 사용자가 참석 여부를 선택하면 채워진 버튼으로 강조 표시된 해당 옵션을 표시하고 평면 렌더링으로 후퇴하는 다른 옵션을 표시합니다.

라이브러리/메인.다트

class YesNoSelection extends StatelessWidget {
  const YesNoSelection({required this.state, required this.onSelection});
  final Attending state;
  final void Function(Attending selection) onSelection;

  @override
  Widget build(BuildContext context) {
    switch (state) {
      case Attending.yes:
        return Padding(
          padding: EdgeInsets.all(8.0),
          child: Row(
            children: [
              ElevatedButton(
                style: ElevatedButton.styleFrom(elevation: 0),
                onPressed: () => onSelection(Attending.yes),
                child: Text('YES'),
              ),
              SizedBox(width: 8),
              TextButton(
                onPressed: () => onSelection(Attending.no),
                child: Text('NO'),
              ),
            ],
          ),
        );
      case Attending.no:
        return Padding(
          padding: EdgeInsets.all(8.0),
          child: Row(
            children: [
              TextButton(
                onPressed: () => onSelection(Attending.yes),
                child: Text('YES'),
              ),
              SizedBox(width: 8),
              ElevatedButton(
                style: ElevatedButton.styleFrom(elevation: 0),
                onPressed: () => onSelection(Attending.no),
                child: Text('NO'),
              ),
            ],
          ),
        );
      default:
        return Padding(
          padding: EdgeInsets.all(8.0),
          child: Row(
            children: [
              StyledButton(
                onPressed: () => onSelection(Attending.yes),
                child: Text('YES'),
              ),
              SizedBox(width: 8),
              StyledButton(
                onPressed: () => onSelection(Attending.no),
                child: Text('NO'),
              ),
            ],
          ),
        );
    }
  }
}

다음으로, 당신은 업데이트 할 필요가 HomePage 의 활용의 빌드 방법을 YesNoSelection 들이 참석하는 경우가 지명에 대한 사용자 로그인이 가능. 또한 이 이벤트의 참석자 수를 표시합니다.

라이브러리/메인.다트

Consumer<ApplicationState>(
  builder: (context, appState, _) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      // Add from here
      if (appState.attendees >= 2)
        Paragraph('${appState.attendees} people going')
      else if (appState.attendees == 1)
        Paragraph('1 person going')
      else
        Paragraph('No one going'),
      // To here.
      if (appState.loginState == ApplicationLoginState.loggedIn) ...[
        // Add from here
        YesNoSelection(
          state: appState.attending,
          onSelection: (attending) => appState.attending = attending,
        ),
        // To here.
        Header('Discussion'),
        GuestBook(
          addMessage: (String message) =>
              appState.addMessageToGuestBook(message),
          messages: appState.guestBookMessages,
        ),
      ],
    ],
  ),
),

규칙 추가

이미 몇 가지 규칙이 설정되어 있으므로 버튼을 사용하여 추가하는 새 데이터는 거부됩니다. 당신은에 추가 할 수 있도록 규칙을 업데이트해야합니다 attendees 모음입니다.

를 들어 attendees 문서 이름으로 인증 UID를 사용하기 때문에 수집, 당신은 그것을 잡고 제출자의 확인할 수 있습니다 uid 그들이 작성하는 문서와 동일합니다. 모든 사람이 참석자 목록을 읽을 수 있도록 허용하지만(개인 데이터가 없기 때문에) 작성자만 업데이트할 수 있어야 합니다.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId;
    }
  }
}

유효성 검사 규칙 추가

모든 예상 필드가 문서에 있는지 확인하기 위해 데이터 유효성 검사를 추가합니다.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId
          && "attending" in request.resource.data;

    }
  }
}

(선택 사항) 이제 버튼을 클릭의 결과를 볼 수 있습니다. Firebase 콘솔에서 Cloud Firestore 대시보드로 이동합니다.

앱 미리보기

Firebase를 사용하여 대화형 실시간 웹 애플리케이션을 구축했습니다.

우리가 다룬 내용

  • Firebase 인증
  • 클라우드 파이어스토어
  • Firebase 보안 규칙

다음 단계

  • 다른 Firebase 제품에 대해 자세히 알고 싶으십니까? 사용자가 업로드한 이미지 파일을 저장하고 싶습니까? 아니면 사용자에게 알림을 보내시겠습니까? 아웃 확인 중포 기지 문서를 . Firebase용 Flutter 플러그인에 대해 자세히 알고 싶으십니까? 확인 FlutterFire을 자세한 내용은.
  • Cloud Firestore에 대해 자세히 알고 싶으십니까? 하위 컬렉션 및 트랜잭션에 대해 배우고 싶습니까? 받는 사람 향할 클라우드 경우 FireStore 웹 코드 랩 클라우드 경우 FireStore에 더 깊이로가는 코드 랩합니다. 또는이 확인 클라우드 경우 FireStore을 알게 유튜브 시리즈 !

더 알아보기

어떻게 되었나요?

우리는 당신의 피드백을 좋아할 것입니다! A (매우) 간단한 양식을 기입하십시오 여기 .