Firebase for Flutter'ı tanıyın

Koleksiyonlar ile düzeninizi koruyun İçeriği tercihlerinize göre kaydedin ve kategorilere ayırın.

1. Başlamadan önce

Bu kod laboratuvarında, Android ve iOS için Flutter mobil uygulamaları oluşturmaya yönelik Firebase'in bazı temel bilgilerini öğreneceksiniz.

Önkoşullar

ne öğreneceksin

  • Flutter ile Android, iOS, Web ve macOS'ta bir etkinlik LCV'si ve ziyaretçi defteri sohbet uygulaması nasıl oluşturulur?
  • Firebase Authentication ile kullanıcıların kimlik doğrulaması nasıl yapılır ve veriler Firestore ile nasıl senkronize edilir.

Neye ihtiyacın olacak

Aşağıdaki cihazlardan herhangi biri:

  • Bilgisayarınıza bağlı ve geliştirici moduna ayarlanmış fiziksel bir Android veya iOS cihazı.
  • iOS simülatörü ( Xcode araçları gerektirir).
  • Android öykünücüsü ( Android Studio'da kurulum gerektirir).

Ayrıca şunlara da ihtiyacınız var:

  • Google Chrome gibi seçtiğiniz bir tarayıcı.
  • Android Studio veya Visual Studio Code gibi Dart ve Flutter eklentileriyle yapılandırılmış, seçtiğiniz bir IDE veya metin düzenleyici.
  • Sınırda yaşamayı seviyorsanız Flutter veya beta en son stable sürümü.
  • Firebase projenizin oluşturulması ve yönetimi için bir Google Hesabı.
  • Firebase CLI , Google Hesabınızda oturum açtı.

2. Örnek kodu alın

Projenizin ilk sürümünü GitHub'dan indirin:

  1. Komut satırından, flutter-codelabs dizinindeki GitHub deposunu klonlayın:
git clone https://github.com/flutter/codelabs.git flutter-codelabs

flutter-codelabs dizini, bir codelabs koleksiyonunun kodunu içerir. Bu codelab'in kodu flutter-codelabs/firebase-get-to-know-flutter dizinindedir. Dizin, projenizin her adımın sonunda nasıl görünmesi gerektiğini gösteren bir dizi anlık görüntü içerir. Örneğin, ikinci adımdasınız.

  1. İkinci adım için eşleşen dosyaları bulun:
cd flutter-codelabs/firebase-get-to-know-flutter/step_02

İleri atlamak veya bir adımdan sonra bir şeyin nasıl görünmesi gerektiğini görmek istiyorsanız, ilgilendiğiniz adımın adını taşıyan dizine bakın.

Başlangıç ​​uygulamasını içe aktarın

  • flutter-codelabs/firebase-get-to-know-flutter/step_02 dizinini açın veya içe aktarın. Bu dizin, henüz işlevsel olmayan bir Flutter buluşma uygulamasından oluşan codelab için başlangıç ​​kodunu içerir.

Çalışma gerektiren dosyaları bulun

Bu uygulamadaki kod, birden çok dizine yayılmıştır. Bu işlevsellik ayrımı, kodu işlevselliğe göre gruplandırdığı için işi kolaylaştırır.

  • Aşağıdaki dosyaları bulun:
    • lib/main.dart : Bu dosya, ana giriş noktasını ve uygulama widget'ını içerir.
    • lib/src/widgets.dart : Bu dosya, uygulamanın stilini standartlaştırmaya yardımcı olacak bir avuç pencere öğesi içerir. Başlangıç ​​uygulamasının ekranını oluştururlar.
    • lib/src/authentication.dart : Bu dosya, Firebase e-posta tabanlı kimlik doğrulaması için oturum açma kullanıcı deneyimi oluşturmak üzere bir dizi pencere öğesiyle birlikte Kimlik Doğrulama'nın kısmi bir uygulamasını içerir. Kimlik doğrulama akışı için bu pencere öğeleri henüz başlangıç ​​uygulamasında kullanılmaz, ancak bunları yakında eklersiniz.

Uygulamanın geri kalanını oluşturmak için gereken ek dosyaları eklersiniz.

lib/main.dart dosyasını inceleyin

Bu uygulama, Roboto'yu uygulama genelinde varsayılan yazı tipi yapmak için google_fonts paketinden yararlanır. Fonts.google.com'u keşfedebilir ve orada keşfettiğiniz yazı tiplerini uygulamanın farklı bölümlerinde kullanabilirsiniz.

Yardımcı pencere öğelerini lib/src/widgets.dart dosyasından Header , Paragraph ve IconAndDetail . Bu widget'lar, HomePage açıklanan sayfa düzenindeki karışıklığı azaltmak için yinelenen kodu ortadan kaldırır. Bu aynı zamanda tutarlı bir görünüm ve his sağlar.

Uygulamanız Android, iOS, Web ve macOS'ta şöyle görünür:

3. Bir Firebase projesi oluşturun ve yapılandırın

Etkinlik bilgilerinin görüntülenmesi misafirleriniz için harikadır, ancak tek başına kimse için pek kullanışlı değildir. Uygulamaya bazı dinamik işlevler eklemeniz gerekir. Bunu yapmak için Firebase'i uygulamanıza bağlamanız gerekir. Firebase'i kullanmaya başlamak için bir Firebase projesi oluşturmanız ve yapılandırmanız gerekir.

Bir Firebase projesi oluşturun

  1. Firebase'de oturum açın.
  2. Konsolda, Proje Ekle'ye veya Bir proje oluştur'a tıklayın.
  3. Proje adı alanına Firebase-Flutter-Codelab yazın ve ardından Devam'a tıklayın.

4395e4e67c08043a.png

  1. Proje oluşturma seçeneklerini tıklayın. İstenirse, Firebase şartlarını kabul edin, ancak bu uygulama için kullanmayacağınız için Google Analytics kurulumunu atlayın.

b7138cde5f2c7b61.png

Firebase projeleri hakkında daha fazla bilgi edinmek için Firebase projelerini anlama bölümüne bakın.

Uygulama, web uygulamaları için kullanılabilen aşağıdaki Firebase ürünlerini kullanır:

  • Kimlik doğrulama: Kullanıcıların uygulamanızda oturum açmasına izin verir.
  • Firestore: Yapılandırılmış verileri buluta kaydeder ve veriler değiştiğinde anında bildirim alır.
  • Firebase Güvenlik Kuralları: Veritabanınızın güvenliğini sağlar.

Bu ürünlerden bazılarının özel yapılandırmaya ihtiyacı var veya bunları Firebase konsolunda etkinleştirmeniz gerekiyor.

E-posta oturum açma kimlik doğrulamasını etkinleştir

  1. Firebase konsolunun Projeye genel bakış bölmesinde Oluştur menüsünü genişletin.
  2. Kimlik Doğrulama > Başlayın > Oturum açma yöntemi > E-posta/Parola > Etkinleştir > Kaydet öğesine tıklayın .

58e3e3e23c2f16a4.png

Firestore'u etkinleştir

Web uygulaması, sohbet mesajlarını kaydetmek ve yeni sohbet mesajları almak için Firestore'u kullanır.

Firestore'u etkinleştirin:

  • Oluştur menüsünde, Cloud Firestore > Veritabanı oluştur'a tıklayın.

99e8429832d23fa3.png

  1. Test modunda başlat'ı seçin ve ardından güvenlik kuralları hakkındaki sorumluluk reddini okuyun. Test modu, geliştirme sırasında veritabanına serbestçe yazabilmenizi sağlar.

6be00e26c72ea032.png

  1. İleri'ye tıklayın ve ardından veritabanınız için konumu seçin. Varsayılanı kullanabilirsiniz. Konumu daha sonra değiştiremezsiniz.

278656eefcfb0216.png

  1. Etkinleştir'i tıklayın.

4. Firebase'i yapılandırın

Firebase'i Flutter ile birlikte kullanmak için, Flutter projesini FlutterFire kitaplıklarını doğru şekilde kullanacak şekilde yapılandırmak üzere aşağıdaki görevleri tamamlamanız gerekir:

  1. FlutterFire bağımlılıklarını projenize ekleyin.
  2. İstenen platformu Firebase projesine kaydedin.
  3. Platforma özgü yapılandırma dosyasını indirin ve ardından koda ekleyin.

Flutter uygulamanızın en üst düzey dizininde sırasıyla iOS ve Android için platforma özel yapılandırma dosyalarını tutan android , ios , macos ve web alt dizinleri bulunur.

Bağımlılıkları yapılandırma

Bu uygulamada kullandığınız iki Firebase ürünü için FlutterFire kitaplıklarını eklemeniz gerekir: Authentication ve Firestore.

  • Komut satırından aşağıdaki bağımlılıkları ekleyin:
$ flutter pub add firebase_core

firebase_core paketi , tüm Firebase Flutter eklentileri için gereken ortak koddur.

$ flutter pub add firebase_auth

firebase_auth paketi , Kimlik Doğrulama ile entegrasyonu sağlar.

$ flutter pub add cloud_firestore

cloud_firestore paketi , Firestore veri deposuna erişim sağlar.

$ flutter pub add provider

firebase_ui_auth paketi , kimlik doğrulama akışlarıyla geliştirici hızını artırmak için bir dizi pencere öğesi ve yardımcı program sağlar.

$ flutter pub add firebase_ui_auth

Gerekli paketleri eklediniz ancak Firebase'i uygun şekilde kullanmak için iOS, Android, macOS ve Web runner projelerini de yapılandırmanız gerekiyor. İş mantığının görüntüleme mantığından ayrılmasını sağlayan provider paketini de kullanırsınız.

FlutterFire CLI'yi kurun

FlutterFire CLI, temeldeki Firebase CLI'ye bağlıdır.

  1. Henüz yapmadıysanız, Firebase CLI'yi makinenize kurun.
  2. FlutterFire CLI'yi kurun:
$ dart pub global activate flutterfire_cli

Kurulduktan sonra, flutterfire komutu küresel olarak kullanılabilir.

Uygulamalarınızı yapılandırın

CLI, belirli bir platform için tüm yapılandırmayı oluşturmak üzere Firebase projenizden ve seçilen proje uygulamalarından bilgi alır.

Uygulamanızın kökünde, configure komutunu çalıştırın:

$ flutterfire configure

Yapılandırma komutu, aşağıdaki işlemlerde size yol gösterir:

  1. .firebaserc dosyasına dayalı veya Firebase Konsolundan bir Firebase projesi seçin.
  2. Android, iOS, macOS ve web gibi yapılandırma platformlarını belirleyin.
  3. Yapılandırmanın ayıklanacağı Firebase uygulamalarını tanımlayın. Varsayılan olarak CLI, mevcut proje yapılandırmanıza göre Firebase uygulamalarını otomatik olarak eşleştirmeye çalışır.
  4. Projenizde bir firebase_options.dart dosyası oluşturun.

macOS'i yapılandırın

macOS'ta Flutter, tamamen korumalı alan uygulamaları oluşturur. Bu uygulama, Firebase sunucularıyla iletişim kurmak için ağ ile entegre olduğundan, uygulamanızı ağ istemcisi ayrıcalıklarıyla yapılandırmanız gerekir.

macos/Runner/DebugProfile.entitlements

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.cs.allow-jit</key>
	<true/>
	<key>com.apple.security.network.server</key>
	<true/>
  <!-- Add the following two lines -->
	<key>com.apple.security.network.client</key>
	<true/>
</dict>
</plist>

macos/Runner/Release.entitlements

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
  <!-- Add the following two lines -->
	<key>com.apple.security.network.client</key>
	<true/>
</dict>
</plist>

Daha fazla bilgi için bkz. Flutter için Masaüstü desteği .

5. LCV işlevi ekleyin

Firebase'i uygulamaya eklediğinize göre, Authentication ile kişileri kaydeden bir LCV düğmesi oluşturabilirsiniz. Android yerel, iOS yerel ve Web için önceden oluşturulmuş FirebaseUI Auth paketleri vardır, ancak bu yeteneği Flutter için oluşturmanız gerekir.

Daha önce aldığınız proje, kimlik doğrulama akışının çoğu için kullanıcı arabirimini uygulayan bir dizi pencere öğesi içeriyordu. Kimlik Doğrulamayı uygulama ile entegre etmek için iş mantığını uygularsınız.

Provider paketi ile iş mantığı ekleyin

Uygulamanın Flutter pencere öğeleri ağacında merkezi bir uygulama durumu nesnesi oluşturmak için provider paketini kullanın:

  1. lib/main.dart dosyasının üst kısmındaki içe aktarmaları değiştirin:

lib/main.dart

import 'dart:async';                                     // new
import 'package:firebase_auth/firebase_auth.dart'        // new
    hide EmailAuthProvider, PhoneAuthProvider;           // new
import 'package:firebase_core/firebase_core.dart';       // new
import 'package:firebase_ui_auth/firebase_ui_auth.dart'; // new
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';                 // new

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

import deyimleri, Firebase Core ve Auth'u tanıtır, uygulama durumu nesnesini pencere öğesi ağacında kullanılabilir kılan provider paketini çeker ve firebase_ui_auth paketindeki kimlik doğrulama parçacıklarını içerir.

Bu ApplicationState uygulama durumu nesnesinin, bu adım için bir ana sorumluluğu vardır; bu, parçacık ağacını kimliği doğrulanmış bir durumda bir güncelleme olduğu konusunda uyarmaktır.

  1. Aşağıdaki sınıfı lib/main.dart dosyasının sonuna ekleyin:

lib/main.dart

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

  bool _loggedIn = false;
  bool get loggedIn => _loggedIn;

  Future<void> init() async {
    await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform);

    FirebaseUIAuth.configureProviders([
      EmailAuthProvider(),
    ]);

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loggedIn = true;
      } else {
        _loggedIn = false;
      }
      notifyListeners();
    });
  }
}

Bir sağlayıcıyı yalnızca bir kullanıcının oturum açma durumunu uygulamaya iletmek için kullanırsınız. Bir kullanıcının oturum açmasına izin vermek için, uygulamalarınızda oturum açma ekranlarını hızlı bir şekilde başlatmanın harika bir yolu olan firebase_ui_auth paketi tarafından sağlanan kullanıcı arayüzlerini kullanırsınız.

Kimlik doğrulama akışını entegre edin

  1. Uygulama durumunu uygulama başlatmaya bağlayın ve ardından kimlik doğrulama akışını HomePage ekleyin:

lib/main.dart

void main() {
  // Modify from here...
  WidgetsFlutterBinding.ensureInitialized();

  runApp(ChangeNotifierProvider(
    create: (context) => ApplicationState(),
    builder: ((context, child) => const App()),
  ));
  // ...to here.
}

main() işlevinde yapılan değişiklik, sağlayıcı paketini, ChangeNotifierProvider parçacığıyla uygulama durumu nesnesinin somutlaştırılmasından sorumlu kılar. Bu belirli provider sınıfını kullanırsınız çünkü uygulama durumu nesnesi, provider paketinin bağımlı parçacıkların ne zaman yeniden görüntüleneceğini bilmesini sağlayan ChangeNotifier sınıfını genişletir.

  1. FirebaseUI'nin size sağladığı farklı ekranlarda gezinmeyi işlemek için uygulamanızı güncelleyin:

lib/main.dart

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //Start adding here
      initialRoute: '/home',
      routes: {
        '/home': (context) {
          return const HomePage();
        },
        '/sign-in': ((context) {
          return SignInScreen(
            actions: [
              ForgotPasswordAction(((context, email) {
                Navigator.of(context)
                    .pushNamed('/forgot-password', arguments: {'email': email});
              })),
              AuthStateChangeAction(((context, state) {
                if (state is SignedIn || state is UserCreated) {
                  var user = (state is SignedIn)
                      ? state.user
                      : (state as UserCreated).credential.user;
                  if (user == null) {
                    return;
                  }
                  if (state is UserCreated) {
                    user.updateDisplayName(user.email!.split('@')[0]);
                  }
                  if (!user.emailVerified) {
                    user.sendEmailVerification();
                    const snackBar = SnackBar(
                        content: Text(
                            'Please check your email to verify your email address'));
                    ScaffoldMessenger.of(context).showSnackBar(snackBar);
                  }
                  Navigator.of(context).pushReplacementNamed('/home');
                }
              })),
            ],
          );
        }),
        '/forgot-password': ((context) {
          final arguments = ModalRoute.of(context)?.settings.arguments
              as Map<String, dynamic>?;

          return ForgotPasswordScreen(
            email: arguments?['email'] as String,
            headerMaxExtent: 200,
          );
        }),
        '/profile': ((context) {
          return ProfileScreen(
            providers: [],
            actions: [
              SignedOutAction(
                ((context) {
                  Navigator.of(context).pushReplacementNamed('/home');
                }),
              ),
            ],
          );
        })
      },
      // end adding here
      title: 'Firebase Meetup',
      theme: ThemeData(
        buttonTheme: Theme.of(context).buttonTheme.copyWith(
              highlightColor: Colors.deepPurple,
            ),
        primarySwatch: Colors.deepPurple,
        textTheme: GoogleFonts.robotoTextTheme(
          Theme.of(context).textTheme,
        ),
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
    );
  }
}

Her ekran, kimlik doğrulama akışının yeni durumuna bağlı olarak kendisiyle ilişkilendirilmiş farklı türde bir eyleme sahiptir. Kimlik doğrulamadaki çoğu durum değişikliğinden sonra, ister ana ekran ister profil gibi farklı bir ekran olsun, tercih edilen bir ekrana yeniden yönlendirebilirsiniz.

  1. HomePage sınıfının derleme yönteminde, uygulama durumunu AuthFunc küçük aracıyla entegre edin:

lib/main.dart

class HomePage extends StatelessWidget {
  const HomePage({super.key});

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

AuthFunc parçacığını başlatır ve onu bir Consumer parçacığına sararsınız. Tüketici widget'ı, uygulama durumu değiştiğinde provider paketinin ağacın bir bölümünü yeniden oluşturmak için kullanılabileceği olağan yoldur. AuthFunc widget'ı, test ettiğiniz tamamlayıcı widget'lardır.

Kimlik doğrulama akışını test edin

cdf2d25e436bd48d.png

  1. Uygulamada SignInScreen başlatmak için LCV düğmesine dokunun.

2a2cd6d69d172369.png

  1. Bir e-mail adresi girin. Zaten kayıtlıysanız, sistem sizden bir şifre girmenizi ister. Aksi takdirde, sistem sizden kayıt formunu doldurmanızı ister.

e5e65065dba36b54.png

  1. Hata işleme akışını kontrol etmek için altı karakterden kısa bir parola girin. Kayıtlıysanız, bunun yerine şifresini görürsünüz.
  2. Hata işleme akışını kontrol etmek için yanlış parolalar girin.
  3. Doğru parolayı girin. Kullanıcıya oturumu kapatma olanağı sunan oturum açma deneyimini görürsünüz.

4ed811a25b0cf816.png

6. Firestore'a mesaj yazın

Kullanıcıların geleceğini bilmek harika ama konuklara uygulamada yapacakları başka bir şey vermeniz gerekiyor. Ya bir ziyaretçi defterine mesaj bırakabilirlerse? Gelmek için neden heyecanlandıklarını veya kiminle tanışmayı umduklarını paylaşabilirler.

Kullanıcıların uygulamada yazdığı sohbet mesajlarını depolamak için Firestore'u kullanırsınız.

Veri örneği

Firestore bir NoSQL veritabanıdır ve veritabanında depolanan veriler koleksiyonlara, belgelere, alanlara ve alt koleksiyonlara bölünmüştür. Sohbetin her mesajını, üst düzey bir koleksiyon olan bir ziyaretçi defteri koleksiyonunda bir belge olarak gustbook .

7c20dc8424bb1d84.png

Firestore'a mesaj ekleyin

Bu bölümde, kullanıcıların veritabanına mesaj yazması için işlevsellik eklersiniz. Önce bir form alanı ve gönder butonu ekliyorsunuz ve ardından bu elemanları veri tabanına bağlayan kodu ekliyorsunuz.

  1. lib/main.dart dosyasında, cloud_firestore ve dart:async paketleri için içe aktarmaları ekleyin:

lib/main.dart

import 'dart:async';                                    // new

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

import 'firebase_options.dart';
import 'src/authentication.dart';
import 'src/widgets.dart';
  1. lib/main.dart dosyasının sonuna, bir mesaj alanının kullanıcı arabirimi öğelerini ve bir gönder düğmesini oluşturmak için durum bilgisi olan bir Konuk GuestBook pencere öğesi ekleyin:

lib/main.dart

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

  @override
  State<GuestBook> 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;
                },
              ),
            ),
            const SizedBox(width: 8),
            StyledButton(
              onPressed: () async {
                if (_formKey.currentState!.validate()) {
                  await widget.addMessage(_controller.text);
                  _controller.clear();
                }
              },
              child: Row(
                children: const [
                  Icon(Icons.send),
                  SizedBox(width: 4),
                  Text('SEND'),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Burada birkaç ilgi çekici nokta var. İlk olarak, mesajın gerçekten içerik içerdiğini doğrulayabilmeniz ve kullanıcıya bir hata mesajı yoksa bir hata mesajı gösterebilmeniz için bir form örneği oluşturursunuz. Bir formu doğrulamak için, formun arkasındaki form durumuna bir GlobalKey ile erişirsiniz. Tuşlar ve bunların nasıl kullanılacağı hakkında daha fazla bilgi için Tuşları Ne Zaman Kullanmalı konusuna bakın.

Ayrıca pencere öğelerinin düzenlenme biçimine dikkat edin, bir TextFormField içeren bir StyledButton ve bir Row içeren bir Row sahipsiniz. Ayrıca, TextFormField öğesinin, TextFormField satırdaki herhangi bir fazladan alanı doldurmaya zorlayan bir Expanded widget'ına sarıldığına da dikkat edin. Bunun neden gerekli olduğunu daha iyi anlamak için Kısıtlamaları anlama bölümüne bakın.

Artık kullanıcının Ziyaretçi Defterine eklemek üzere bir miktar metin girmesini sağlayan bir widget'a sahip olduğunuza göre, onu ekrana almanız gerekiyor.

  1. ListView alt öğelerinin sonuna aşağıdaki iki satırı eklemek için HomePage gövdesini düzenleyin:
const Header("What we'll be doing"),
const Paragraph(
  'Join us for a day full of Firebase Workshops and Pizza!',
),
// Add the following two lines.
const Header('Discussion'),
GuestBook(addMessage: (message) => print(message)),

Bu, widget'ı görüntülemek için yeterli olsa da, yararlı bir şey yapmak için yeterli değildir. İşlevsel hale getirmek için bu kodu kısa süre içinde güncellersiniz.

Uygulama önizlemesi

Bir kullanıcı GÖNDER düğmesini tıkladığında, aşağıdaki kod parçacığını tetikler. Mesaj giriş alanının içeriğini veritabanının guestbook koleksiyonuna ekler. Özellikle, addMessageToGuestBook yöntemi, mesaj içeriğini, guestbook koleksiyonunda otomatik olarak oluşturulmuş bir kimliğe sahip yeni bir belgeye ekler.

FirebaseAuth.instance.currentUser.uid öğesinin, Kimlik Doğrulamanın oturum açmış tüm kullanıcılar için verdiği, otomatik olarak oluşturulmuş benzersiz kimliğe bir referans olduğunu unutmayın.

  • lib/main.dart dosyasında addMessageToGuestBook yöntemini ekleyin. Bir sonraki adımda bu yeteneği kullanıcı arayüzüne bağlarsınız.

lib/main.dart

class ApplicationState extends ChangeNotifier {

  // Current content of ApplicationState elided ...

  // Add from here...
  Future<DocumentReference> addMessageToGuestBook(String message) {
    if (!_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.
}

Arayüzü ve veritabanını bağlayın

Kullanıcının Ziyaretçi Defterine eklemek istediği metni girebileceği bir kullanıcı arayüzünüz ve girişi Firestore'a eklemek için kodunuz var. Şimdi tek yapmanız gereken ikisini birbirine bağlamak.

  • lib/main.dart dosyasında, HomePage pencere öğesinde aşağıdaki değişikliği yapın:

lib/main.dart

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Firebase Meetup'),
      ),
      body: ListView(
        children: <Widget>[
          Image.asset('assets/codelab.png'),
          const SizedBox(height: 8),
          const IconAndDetail(Icons.calendar_today, 'October 30'),
          const IconAndDetail(Icons.location_city, 'San Francisco'),
          Consumer<ApplicationState>(
            builder: (context, appState, _) => AuthFunc(
                loggedIn: appState.loggedIn,
                signOut: () {
                  FirebaseAuth.instance.signOut();
                }),
          ),
          const Divider(
            height: 8,
            thickness: 1,
            indent: 8,
            endIndent: 8,
            color: Colors.grey,
          ),
          const Header("What we'll be doing"),
          const 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.loggedIn) ...[
                  const Header('Discussion'),
                  GuestBook(
                    addMessage: (message) =>
                        appState.addMessageToGuestBook(message),
                  ),
                ],
              ],
            ),
          ),
          // ...to here.
        ],
      ),
    );
  }
}

Bu adımın başında eklediğiniz iki satırı tam uygulama ile değiştirdiniz. Uygulama durumunu ağacın oluşturduğunuz bölümünde kullanılabilir hale getirmek için tekrar Consumer<ApplicationState> kullanırsınız. Bu, kullanıcı arayüzüne mesaj giren birine tepki vermenizi ve mesajı veritabanında yayınlamanızı sağlar. Bir sonraki bölümde, eklenen mesajların veritabanında yayınlanıp yayınlanmadığını test edersiniz.

Mesaj göndermeyi test et

  1. Gerekirse uygulamada oturum açın.
  2. Hey there! ve ardından GÖNDER öğesini tıklayın.

Bu eylem, mesajı Firestore veritabanınıza yazar. Ancak, bir sonraki adımda yapacağınız veri alma işlemini gerçekleştirmeniz gerektiğinden, mesajı gerçek Flutter uygulamanızda görmezsiniz. Ancak, Firebase konsolunun Veritabanı kontrol panelinde , eklenen mesajınızı guestbook koleksiyonunda görebilirsiniz. Daha fazla mesaj gönderirseniz, guestbook koleksiyonunuza daha fazla belge eklersiniz. Örneğin, aşağıdaki kod parçacığına bakın:

713870af0b3b63c.png

7. Mesajları oku

Konukların veri tabanına mesaj yazabilmeleri çok hoş ama henüz uygulamada göremiyorlar. Bunu düzeltme zamanı!

Mesajları senkronize et

Mesajları görüntülemek için, veriler değiştiğinde tetikleyen dinleyiciler eklemeniz ve ardından yeni mesajları gösteren bir UI öğesi oluşturmanız gerekir. Uygulamadan yeni eklenen mesajları dinleyen uygulama durumuna kod eklersiniz.

  1. Firestore'da depoladığınız verilerin yapılandırılmış bir görünümünü ortaya çıkarmak için GuestBook küçük aracından önceki lib/main.dart dosyasında aşağıdaki sınıfı ekleyin.

lib/main.dart

class GuestBookMessage {
  GuestBookMessage({required this.name, required this.message});
  final String name;
  final String message;
}
  1. State ve getters'ı tanımladığınız ApplicationState bölümünde aşağıdaki satırları ekleyin:

lib/main.dart

  bool _loggedIn = false;
  bool get loggedIn => _loggedIn;

  // Add from here...
  StreamSubscription<QuerySnapshot>? _guestBookSubscription;
  List<GuestBookMessage> _guestBookMessages = [];
  List<GuestBookMessage> get guestBookMessages => _guestBookMessages;
  // ...to here.
  1. ApplicationState başlatma bölümünde, bir kullanıcı oturum açtığında belge koleksiyonu üzerinden bir sorguya abone olmak ve oturumu kapattığında abonelikten çıkmak için aşağıdaki satırları ekleyin:

lib/main.dart

  Future<void> init() async {
    await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform);

    FirebaseUIAuth.configureProviders([
      EmailAuthProvider(),
    ]);
    
    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loggedIn = true;
        _guestBookSubscription = FirebaseFirestore.instance
            .collection('guestbook')
            .orderBy('timestamp', descending: true)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          for (final document in snapshot.docs) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'] as String,
                message: document.data()['text'] as String,
              ),
            );
          }
          notifyListeners();
        });
      } else {
        _loggedIn = false;
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
      }
      notifyListeners();
    });
  }

Bu bölüm, guestbook koleksiyonu üzerinde bir sorgu oluşturduğunuz ve bu koleksiyona abone olma ve abonelikten çıkma işlemlerini gerçekleştirdiğiniz yer olduğundan önemlidir. guestbook koleksiyonundaki mesajların yerel bir önbelleğini yeniden oluşturduğunuz ve ayrıca daha sonra abonelikten çıkabilmeniz için bu aboneliğe bir referans sakladığınız akışı dinlersiniz. Burada çok şey oluyor, bu yüzden daha net bir zihinsel model elde etmek için ne olduğunu incelemek için bir hata ayıklayıcıda keşfetmelisiniz. Daha fazla bilgi için bkz. Firestore ile gerçek zamanlı güncellemeler alın .

  1. GuestBook pencere öğesinde, bu değişen durumu kullanıcı arayüzüne bağlamak için yapılandırmanın bir parçası olarak bir mesaj listesi ekleyin:

lib/main.dart

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

  @override
  _GuestBookState createState() => _GuestBookState();
}
  1. _GuestBookState , bu yapılandırmayı ortaya çıkarmak için build yöntemini aşağıdaki gibi değiştirin:

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;
                    },
                  ),
                ),
                const SizedBox(width: 8),
                StyledButton(
                  onPressed: () async {
                    if (_formKey.currentState!.validate()) {
                      await widget.addMessage(_controller.text);
                      _controller.clear();
                    }
                  },
                  child: Row(
                    children: const [
                      Icon(Icons.send),
                      SizedBox(width: 4),
                      Text('SEND'),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
        // Modify from here...
        const SizedBox(height: 8),
        for (var message in widget.messages)
          Paragraph('${message.name}: ${message.message}'),
        const SizedBox(height: 8),
      ],
      // ...to here.
    );
  }
}

build() yönteminin önceki içeriğini bir Column parçacığıyla sararsınız ve ardından Column alt öğelerinin kuyruğuna bir koleksiyon ekleyerek iletiler listesindeki her ileti için yeni bir Paragraph oluşturursunuz.

  1. Yeni messages parametresiyle GuestBook HomePage bir şekilde oluşturmak için Ana Sayfanın gövdesini güncelleyin:

lib/main.dart

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

Test mesajı senkronizasyonu

Firestore, verileri veritabanına abone olan istemcilerle otomatik olarak ve anında senkronize eder.

Mesaj senkronizasyonunu test edin:

  1. Uygulamada, daha önce veritabanında oluşturduğunuz mesajları bulun.
  2. Yeni mesajlar yaz. Anında görünürler.
  3. Çalışma alanınızı birden çok pencerede veya sekmede açın. Mesajlar, pencereler ve sekmeler arasında gerçek zamanlı olarak senkronize edilir.
  4. İsteğe bağlı: Firebase konsolunun Veritabanı menüsünde, mesajları manuel olarak silin, değiştirin veya yeni mesajlar ekleyin. Tüm değişiklikler kullanıcı arayüzünde görünür.

Tebrikler! Uygulamanızda Firestore belgelerini okursunuz!

Uygulama önizlemesi

8. Temel güvenlik kurallarını ayarlayın

Firestore'u başlangıçta test modunu kullanacak şekilde ayarlarsınız; bu, veritabanınızın okuma ve yazma işlemlerine açık olduğu anlamına gelir. Ancak, test modunu yalnızca geliştirmenin ilk aşamalarında kullanmalısınız. En iyi uygulama olarak, uygulamanızı geliştirirken veritabanınız için güvenlik kuralları oluşturmalısınız. Güvenlik, uygulamanızın yapısının ve davranışının ayrılmaz bir parçasıdır.

Firebase Güvenlik Kuralları, veritabanınızdaki belgelere ve koleksiyonlara erişimi kontrol etmenizi sağlar. Esnek kural sözdizimi, veritabanının tamamına yapılan tüm yazma işlemlerinden belirli bir belge üzerindeki işlemlere kadar her şeyle eşleşen kurallar oluşturmanıza olanak tanır.

Temel güvenlik kurallarını ayarlayın:

  1. Firebase konsolunun Geliştirme menüsünde Veritabanı > Kurallar'ı tıklayın. Aşağıdaki varsayılan güvenlik kurallarını ve kuralların herkese açık olduğuna dair bir uyarı görmelisiniz:

7767a2d2e64e7275.png

  1. Uygulamanın veri yazdığı koleksiyonları tanımlayın:

match /databases/{database}/documents , güvenliğini sağlamak istediğiniz koleksiyonu tanımlayın:

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

Kimlik Doğrulama UID'sini her konuk defteri belgesinde bir alan olarak kullandığınız için, Kimlik Doğrulama UID'sini alabilir ve belgeye yazmaya çalışan herkesin eşleşen bir Kimlik Doğrulama UID'si olduğunu doğrulayabilirsiniz.

  1. Okuma ve yazma kurallarını kural kümenize ekleyin:
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;
    }
  }
}

Artık yalnızca oturum açmış kullanıcılar konuk defterindeki iletileri okuyabilir, ancak yalnızca iletinin yazarı bir iletiyi düzenleyebilir.

  1. Beklenen tüm alanların belgede bulunduğundan emin olmak için veri doğrulama ekleyin:
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;
    }
  }
}

9. Bonus adım: Öğrendiklerinizi uygulayın

Bir katılımcının LCV durumunu kaydetme

Şu anda, uygulamanız kullanıcıların yalnızca etkinlikle ilgilendiklerinde sohbet etmesine izin veriyor. Ayrıca, birinin gelip gelmediğini öğrenmenin tek yolu, sohbette bunu söylemesidir.

Bu adımda organize olursunuz ve insanların kaç kişinin geldiğini bilmesini sağlarsınız. Uygulama durumuna birkaç yetenek eklersiniz. İlki, oturum açmış bir kullanıcının katılıp katılmadıklarını belirleme yeteneğidir. İkincisi, kaç kişinin katıldığını gösteren bir sayaçtır.

  1. lib/main.dart dosyasında, UI kodunun bu durumla etkileşime girebilmesi için erişimciler bölümüne aşağıdaki satırları ekleyin:

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(<String, dynamic>{'attending': true});
  } else {
    userDoc.set(<String, dynamic>{'attending': false});
  }
}
  1. ApplicationState init() yöntemini aşağıdaki gibi güncelleyin:

lib/main.dart

  Future<void> init() async {
    await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform);

    FirebaseUIAuth.configureProviders([
      EmailAuthProvider(),
    ]);

    // 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 = [];
          for (final document in snapshot.docs) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'] as String,
                message: document.data()['text'] as String,
              ),
            );
          }
          notifyListeners();
        });
        // Add from here...
        _attendingSubscription = FirebaseFirestore.instance
            .collection('attendees')
            .doc(user.uid)
            .snapshots()
            .listen((snapshot) {
          if (snapshot.data() != null) {
            if (snapshot.data()!['attending'] as bool) {
              _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();
    });
  }

Bu kod, katılımcı sayısını belirlemek için her zaman abone olunan bir sorgu ve kullanıcının katılıp katılmadığını belirlemek için yalnızca bir kullanıcı oturum açtığında etkin olan ikinci bir sorgu ekler.

  1. GuestBookMessage bildiriminden sonra aşağıdaki numaralandırmayı ekleyin:

lib/main.dart

enum Attending { yes, no, unknown }
  1. Eski radyo düğmeleri gibi davranan yeni bir pencere öğesi tanımlayın:

lib/main.dart

class YesNoSelection extends StatelessWidget {
  const YesNoSelection(
      {super.key, 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: const EdgeInsets.all(8.0),
          child: Row(
            children: [
              ElevatedButton(
                style: ElevatedButton.styleFrom(elevation: 0),
                onPressed: () => onSelection(Attending.yes),
                child: const Text('YES'),
              ),
              const SizedBox(width: 8),
              TextButton(
                onPressed: () => onSelection(Attending.no),
                child: const Text('NO'),
              ),
            ],
          ),
        );
      case Attending.no:
        return Padding(
          padding: const EdgeInsets.all(8.0),
          child: Row(
            children: [
              TextButton(
                onPressed: () => onSelection(Attending.yes),
                child: const Text('YES'),
              ),
              const SizedBox(width: 8),
              ElevatedButton(
                style: ElevatedButton.styleFrom(elevation: 0),
                onPressed: () => onSelection(Attending.no),
                child: const Text('NO'),
              ),
            ],
          ),
        );
      default:
        return Padding(
          padding: const EdgeInsets.all(8.0),
          child: Row(
            children: [
              StyledButton(
                onPressed: () => onSelection(Attending.yes),
                child: const Text('YES'),
              ),
              const SizedBox(width: 8),
              StyledButton(
                onPressed: () => onSelection(Attending.no),
                child: const Text('NO'),
              ),
            ],
          ),
        );
    }
  }
}

Ne Evet ne de Hayır seçilmeden belirsiz bir durumda başlar. Kullanıcı katılıp katılmayacağını seçtiğinde, bu seçeneği dolu bir düğmeyle vurgulanmış olarak gösterirsiniz ve diğer seçenek düz bir işleme ile geri çekilir.

  1. YesNoSelection yararlanmak için HomePage build() yöntemini güncelleyin, oturum açmış bir kullanıcının katılıp katılmadıklarını belirlemesini sağlayın ve etkinliğe katılanların sayısını görüntüleyin:

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)
        const Paragraph('1 person going')
      else
        const Paragraph('No one going'),
      // ...to here.
      if (appState.loggedIn) ...[
        // Add from here...
        YesNoSelection(
          state: appState.attending,
          onSelection: (attending) => appState.attending = attending,
        ),
        // ...to here.
        const Header('Discussion'),
        GuestBook(
          addMessage: (message) =>
              appState.addMessageToGuestBook(message),
          messages: appState.guestBookMessages,
        ),
      ],
    ],
  ),
),

Kural ekle

Zaten bazı kurallar belirlediniz, bu nedenle düğmelerle eklediğiniz veriler reddedilecek. attendees koleksiyonuna eklemelere izin vermek için kuralları güncellemeniz gerekir.

  1. attendees koleksiyonunda, belge adı olarak kullandığınız Kimlik Doğrulama uid alın ve gönderenin kullanıcı kimliğinin yazdıkları belgeyle aynı olduğunu doğrulayın:
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId;
    }
  }
}

Bu, herkesin katılımcı listesini okumasına olanak tanır çünkü burada özel veri yoktur, ancak yalnızca oluşturan kişi güncelleyebilir.

  1. Beklenen tüm alanların belgede bulunduğundan emin olmak için veri doğrulama ekleyin:
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;

    }
  }
}
  1. İsteğe bağlı: Uygulamada, sonuçları Firebase konsolundaki Firestore kontrol panelinde görmek için düğmeleri tıklayın.

Uygulama önizlemesi

10. Tebrikler!

Etkileşimli, gerçek zamanlı bir web uygulaması oluşturmak için Firebase'i kullandınız!

Daha fazla bilgi edin