Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Kenali Firebase untuk Flutter

Dalam codelab ini, Anda akan belajar beberapa dasar-dasar Firebase untuk membuat Flutter aplikasi mobile untuk Android dan iOS.

Prasyarat

Codelab ini mengasumsikan Anda sudah familiar dengan Flutter, dan Anda telah menginstal Flutter SDK , dan editor .

Apa yang akan Anda buat

Dalam codelab ini Anda akan membuat aplikasi obrolan RSVP dan buku tamu acara di Android, iOS, Web, dan macOS menggunakan Flutter. Anda akan mengautentikasi pengguna dengan Firebase Authentication dan menyinkronkan data menggunakan Cloud Firestore.

Apa yang Anda butuhkan?

Anda dapat menjalankan codelab ini menggunakan salah satu perangkat berikut:

  • Perangkat fisik (Android atau iOS) yang terhubung ke komputer Anda dan disetel ke mode pengembang.
  • Simulator iOS. (Membutuhkan memasang alat Xcode .)
  • Emulator Androidnya. (Membutuhkan setup pada Android Studio .)

Selain yang di atas, Anda juga membutuhkan:

  • Peramban pilihan Anda, seperti Chrome.
  • IDE atau editor teks pilihan Anda, seperti Android Studio atau Kode VS dikonfigurasi dengan Dart dan Flutter plugin.
  • Terbaru stable versi Flutter (atau beta jika Anda menikmati hidup di tepi).
  • Akun Google, seperti akun gmail, untuk membuat dan mengelola proyek Firebase Anda.
  • Kode sampel codelab. Lihat langkah selanjutnya untuk cara mendapatkan kodenya.

Mari kita mulai dengan mengunduh versi awal proyek kita dari GitHub.

Mengkloning repositori GitHub dari baris perintah:

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

Atau, jika Anda memiliki cli GitHub ini alat diinstal:

gh repo clone flutter/codelabs flutter-codelabs

Kode contoh harus kloning ke dalam flutter-codelabs direktori, yang berisi kode untuk koleksi codelabs. Kode untuk codelab ini di flutter-codelabs/firebase-get-to-know-flutter .

Struktur direktori di bawah flutter-codelabs/firebase-get-to-know-flutter adalah serangkaian snapshot dari mana Anda harus pada akhir setiap langkah yang bernama. Ini adalah Langkah 2, jadi menemukan file yang cocok semudah:

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

Jika Anda ingin melompat ke depan, atau melihat seperti apa tampilan setelah suatu langkah, lihat di direktori yang dinamai sesuai dengan langkah yang Anda minati.

Impor aplikasi pemula

Terbuka atau mengimpor flutter-codelabs/firebase-get-to-know-flutter/step_02 direktori ke IDE pilihan Anda. Direktori ini berisi kode awal untuk codelab yang terdiri dari aplikasi pertemuan Flutter yang belum berfungsi.

Temukan file untuk dikerjakan

Kode dalam aplikasi ini tersebar di beberapa direktori. Pemisahan fungsi ini dirancang untuk mempermudah pengerjaan, dengan mengelompokkan kode berdasarkan fungsionalitas.

Temukan file berikut dalam proyek:

  • lib/main.dart : File ini berisi titik masuk utama dan widget aplikasi.
  • lib/src/widgets.dart : File ini berisi beberapa widget untuk membantu standarisasi styling aplikasi. Ini digunakan untuk membuat layar aplikasi pemula.
  • lib/src/authentication.dart : File ini berisi implementasi parsial FirebaseUI Tupoksi dengan satu set widget untuk membuat login pengalaman pengguna untuk otentikasi berbasis Firebase email. Widget untuk alur autentikasi ini belum digunakan di aplikasi pemula, tetapi Anda akan segera menghubungkannya.

Anda akan menambahkan file tambahan yang diperlukan untuk membangun sisa aplikasi.

Meninjau lib/main.dart berkas

Aplikasi ini mengambil keuntungan dari google_fonts paket untuk memungkinkan kita untuk membuat Roboto font default di seluruh aplikasi. Latihan bagi pembaca termotivasi adalah untuk mengeksplorasi fonts.google.com dan menggunakan font Anda menemukan ada di berbagai bagian aplikasi.

Anda memanfaatkan widget penolong dari lib/src/widgets.dart dalam bentuk Header , Paragraph dan IconAndDetail . Widget ini mengurangi kekacauan dalam tata letak halaman yang dijelaskan dalam HomePage dengan menghilangkan duplikasi kode. Ini memiliki manfaat tambahan untuk memungkinkan tampilan dan nuansa yang konsisten.

Berikut tampilan aplikasi Anda di Android, iOS, Web, dan macOS:

Pratinjau aplikasi

Menampilkan informasi acara sangat bagus untuk tamu Anda, tetapi hanya menampilkan acara tidak terlalu berguna bagi siapa pun. Mari tambahkan beberapa fungsi dinamis ke aplikasi ini. Untuk ini, Anda harus menghubungkan Firebase ke aplikasi Anda. Untuk memulai Firebase, Anda harus membuat dan menyiapkan proyek Firebase.

Buat proyek Firebase

  1. Masuk ke Firebase .
  2. Di konsol Firebase, klik Add Project (atau Buat proyek), dan nama Anda Firebase proyek Firebase-Flutter-Codelab.

4395e4e67c08043a.png

  1. Klik melalui opsi pembuatan proyek. Terima persyaratan Firebase jika diminta. Lewati penyiapan Google Analytics, karena Anda tidak akan menggunakan Analytics untuk aplikasi ini.

b7138cde5f2c7b61.png

Untuk mempelajari lebih lanjut tentang proyek Firebase, lihat Memahami proyek Firebase .

Aplikasi yang Anda buat menggunakan beberapa produk Firebase yang tersedia untuk aplikasi web:

  • Firebase Otentikasi untuk memungkinkan pengguna untuk masuk ke aplikasi Anda.
  • Cloud Firestore untuk menyimpan data terstruktur di atas awan dan mendapatkan pemberitahuan instan ketika data perubahan.
  • Firebase Aturan Keamanan untuk mengamankan database Anda.

Beberapa produk ini memerlukan konfigurasi khusus atau perlu diaktifkan menggunakan Firebase console.

Aktifkan email masuk untuk Firebase Authentication

Untuk memungkinkan pengguna untuk masuk ke aplikasi web, Anda akan menggunakan Email / Password masuk metode untuk codelab ini:

  1. Dalam Firebase konsol, memperluas menu Build di panel sebelah kiri.
  2. Klik Authentication, dan kemudian klik Dapatkan Started tombol, maka Sign-in metode tab (atau klik disini untuk langsung ke Sign-in tab metode).
  3. Klik Email / Password di Sign-in penyedia daftar, mengatur Aktifkan saklar ke posisi, dan kemudian klik Simpan. 58e3e3e23c2f16a4.png

Aktifkan Cloud Firestore

Aplikasi web menggunakan Cloud Firestore untuk menyimpan pesan chat dan menerima pesan chat baru.

Aktifkan Cloud Firestore:

  1. Pada bagian Build Firebase konsol, klik Cloud Firestore.
  2. Klik Membuat database. 99e8429832d23fa3.png
  1. Pilih Mulai dalam pilihan mode uji. Baca penafian tentang aturan keamanan. Mode uji memastikan bahwa Anda dapat dengan bebas menulis ke database selama pengembangan. Klik Next. 6be00e26c72ea032.png
  1. Pilih lokasi untuk database Anda (Anda bisa menggunakan default). Perhatikan bahwa lokasi ini tidak dapat diubah nanti. 278656eefcfb0216.png
  2. Klik Aktifkan.

Untuk menggunakan Firebase dengan Flutter, Anda harus mengikuti proses untuk mengonfigurasi proyek Flutter agar dapat menggunakan library FlutterFire dengan benar:

  • Tambahkan dependensi FlutterFire untuk pubspec.yaml
  • Daftarkan platform yang diinginkan pada proyek Firebase
  • Unduh file konfigurasi khusus platform, dan tambahkan ke kode.

Dalam direktori tingkat atas dari aplikasi Flutter Anda, ada subdirektori disebut ios dan android . Direktori ini masing-masing menyimpan file konfigurasi khusus platform untuk iOS dan Android.

Konfigurasikan dependensi

Anda perlu menambahkan library FlutterFire untuk dua produk Firebase yang Anda gunakan di aplikasi ini - Firebase Auth dan Cloud Firestore. Mengedit pubspec.yaml dan menambahkan dependensi berikut:

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

Meskipun Anda telah menambahkan paket yang diperlukan, Anda juga perlu mengonfigurasi proyek iOS, Android, macOS, dan Web runner untuk menggunakan Firebase dengan tepat. Anda juga menggunakan provider paket yang akan memungkinkan pemisahan logika bisnis dari logika layar.

Konfigurasikan iOS

  1. Dalam Firebase konsol , pilih Ikhtisar Proyek di bar navigasi sebelah kiri, dan klik tombol iOS bawah Mulailah dengan menambahkan Firebase untuk aplikasi Anda.

Anda akan melihat dialog berikut:

c42139f18fb9a2ee.png

  1. Nilai penting untuk memberikan adalah iOS bundel ID. Anda mendapatkan ID bundel dengan melakukan tiga langkah berikutnya.
  1. Di alat baris perintah, buka direktori tingkat atas aplikasi Flutter Anda.
  2. Jalankan perintah open ios/Runner.xcworkspace untuk membuka Xcode.
  1. Dalam Xcode, klik Runner tingkat atas di sebelah kiri, kemudian pilih Runner bawah Target, untuk menunjukkan tab General di panel kanan, seperti yang ditunjukkan. Salin nilai Bundle Identifier.

9d67acd88c718763.png

  1. Kembali ke dialog Firebase, tempelkan disalin Bundle Identifier ke dalam iOS bundel ID lapangan, dan klik Register App.
  1. Melanjutkan di Firebase, ikuti petunjuk untuk men-download file konfigurasi GoogleService-Info.plist .
  2. Kembali ke Xcode. Perhatikan bahwa Runner memiliki subfolder juga disebut Runner (ditunjukkan pada gambar sebelumnya).
  3. Tarik GoogleService-Info.plist berkas (yang baru saja Anda download) ke dalam Runner subfolder.
  4. Pada dialog yang muncul di Xcode, klik Finish.
  5. Jangan ragu untuk menutup Xcode pada saat ini, karena tidak diperlukan di masa mendatang.
  6. Kembali ke konsol Firebase. Pada langkah setup, klik Berikutnya, abaikan langkah, dan kembali ke halaman utama konsol Firebase.

Anda telah selesai mengonfigurasi aplikasi Flutter untuk iOS. Untuk lebih detail, silakan lihat dokumentasi instalasi FlutterFire iOS .

Konfigurasikan Android

  1. Dalam Konsol Firebase , pilih Ikhtisar Proyek di bar navigasi sebelah kiri, dan klik tombol Android di bawah Mulailah dengan menambahkan Firebase untuk aplikasi Anda.

Anda akan melihat dialog berikut: 8254fc299e82f528.png

  1. Nilai penting untuk memberikan adalah Android nama paket. Anda mendapatkan nama paket saat melakukan dua langkah berikut:
  1. Dalam direktori aplikasi Flutter Anda, buka file android/app/src/main/AndroidManifest.xml .
  2. Dalam manifest elemen, menemukan nilai string dari package atribut. Nilai ini adalah Android nama paket (sesuatu seperti com.yourcompany.yourproject ). Salin nilai ini.
  3. Dalam dialog Firebase, sisipkan nama paket disalin ke dalam bidang nama paket Android.
  4. Anda tidak perlu Debug sertifikat penandatanganan SHA-1 untuk codelab ini. Biarkan ini kosong.
  5. Klik Register App.
  6. Melanjutkan di Firebase, ikuti petunjuk untuk men-download file konfigurasi google-services.json .
  7. Pergi ke direktori aplikasi Flutter Anda, dan memindahkan google-services.json berkas (yang baru saja Anda download) ke dalam android/app direktori.
  8. Kembali ke Firebase console, lewati langkah selanjutnya, dan kembali ke halaman utama Firebase console.
  9. Mengedit Anda android/build.gradle untuk menambahkan google-services Plugin ketergantungan:

android/build.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. Mengedit Anda android/app/build.gradle untuk mengaktifkan google-services Plugin:

android/app/build.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 mengharuskan Multidex diaktifkan, dan salah satu cara untuk melakukannya adalah dengan menyetel SDK minimum yang didukung ke 21 atau lebih tinggi. Mengedit Anda android/app/build.gradle untuk memperbarui minSdkVersion :

android/app/build.gradle

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

Anda telah selesai mengonfigurasi aplikasi Flutter untuk Android. Untuk lebih detail, silakan lihat dokumentasi instalasi FlutterFire Android .

Konfigurasi untuk Web

  1. Dalam Konsol Firebase , pilih Ikhtisar Proyek di bar navigasi sebelah kiri, dan klik tombol Web di bawah Mulailah dengan menambahkan Firebase untuk aplikasi Anda.

25b14deff9e589ce.png

  1. Berikan aplikasi ini nama panggilan, dan klik pada tombol aplikasi Register. Kami akan membiarkan Firebase Hosting dimatikan untuk tutorial ini karena kami hanya akan menjalankannya secara lokal. Jangan ragu untuk membaca lebih lanjut tentang Firebase Hosting di sini. 9c697cc1b309c806.png
  2. Mengedit bagian tubuh Anda web/index.html file sebagai berikut. Pastikan untuk menambahkan firebaseConfig data dari langkah sebelumnya.

web/index.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>

Anda telah selesai mengonfigurasi aplikasi Flutter untuk Web. Untuk lebih detail, silakan lihat dokumentasi instalasi FlutterFire Web .

Konfigurasikan macOS

Langkah-langkah konfigurasi untuk macOS hampir identik dengan iOS. Kita akan menggunakan kembali file konfigurasi GoogleService-Info.plist dari iOS langkah di atas.

  1. Jalankan perintah open macos/Runner.xcworkspace untuk membuka Xcode.
  1. Tarik GoogleService-Info.plist file ke subfolder Runner. Ini diciptakan dalam langkah-langkah Konfigurasi iOS di atas. c2b9229a605fd738.png
  2. Dalam macos/Runner/DebugProfile.entitlements berkas, menambahkan com.apple.security.network.client hak, dan set ke true . 8bee5665e35d3f34.png
  3. Dalam macos/Runner/Release.entitlements berkas, juga menambahkan com.apple.security.network.client hak, dan set ke true . 41e2e23b7928546a.png
  4. Jangan ragu untuk menutup Xcode pada saat ini, karena tidak diperlukan di masa mendatang.

Anda telah selesai mengonfigurasi aplikasi Flutter untuk macOS. Untuk lebih detail, silakan lihat yang FlutterFire MacOS dokumentasi instalasi , dan dukungan Desktop untuk Flutter halaman.

Sekarang bahwa Anda telah menambahkan Firebase untuk aplikasi, Anda dapat mengatur tombol RSVP yang register orang yang menggunakan Firebase Authentication . Untuk bawaan Android, bawaan iOS, dan Web ada paket FirebaseUI Auth yang sudah dibuat sebelumnya, tetapi untuk Flutter Anda perlu membangun kemampuan ini.

Proyek yang Anda ambil di Langkah 2 menyertakan satu set widget yang mengimplementasikan antarmuka pengguna untuk sebagian besar alur autentikasi. Anda akan menerapkan logika bisnis untuk mengintegrasikan Firebase Authentication ke dalam aplikasi.

Logika Bisnis dengan Penyedia

Anda akan menggunakan provider paket untuk membuat aplikasi terpusat objek negara tersedia di seluruh pohon aplikasi widget Flutter. Untuk mulai dengan, memodifikasi impor di bagian atas lib/main.dart :

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';

The import garis memperkenalkan Firebase Core dan Tupoksi, tarik dalam provider paket yang Anda gunakan untuk membuat aplikasi objek negara yang tersedia melalui pohon widget, dan termasuk widget otentikasi dari lib/src .

Ini objek negara aplikasi, ApplicationState , memiliki dua tanggung jawab utama untuk langkah ini, tetapi akan mendapatkan tanggung jawab tambahan ketika Anda menambahkan kemampuan lebih untuk aplikasi dalam langkah-langkah selanjutnya. Tanggung jawab pertama adalah untuk menginisialisasi perpustakaan Firebase dengan panggilan untuk Firebase.initializeApp() , dan kemudian ada penanganan aliran otorisasi. Menambahkan kelas berikut untuk akhir lib/main.dart :

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

Perlu dicatat beberapa poin penting dalam kelas ini. Pengguna memulai tanpa otentikasi, aplikasi menunjukkan formulir yang meminta alamat email pengguna, tergantung pada apakah alamat email itu ada di file, aplikasi akan meminta pengguna mendaftar, atau meminta kata sandi mereka, dan kemudian mengasumsikan semuanya berhasil, pengguna diautentikasi.

Harus diperhatikan bahwa ini bukan implementasi lengkap dari alur FirebaseUI Auth, karena tidak menangani kasus pengguna dengan akun yang ada yang mengalami masalah saat masuk. Menerapkan kemampuan tambahan ini dibiarkan sebagai latihan untuk pembaca termotivasi.

Mengintegrasikan alur Otentikasi

Sekarang bahwa Anda memiliki awal negara aplikasi saatnya untuk kawat negara aplikasi ke dalam inisialisasi aplikasi dan menambahkan aliran otentikasi ke HomePage . Update titik masuk utama untuk mengintegrasikan negara aplikasi melalui provider paket:

lib/main.dart

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

Modifikasi ke main fungsi membuat paket penyedia bertanggung jawab untuk instantiating objek negara aplikasi menggunakan ChangeNotifierProvider widget. Anda menggunakan ini kelas penyedia tertentu karena objek negara aplikasi meluas ChangeNotifier dan ini memungkinkan provider paket untuk tahu kapan untuk menampilkan kembali tergantung widget. Akhirnya, mengintegrasikan negara aplikasi dengan Authentication dengan memperbarui HomePage 's build metode:

lib/main.dart

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

Anda instantiate Authentication widget, dan bungkus dalam Consumer widget. Konsumen widget cara yang biasa bahwa provider paket dapat digunakan untuk membangun kembali bagian dari pohon ketika perubahan negara aplikasi. The Authentication widget adalah UI otentikasi bahwa Anda sekarang akan tes.

Menguji alur Otentikasi

cdf2d25e436bd48d.png

Inilah awal dari alur otentikasi, di mana pengguna dapat mengetuk tombol RSVP, untuk memulai formulir email.

2a2cd6d69d172369.png

Setelah memasukkan email, sistem mengkonfirmasi apakah pengguna sudah terdaftar, dalam hal ini pengguna dimintai kata sandi, atau jika pengguna tidak terdaftar, maka mereka pergi melalui formulir pendaftaran.

e5e65065dba36b54.png

Pastikan untuk mencoba memasukkan kata sandi pendek (kurang dari enam karakter) untuk memeriksa alur penanganan kesalahan. Jika pengguna terdaftar, mereka akan melihat kata sandi untuknya.

fbb3ea35fb4f67a.png

Pada halaman ini pastikan untuk memasukkan kata sandi yang salah untuk memeriksa penanganan kesalahan pada halaman ini. Terakhir, setelah pengguna masuk, Anda akan melihat pengalaman masuk yang menawarkan pengguna kemampuan untuk keluar lagi.

4ed811a25b0cf816.png

Dan dengan itu, Anda telah menerapkan alur otentikasi. Selamat!

Mengetahui bahwa pengguna akan datang adalah hal yang bagus, tetapi mari berikan tamu hal lain untuk dilakukan di aplikasi. Bagaimana jika mereka bisa meninggalkan pesan di buku tamu? Mereka dapat berbagi mengapa mereka bersemangat untuk datang atau siapa yang ingin mereka temui.

Untuk menyimpan pesan chat yang pengguna menulis dalam aplikasi, Anda akan menggunakan Cloud Firestore .

Model data

Cloud Firestore adalah database NoSQL, dan data yang disimpan dalam database dibagi menjadi koleksi, dokumen, kolom, dan subkoleksi. Anda akan menyimpan setiap pesan chat sebagai dokumen dalam koleksi tingkat atas disebut guestbook .

7c20dc8424bb1d84.png

Tambahkan pesan ke Firestore

Di bagian ini, Anda akan menambahkan fungsionalitas bagi pengguna untuk menulis pesan baru ke database. Pertama, Anda menambahkan elemen UI (bidang formulir dan tombol kirim), lalu Anda menambahkan kode yang mengaitkan elemen-elemen ini ke database.

Pertama, tambahkan impor untuk cloud_firestore paket dan dart:async .

lib/main.dart

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';

Untuk membangun elemen UI dari kolom pesan dan tombol kirim, menambahkan stateful baru widget GuestBook di bagian bawah lib/main.dart .

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

Ada beberapa tempat menarik di sini. Pertama, Anda membuat Instansiasi Formulir sehingga upi dapat memvalidasi pesan yang sebenarnya memiliki beberapa konten, dan menunjukkan kepada pengguna pesan kesalahan jika tidak ada. Cara untuk memvalidasi formulir melibatkan mengakses negara berupa belakang formulir, dan untuk ini Anda menggunakan GlobalKey . Untuk informasi lebih lanjut tentang Keys, dan bagaimana menggunakannya, silakan lihat Flutter Widgets 101 episode "Kapan Gunakan Keys" .

Perhatikan juga cara widget diletakkan, Anda memiliki Row , dengan TextFormField dan StyledButton , yang itu sendiri berisi Row . Juga perhatikan TextFormField dibungkus dalam sebuah Expanded widget, pasukan ini TextFormField untuk mengambil setiap ruang ekstra di baris. Untuk lebih memahami mengapa hal ini diperlukan, silakan membaca kendala Memahami .

Sekarang setelah Anda memiliki widget yang memungkinkan pengguna memasukkan beberapa teks untuk ditambahkan ke Buku Tamu, Anda harus menampilkannya di layar. Untuk melakukannya, mengedit tubuh HomePage untuk menambahkan dua baris berikut di bagian bawah ListView 's anak:

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

Meskipun ini cukup untuk menampilkan Widget, itu tidak cukup untuk melakukan sesuatu yang berguna. Anda akan segera memperbarui kode ini agar berfungsi.

Pratinjau aplikasi

Seorang pengguna mengklik tombol SEND akan memicu potongan kode di bawah. Ia menambahkan isi dari field input pesan ke guestbook koleksi database. Secara khusus, addMessageToGuestBook metode menambah isi pesan ke dokumen baru (dengan ID secara otomatis) ke guestbook koleksi.

Perhatikan bahwa FirebaseAuth.instance.currentUser.uid adalah referensi ke auto-generated ID unik yang Firebase Authentication memberikan untuk semua log-in pengguna.

Membuat perubahan lain ke lib/main.dart berkas. Tambahkan addMessageToGuestBook metode. Anda akan menghubungkan antarmuka pengguna dan kemampuan ini bersama-sama di langkah berikutnya.

lib/main.dart

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
}

Menghubungkan UI ke database

Anda memiliki UI tempat pengguna dapat memasukkan teks yang ingin mereka tambahkan ke Buku Tamu, dan Anda memiliki kode untuk menambahkan entri ke Cloud Firestore. Sekarang yang perlu Anda lakukan adalah menyambungkan keduanya. Dalam lib/main.dart membuat perubahan berikut ke HomePage widget.

lib/main.dart

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

Anda telah mengganti dua baris yang Anda tambahkan kembali di awal langkah ini dengan implementasi penuh. Anda lagi menggunakan Consumer<ApplicationState> untuk membuat negara aplikasi yang tersedia untuk bagian dari pohon Anda rendering. Ini memungkinkan Anda untuk bereaksi terhadap seseorang yang memasukkan pesan di UI, dan memublikasikannya ke dalam database. Di bagian berikutnya Anda akan menguji apakah pesan yang ditambahkan dipublikasikan ke dalam database.

Uji pengiriman pesan

  1. Pastikan Anda masuk ke aplikasi.
  2. Masukkan pesan seperti "Hei!", Lalu klik KIRIM.

Tindakan ini menulis pesan ke database Cloud Firestore Anda. Namun, Anda belum akan melihat pesan tersebut di aplikasi Flutter Anda yang sebenarnya karena Anda masih perlu menerapkan pengambilan data. Anda akan melakukannya di langkah berikutnya.

Tetapi Anda dapat melihat pesan yang baru ditambahkan di konsol Firebase.

Dalam Firebase konsol, di database dashboard , Anda harus melihat guestbook koleksi dengan pesan Anda baru ditambahkan. Jika Anda terus mengirim pesan, koleksi buku tamu Anda akan berisi banyak dokumen, seperti ini:

Konsol Firebase

713870af0b3b63c.png

Sangat menyenangkan bahwa para tamu dapat menulis pesan ke database, tetapi mereka belum dapat melihatnya di aplikasi. Mari kita perbaiki itu!

Sinkronkan pesan

Untuk menampilkan pesan, Anda harus menambahkan listener yang memicu saat data berubah, lalu membuat elemen UI yang menampilkan pesan baru. Anda akan menambahkan kode ke status aplikasi yang mendengarkan pesan yang baru ditambahkan dari aplikasi.

Tepat di atas GuestBook widget kelas nilai berikut. Kelas ini menampilkan tampilan terstruktur dari data yang Anda simpan di Cloud Firestore.

lib/main.dart

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

Pada bagian dari ApplicationState mana Anda mendefinisikan negara dan getter, tambahkan baris baru berikut:

lib/main.dart

  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.

Dan akhirnya, di bagian inisialisasi ApplicationState , tambahkan berikut untuk berlangganan query atas koleksi dokumen ketika pengguna log in, dan berhenti berlangganan ketika mereka log out.

lib/main.dart

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

Bagian ini penting, karena di sini adalah di mana Anda membangun sebuah permintaan atas guestbook koleksi, dan menangani berlangganan dan berhenti berlangganan untuk koleksi ini. Anda mendengarkan aliran, di mana Anda merekonstruksi cache lokal dari pesan dalam guestbook koleksi, dan juga menyimpan referensi ke langganan ini sehingga Anda dapat berhenti berlangganan nanti. Ada banyak hal yang terjadi di sini, dan ada baiknya menghabiskan waktu di debugger untuk memeriksa apa yang terjadi ketika mendapatkan model mental yang lebih jelas.

Untuk informasi lebih lanjut, lihat dokumentasi Cloud Firestore .

Dalam GuestBook widget Anda perlu menghubungkan negara mengubah ini untuk user interface. Anda memodifikasi widget dengan menambahkan daftar pesan sebagai bagian dari konfigurasinya.

lib/main.dart

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

Berikutnya, kita mengekspos konfigurasi baru ini di _GuestBookState dengan memodifikasi build metode sebagai berikut.

lib/main.dart

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

Anda membungkus isi sebelumnya metode membangun dengan Column widget, dan kemudian di ekor Column 's anak Anda menambahkan koleksi untuk untuk menghasilkan baru Paragraph untuk setiap pesan dalam daftar pesan.

Akhirnya, Anda sekarang perlu untuk memperbarui tubuh HomePage untuk benar membangun GuestBook dengan baru messages parameter.

lib/main.dart

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

Uji sinkronisasi pesan

Cloud Firestore secara otomatis dan instan menyinkronkan data dengan klien yang berlangganan database.

  1. Pesan yang Anda buat sebelumnya di database harus ditampilkan di aplikasi. Jangan ragu untuk menulis pesan baru; mereka harus muncul secara instan.
  2. Jika Anda membuka ruang kerja di beberapa jendela atau tab, pesan akan disinkronkan secara real time di seluruh tab.
  3. (Opsional) Anda dapat mencoba secara manual menghapus, memodifikasi, atau menambahkan pesan baru secara langsung di bagian Database konsol Firebase; perubahan apa pun akan muncul di UI.

Selamat! Anda sedang membaca dokumen Cloud Firestore di aplikasi Anda!

App p tinjauan

Anda awalnya menyiapkan Cloud Firestore untuk menggunakan mode pengujian, artinya database Anda terbuka untuk membaca dan menulis. Namun, Anda hanya boleh menggunakan mode uji selama tahap pengembangan yang sangat awal. Sebagai praktik terbaik, Anda harus menyiapkan aturan keamanan untuk database saat mengembangkan aplikasi. Keamanan harus menjadi bagian integral dari struktur dan perilaku aplikasi Anda.

Aturan Keamanan memungkinkan Anda mengontrol akses ke dokumen dan koleksi di database Anda. Sintaks aturan yang fleksibel memungkinkan Anda membuat aturan yang cocok dengan apa pun, mulai dari semua penulisan ke seluruh database hingga operasi pada dokumen tertentu.

Anda dapat menulis aturan keamanan untuk Cloud Firestore di Firebase console:

  1. Dalam Mengembangkan bagian Firebase konsol, klik Database, kemudian pilih tab Aturan (atau klik disini untuk langsung ke tab Aturan).
  2. Anda akan melihat aturan keamanan default berikut, bersama dengan peringatan tentang aturan yang bersifat publik.

7767a2d2e64e7275.png

Identifikasi koleksi

Pertama, identifikasi koleksi tempat aplikasi menulis data.

Dalam match /databases/{database}/documents , mengidentifikasi koleksi yang Anda ingin mengamankan:

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

Tambahkan aturan keamanan

Karena Anda menggunakan UID Otentikasi sebagai bidang di setiap dokumen buku tamu, Anda bisa mendapatkan UID Otentikasi dan memverifikasi bahwa siapa pun yang mencoba menulis ke dokumen memiliki UID Otentikasi yang cocok.

Tambahkan aturan baca dan tulis ke set aturan Anda seperti yang ditunjukkan di bawah ini:

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

Sekarang, untuk buku tamu, hanya pengguna yang masuk yang dapat membaca pesan (pesan apa pun!), tetapi hanya pembuat pesan yang dapat mengedit pesan.

Tambahkan aturan validasi

Tambahkan validasi data untuk memastikan bahwa semua bidang yang diharapkan ada dalam dokumen:

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

Catat status RSVP peserta

Saat ini, aplikasi Anda hanya memungkinkan orang untuk mulai mengobrol jika mereka tertarik dengan acara tersebut. Juga, satu-satunya cara Anda tahu jika seseorang datang adalah jika mereka mempostingnya di obrolan. Mari kita mengatur dan memberi tahu orang-orang berapa banyak orang yang datang.

Anda akan menambahkan beberapa kemampuan baru ke status aplikasi. Yang pertama adalah kemampuan bagi pengguna yang masuk untuk mencalonkan apakah mereka hadir atau tidak. Kemampuan kedua adalah penghitung berapa banyak orang yang benar-benar hadir.

Dalam lib/main.dart , tambahkan berikut ke bagian accesor untuk memungkinkan kode UI untuk berinteraksi dengan keadaan ini:

lib/main.dart

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

Perbarui ApplicationState 's init metode sebagai berikut:

lib/main.dart

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

Di atas menambahkan kueri selalu berlangganan untuk mengetahui jumlah peserta, dan kueri kedua yang hanya aktif saat pengguna masuk untuk mengetahui apakah pengguna hadir. Berikutnya, tambahkan pencacahan berikut setelah GuestBookMessage deklarasi:

lib/main.dart

enum Attending { yes, no, unknown }

Anda sekarang akan menentukan widget baru yang berfungsi seperti tombol radio lama. Ini dimulai dalam keadaan tak tentu, dengan tidak ya atau tidak dipilih, tetapi setelah pengguna memilih apakah mereka hadir atau tidak, maka Anda menunjukkan opsi yang disorot dengan tombol yang diisi, dan opsi lainnya surut dengan rendering datar.

lib/main.dart

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

Berikutnya, Anda perlu memperbarui HomePage 's metode membangun untuk mengambil keuntungan dari YesNoSelection , memungkinkan login pengguna untuk mencalonkan jika mereka menghadiri. Anda juga akan menampilkan jumlah peserta untuk acara ini.

lib/main.dart

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

Tambahkan aturan

Karena Anda sudah menyiapkan beberapa aturan, data baru yang Anda tambahkan dengan tombol akan ditolak. Anda harus memperbarui aturan untuk memungkinkan menambah attendees koleksi.

Untuk attendees koleksi, karena Anda menggunakan Authentication UID sebagai nama dokumen, Anda bisa ambil dan memverifikasi bahwa submitter ini uid adalah sama dengan dokumen yang mereka tulis. Anda akan mengizinkan semua orang membaca daftar peserta (karena tidak ada data pribadi di sana), tetapi hanya pembuatnya yang dapat memperbaruinya.

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

Tambahkan aturan validasi

Tambahkan validasi data untuk memastikan bahwa semua bidang yang diharapkan ada dalam dokumen:

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;

    }
  }
}

(Opsional) Anda sekarang dapat melihat hasil mengklik tombol. Buka dasbor Cloud Firestore Anda di Firebase console.

Pratinjau aplikasi

Anda telah menggunakan Firebase untuk membuat aplikasi web waktu nyata yang interaktif!

Apa yang telah kita bahas

  • Otentikasi Firebase
  • Cloud Firestore
  • Aturan Keamanan Firebase

Langkah selanjutnya

  • Ingin mempelajari lebih lanjut tentang produk Firebase lainnya? Mungkin Anda ingin menyimpan file gambar yang diunggah pengguna? Atau mengirim pemberitahuan ke pengguna Anda? Memeriksa dokumentasi Firebase . Ingin mempelajari lebih lanjut tentang plugin Flutter untuk Firebase? Periksa FlutterFire untuk informasi lebih lanjut.
  • Ingin mempelajari lebih lanjut tentang Cloud Firestore? Mungkin Anda ingin belajar tentang subkoleksi dan transaksi? Kepala ke codelab web Cloud Firestore untuk codelab yang masuk ke lebih mendalam tentang Cloud Firestore. Atau periksa ini seri YouTube untuk mengenal Cloud Firestore !

Belajarlah lagi

Bagaimana hasilnya?

Kami akan menyukai tanggapan Anda! Silahkan isi (sangat) bentuk pendek di sini .