Flutter için Firebase'i tanıyın

1. Başlamadan önce

Bu codelab'de, Android ve iOS için Flutter mobil uygulamaları oluştururken Firebase ile ilgili bazı temel bilgileri öğreneceksiniz.

Ön koşullar

Neler öğreneceksiniz?

  • Flutter ile Android, iOS, web ve macOS'te etkinlik LCV'si ve konuk defteri sohbet uygulaması oluşturma.
  • Firebase Authentication ile kullanıcıların kimliğini doğrulama ve verileri Firestore ile senkronize etme

Android'de uygulamanın ana ekranı

iOS'te uygulamanın ana ekranı

Gerekenler

Aşağıdaki cihazlardan herhangi biri:

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

Şunlara da ihtiyacınız vardır:

  • Tercih ettiğiniz bir tarayıcı (ör. Google Chrome).
  • Android Studio veya Visual Studio Code gibi Dart ve Flutter eklentileriyle yapılandırılmış, tercih ettiğiniz bir IDE veya metin düzenleyici.
  • Flutter'ın veya uçta yaşamayı seviyorsanız beta'in en yeni stable sürümü.
  • Firebase projenizin oluşturulması ve yönetilmesi için kullanılacak bir Google Hesabı.
  • Firebase KSA, Google Hesabınıza giriş yaptı.

2. Örnek kodu alın

GitHub'dan projenizin ilk sürümünü 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, codelab'leri içeren bir koleksiyon kodunu içerir. Bu codelab'in kodu flutter-codelabs/firebase-get-to-know-flutter dizinindedir. Dizin, her adımın sonunda projenizin nasıl görünmesi gerektiğini gösteren bir dizi anlık görüntüyü 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 gitmek veya bir adımdan sonra bir şeyin nasıl görünmesi gerektiğini görmek isterseniz, 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 tercih ettiğiniz IDE'de 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 fazla dizine yayılmış. Bu işlevsellik dağılımı, kodu işlevselliğe göre gruplandırdığı için işi kolaylaştırır.

  • Şu dosyaları bulun:
    • lib/main.dart: Bu dosya ana giriş noktasını ve uygulama widget'ını içerir.
    • lib/home_page.dart: Bu dosya ana sayfa widget'ını içerir.
    • lib/src/widgets.dart: Bu dosya, uygulamanın stilini standartlaştırmaya yardımcı olacak çeşitli widget'lar 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 giriş kullanıcı deneyimi oluşturmak amacıyla bir dizi widget ile birlikte kısmi bir Kimlik Doğrulama uygulaması içerir. Kimlik doğrulama akışı için bu widget'lar henüz başlangıç uygulamasında kullanılmıyor, ancak yakında eklenecek.

Uygulamanın geri kalanını derlemek 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 adresini ziyaret edebilir ve keşfettiğiniz yazı tiplerini uygulamanın farklı bölümlerinde kullanabilirsiniz.

lib/src/widgets.dart dosyasındaki yardımcı widget'ları Header, Paragraph ve IconAndDetail biçiminde kullanırsınız. Bu widget'lar, HomePage bölümünde açıklanan sayfa düzenindeki karmaşıklığı azaltmak için yinelenen kodları ortadan kaldırır. Bu aynı zamanda tutarlı bir görünüm ve tarz sağlar.

Uygulamanız Android, iOS, web ve macOS'te şu şekilde görünür:

Android'de uygulamanın ana ekranı

iOS'te uygulamanın ana ekranı

Uygulamanın web'deki ana ekranı

Uygulamanın macOS'teki ana ekranı

3. Firebase projesi oluşturma ve yapılandırma

Etkinlik bilgilerinin görüntülenmesi konuklarınız için çok güzel olabilir ancak tek başına kimse için çok faydalı olmaz. Uygulamaya dinamik işlevler eklemeniz gerekiyor. Bunun için Firebase'i uygulamanıza bağlamanız gerekir. Firebase'i kullanmaya başlamak için bir Firebase projesi oluşturup yapılandırmanız gerekir.

Firebase projesi oluşturma

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

4395e4e67c08043a.png

  1. Proje oluşturma seçeneklerini tıklayarak ilerleyin. İstenirse Firebase şartlarını kabul edin ancak Google Analytics'i bu uygulamada kullanamayacağınız için Google Analytics kurulumunu atlayın.

b7138cde5f2c7b61.png

Firebase projeleri hakkında daha fazla bilgi için Firebase projelerini anlama başlıklı makaleyi inceleyin.

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

  • Kimlik doğrulama: Kullanıcıların uygulamanızda oturum açmasına olanak tanır.
  • Firestore: Yapılandırılmış verileri buluta kaydeder ve veriler değiştiğinde anlık bildirimler alır.
  • Firebase Security Rules: Veritabanınızın güvenliğini sağlar.

Bu ürünlerden bazıları için özel yapılandırma gerekir veya bunları Firebase konsolunda etkinleştirmeniz gerekir.

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

  1. Firebase konsolunun Projeye genel bakış bölmesinde Derleme menüsünü genişletin.
  2. Kimlik Doğrulama > Başlayın > Oturum açma yöntemi > E-posta/Şifre > Etkinleştir > Kaydet'i seçin.

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:

  • Build (Derleme) menüsünde, Firestore Database > Veritabanı oluşturun.

99e8429832d23fa3.png

  1. Test modunda başlat'ı seçin ve güvenlik kurallarıyla ilgili sorumluluk reddi beyanını okuyun. Test modu, geliştirme sırasında veritabanına serbestçe yazabilmenizi sağlar.

6be00e26c72ea032.png

  1. Next'i (İleri) tıklayın ve ardından veritabanınızın konumunu seçin. Varsayılan değeri 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 kullanmak için aşağıdaki görevleri tamamlayarak Flutter projesini, FlutterFire kitaplıklarını doğru kullanacak şekilde yapılandırmanız gerekir:

  1. FlutterFire bağımlılıklarını projenize ekleyin.
  2. İstediğiniz platformu Firebase projesine kaydedin.
  3. Platforma özel yapılandırma dosyasını indirip 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ı barındıran 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, Authentication ile entegrasyonu sağlar.

$ flutter pub add cloud_firestore

cloud_firestore paketi, Firestore veri depolama alanına erişim sağlar.

$ flutter pub add provider

firebase_ui_auth paketi, kimlik doğrulama akışlarıyla geliştiricinin hızını artırmak için bir dizi widget ve yardımcı program sunar.

$ flutter pub add firebase_ui_auth

Gerekli paketleri eklediniz. Ancak Firebase'i uygun şekilde kullanmak için iOS, Android, macOS ve Web çalıştırıcı projelerini de yapılandırmanız gerekir. Ayrıca, iş mantığının görüntüleme mantığından ayrılmasına olanak tanıyan provider paketini de kullanırsınız.

FlutterFire CLI'ı yükleme

FlutterFire KSA, temel Firebase CLI'ya bağlıdır.

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

flutterfire komutu yüklendiğinde genel olarak kullanılabilir.

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

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

Uygulamanızın kök dizininde configure komutunu çalıştırın:

$ flutterfire configure

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

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

macOS'i yapılandırın

macOS'te Flutter, tamamen korumalı alana alınmış uygulamalar oluşturur. Bu uygulama Firebase sunucularıyla iletişim kurmak için ağla 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 edinmek için Flutter için masaüstü desteği başlıklı makaleye bakın.

5. LCV işlevi ekleme

Firebase'i uygulamaya eklediğinize göre artık Kimlik Doğrulama özelliğine sahip kullanıcıları kaydetmek için bir LCV düğmesi oluşturabilirsiniz. Android yerel, iOS yerel ve web için önceden oluşturulmuş FirebaseUI Auth paketleri mevcuttur ancak bu özelliği Flutter için oluşturmanız gerekir.

Daha önce aldığınız proje, kimlik doğrulama akışının büyük bir kısmı için kullanıcı arayüzünü uygulayan bir dizi widget içeriyordu. Authentication'ı uygulamaya entegre etmek için iş mantığını uygularsınız.

Provider paketiyle iş mantığı ekleyin

Uygulamanın Flutter widget'ları ağacında merkezi bir uygulama durumu nesnesini kullanılabilir hale getirmek için provider paketini kullanın:

  1. Aşağıdaki içeriğe sahip app_state.dart adlı yeni bir dosya oluşturun:

lib/app_state.dart

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

import 'firebase_options.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();
    });
  }
}

import ifadeleri, Firebase Core ve Auth'u tanıtır, widget ağacında uygulama durumu nesnesini kullanılabilir hale getiren provider paketini alır ve firebase_ui_auth paketindeki kimlik doğrulama widget'larını içerir.

Bu ApplicationState uygulama durumu nesnesinin bu adımda temel sorumluluğu vardır. Bu işlem, widget ağacını kimliği doğrulanmış duruma güncelleme olduğunu bildirmektir.

Sağlayıcıları yalnızca kullanıcının giriş durumunun durumunu uygulamaya iletmek için kullanırsınız. Bir kullanıcının giriş yapmasına izin vermek için firebase_ui_auth paketi tarafından sağlanan kullanıcı arayüzlerini kullanırsınız. Bu, uygulamalarınızdaki giriş ekranlarını hızlı bir şekilde önyüklemenin harika bir yoludur.

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

  1. lib/main.dart dosyasının en üstünde, içe aktarma işlemlerini değiştirin:

lib/main.dart

import 'package:firebase_ui_auth/firebase_ui_auth.dart'; // new
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';               // new
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';                 // new

import 'app_state.dart';                                 // new
import 'home_page.dart';
  1. Uygulama durumunu uygulama başlatmaya bağlayın, ardından kimlik doğrulama akışını HomePage hizmetine 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 widget'ı ile uygulama durumu nesnesinin örneklendirmesinden sorumlu hale getirir. Bu özel provider sınıfını, uygulama durumu nesnesi ChangeNotifier sınıfını genişlettiği için kullanıyorsunuz. Bu sayede provider paketi, bağımlı widget'ların ne zaman yeniden gösterileceğini bilir.

  1. Bir GoRouter yapılandırması oluşturarak uygulamanızı FirebaseUI'nin size sağladığı farklı ekranlarda gezinmeyi işleyecek şekilde güncelleyin:

lib/main.dart

// Add GoRouter configuration outside the App class
final _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomePage(),
      routes: [
        GoRoute(
          path: 'sign-in',
          builder: (context, state) {
            return SignInScreen(
              actions: [
                ForgotPasswordAction(((context, email) {
                  final uri = Uri(
                    path: '/sign-in/forgot-password',
                    queryParameters: <String, String?>{
                      'email': email,
                    },
                  );
                  context.push(uri.toString());
                })),
                AuthStateChangeAction(((context, state) {
                  final user = switch (state) {
                    SignedIn state => state.user,
                    UserCreated state => state.credential.user,
                    _ => null
                  };
                  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);
                  }
                  context.pushReplacement('/');
                })),
              ],
            );
          },
          routes: [
            GoRoute(
              path: 'forgot-password',
              builder: (context, state) {
                final arguments = state.uri.queryParameters;
                return ForgotPasswordScreen(
                  email: arguments['email'],
                  headerMaxExtent: 200,
                );
              },
            ),
          ],
        ),
        GoRoute(
          path: 'profile',
          builder: (context, state) {
            return ProfileScreen(
              providers: const [],
              actions: [
                SignedOutAction((context) {
                  context.pushReplacement('/');
                }),
              ],
            );
          },
        ),
      ],
    ),
  ],
);
// end of GoRouter configuration

// Change MaterialApp to MaterialApp.router and add the routerConfig
class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      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,
        useMaterial3: true,
      ),
      routerConfig: _router, // new
    );
  }
}

Her ekranın, kimlik doğrulama akışının yeni durumuna bağlı olarak farklı bir işlem türü vardır. Kimlik doğrulamadaki çoğu durum değişikliğinden sonra, tercih ettiğiniz bir ekrana (ana ekran veya profil gibi farklı bir ekran) yeniden yönlendirme yapabilirsiniz.

  1. HomePage sınıfının derleme yönteminde, uygulama durumunu AuthFunc widget'ıyla entegre edin:

lib/home_page.dart

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

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

class HomePage extends StatelessWidget {
  const HomePage({super.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'),
          // 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 widget'ını örneklendirdiniz ve bir Consumer widget'ı içinde sarmaladınız. Tüketici widget'ı, uygulama durumu değiştiğinde provider paketinin genel olarak ağacın bir bölümünü yeniden oluşturmak için kullanılmasıdır. AuthFunc widget'ı, test ettiğiniz tamamlayıcı widget'lardır.

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

cdf2d25e436bd48d.png

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

2a2cd6d69d172369.png

  1. Bir e-posta 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 şifre girin. Kayıtlıysanız bunun yerine şifresini görürsünüz.
  2. Hata işleme akışını kontrol etmek için yanlış şifreler girin.
  3. Doğru şifreyi girin. Kullanıcıya çıkış seçeneği sunan giriş yapma deneyimini görürsünüz.

4ed811a25b0cf816.png

6. Firestore'a mesaj yazma

Kullanıcıların geldiğini bilmek güzel, ancak misafirlere uygulamada yapabilecekleri başka bir şey sunmanız gerekiyor. İletilerini konuk defterine bırakabilselerdi ne olurdu? Katılmak için neden heyecan duyduklarını veya kimlerle tanışmak istediklerini paylaşabilirler.

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

Veri modeli

Firestore bir NoSQL veritabanıdır ve veritabanında depolanan veriler koleksiyonlara, belgelere, alanlara ve alt koleksiyonlara bölünür. Sohbetteki her mesaj, üst düzey bir koleksiyon olan guestbook koleksiyonunda bir doküman olarak depolanır.

7c20dc8424bb1d84.png

Firestore'a mesaj ekleme

Bu bölümde, kullanıcıların veritabanına ileti yazması için işlev ekleyeceksiniz. Önce bir form alanı ve gönder düğmesi, ardından bu öğeleri veritabanına bağlayan kodu eklersiniz.

  1. guest_book.dart adında yeni bir dosya oluşturun, bir mesaj alanının ve gönder düğmesinin kullanıcı arayüzü öğelerini oluşturmak için GuestBook durum bilgili widget'ı ekleyin:

lib/guest_book.dart

import 'dart:async';

import 'package:flutter/material.dart';

import 'src/widgets.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ç önemli yer var. İlk olarak, iletinin gerçekten içerik barındırdığını doğrulayabilmeniz için bir form somut hale getirirsiniz ve hiç içerik yoksa kullanıcıya bir hata mesajı gösterilir. Bir formu doğrulamak için formun arkasındaki form durumuna GlobalKey ile erişirsiniz. Anahtarlar ve bunların nasıl kullanılacağı hakkında daha fazla bilgi için Tuşların Kullanılacağı Zaman bölümüne bakın.

Widget'ların düzenlenme şekliyle ilgili olarak TextFormField içeren bir Row ve Row içeren StyledButton bulunduğunu da unutmayın. Ayrıca TextFormField öğesinin, TextFormField öğesini satırdaki fazladan boşluğu doldurmaya zorlayan bir Expanded widget'ına sarmalandığına dikkat edin. Bunun neden gerekli olduğunu daha iyi anlamak için Kısıtlamaları anlama bölümüne bakın.

Kullanıcının Konuk Defteri'ne eklemek üzere metin girmesini sağlayan bir widget'ınız olduğuna göre şimdi onu ekrana getirmeniz gerekir.

  1. HomePage öğesinin gövdesini düzenleyerek aşağıdaki iki satırı ListView öğesinin alt öğelerinin sonuna ekleyin:
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'ın görüntülenmesi için yeterli olsa da faydalı bir şey yapmak yeterli değildir. Çalışması için bu kodu kısa süre içinde güncellersiniz.

Uygulama önizlemesi

Sohbet entegrasyonuna sahip Android&#39;de uygulamanın ana ekranı

Sohbet entegrasyonuna sahip iOS&#39;te uygulamanın ana ekranı

Sohbet entegrasyonuna sahip uygulamanın web sürümünde ana ekran

Sohbet entegrasyonuna sahip macOS&#39;te uygulamanın ana ekranı

Kullanıcı GÖNDER'i tıkladığında aşağıdaki kod snippet'i tetiklenir. Mesaj giriş alanının içeriğini, veritabanının guestbook koleksiyonuna ekler. Özellikle, addMessageToGuestBook yöntemi, ileti içeriğini guestbook koleksiyonunda otomatik olarak oluşturulmuş bir kimliğe sahip yeni bir dokümana ekler.

FirebaseAuth.instance.currentUser.uid değerinin, Kimlik Doğrulaması'nın giriş yapmış tüm kullanıcılar için verdiği otomatik olarak oluşturulmuş benzersiz kimliğe bir referans olduğunu unutmayın.

  • lib/app_state.dart dosyasına addMessageToGuestBook yöntemini ekleyin. Bu özelliği bir sonraki adımda kullanıcı arayüzüne bağlayacaksınız.

lib/app_state.dart

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

import 'firebase_options.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.
}

Kullanıcı arayüzü ve veritabanı bağlayın

Kullanıcının Ziyaretçi Defteri'ne eklemek istediği metni girebileceği bir kullanıcı arayüzünüz vardır ve girişi Firestore'a eklemek için gereken koda sahipsiniz. Şimdi yapmanız gereken tek şey ikisini birbirine bağlamak.

  • lib/home_page.dart dosyasında HomePage widget'ında aşağıdaki değişikliği yapın:

lib/home_page.dart

import 'package:firebase_auth/firebase_auth.dart'
    hide EmailAuthProvider, PhoneAuthProvider;
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'app_state.dart';
import 'guest_book.dart';                         // new
import 'src/authentication.dart';
import 'src/widgets.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 uygulamayla değiştirdiniz. Ağacın oluşturduğunuz kısmı için uygulama durumunu kullanılabilir hale getirmek için yine Consumer<ApplicationState> yöntemini kullanırsınız. Bu sayede, kullanıcı arayüzüne bir mesaj giren birine tepki verebilir ve bu mesajı veritabanında yayınlayabilirsiniz. Sonraki bölümde, eklenen iletilerin veritabanında yayınlanıp yayınlanmadığını test edeceksiniz.

Mesaj göndermeyi test etme

  1. Gerekirse uygulamada oturum açın.
  2. Hey there! gibi bir mesaj girin ve GÖNDER'i tıklayın.

Bu işlem, mesajı Firestore veritabanınıza yazar. Ancak veri alımını da bir sonraki adımda uygulamanız gerektiğinden mesajı gerçek Flutter uygulamanızda görmezsiniz. Ancak Firebase konsolunun Veritabanı kontrol panelinde, eklediğiniz mesajı guestbook koleksiyonunda görebilirsiniz. Daha fazla ileti gönderirseniz guestbook koleksiyonunuza daha çok doküman eklersiniz. Örneğin, aşağıdaki kod snippet'ine bakın:

713870af0b3b63c.png

7. Mesajları okuma

Misafirlerin veritabanına mesaj yazabilmeleri çok güzel ancak bu mesajları henüz uygulamada göremiyorlar. Bu sorunu düzeltmenin zamanı geldi.

İletileri senkronize etme

Mesajları görüntülemek için veriler değiştiğinde tetiklenen işleyiciler eklemeniz ve ardından yeni mesajları gösteren bir kullanıcı arayüzü öğesi oluşturmanız gerekir. Uygulamadan gelen yeni eklenen mesajları dinleyen uygulama durumuna kod eklersiniz.

  1. Yeni bir dosya (guest_book_message.dart) oluşturun. Firestore'da depoladığınız verilerin yapılandırılmış görünümünü ortaya çıkarmak için aşağıdaki sınıfı ekleyin.

lib/guest_book_message.dart

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

  final String name;
  final String message;
}
  1. lib/app_state.dart dosyasına aşağıdaki içe aktarma işlemlerini ekleyin:

lib/app_state.dart

import 'dart:async';                                     // new

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart'
    hide EmailAuthProvider, PhoneAuthProvider;
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

import 'firebase_options.dart';
import 'guest_book_message.dart';                        // new
  1. ApplicationState içinde eyalet ve alıcıları tanımladığınız bölümüne şu satırları ekleyin:

lib/app_state.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. Bir kullanıcı giriş yaptığında doküman koleksiyonu üzerinden bir sorguya abone olmak ve çıkış yaptığında abonelikten çıkmak için ApplicationState ürününün başlatma bölümünde aşağıdaki satırları ekleyin:

lib/app_state.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 sorgu oluşturduğunuz ve bu koleksiyona abone olma ve abonelikten çıkma işlemlerini gerçekleştirdiğiniz yerdir. Akışı dinlersiniz. Burada guestbook koleksiyonundaki iletilerin yerel bir önbelleğini yeniden oluşturur ve daha sonra aboneliği iptal etmek için aboneliğin referans kaydını saklarsınız. Burada çok çeşitli işlemler yapıldığı için daha net bir zihinsel model elde etmek amacıyla neler olduğunu araştırmak üzere hata ayıklayıcıda incelemeniz gerekir. Daha fazla bilgi için Firestore ile gerçek zamanlı güncellemeler alma başlıklı makaleyi inceleyin.

  1. lib/guest_book.dart dosyasına aşağıdaki içe aktarmayı ekleyin:
import 'guest_book_message.dart';
  1. Bu değişen durumu kullanıcı arayüzüne bağlamak için GuestBook widget'ına yapılandırmanın parçası olarak bir mesaj listesi ekleyin:

lib/guest_book.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. Bu yapılandırmayı kullanıma sunmak için _GuestBookState ürününde build yöntemini aşağıdaki gibi değiştirin:

lib/guest_book.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 Column widget'ı ile sarmalarsınız ve ardından ileti listesindeki her ileti için yeni bir Paragraph oluşturmak üzere Column öğesinin alt öğelerinin kuyruğuna bir koleksiyon eklersiniz.

  1. GuestBook öğesini yeni messages parametresiyle doğru şekilde oluşturmak için HomePage öğesinin gövdesini güncelleyin:

lib/home_page.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
        ),
      ],
    ],
  ),
),

Mesaj senkronizasyonunu test edin

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

Mesaj senkronizasyonunu test edin:

  1. Uygulamada, veritabanında daha önce oluşturduğunuz mesajları bulun.
  2. Yeni mesajlar yazabilirsiniz. Anında görünürler.
  3. Çalışma alanınızı birden fazla pencere 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 okuyorsunuz.

Uygulama önizlemesi

Sohbet entegrasyonuna sahip Android&#39;de uygulamanın ana ekranı

Sohbet entegrasyonuna sahip iOS&#39;te uygulamanın ana ekranı

Sohbet entegrasyonuna sahip uygulamanın web sürümünde ana ekran

Sohbet entegrasyonuna sahip macOS&#39;te uygulamanın ana ekranı

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

Başlangıçta Firestore'u test modunu kullanacak şekilde ayarlarsınız. Bu, veritabanınızın okuma ve yazma işlemleri için 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şturmanız gerekir. Güvenlik, uygulamanızın yapısı ve davranışının ayrılmaz bir parçasıdır.

Firebase Güvenlik Kuralları, veritabanınızdaki belge ve koleksiyonlara erişimi kontrol etmenize olanak tanır. Esnek kurallar söz dizimi, veritabanının tamamına yazma işlemlerinden belirli bir dokümandaki 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ştir menüsünde Veritabanı > Kurallar. Aşağıdaki varsayılan güvenlik kurallarını ve herkese açık kurallarla ilgili bir uyarı görürsünüz:

7767a2d2e64e7275.png

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

match /databases/{database}/documents ürününde, güvenliğini sağlamak istediğiniz koleksiyonu belirleyin:

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

Her konuk defteri dokümanında alan olarak Kimlik Doğrulama UID'sini kullandığınızdan, Kimlik Doğrulama UID'sini alabilir ve dokümana yazmaya çalışan herkesin eşleşen bir Kimlik Doğrulama UID'si olduğunu doğrulayabilirsiniz.

  1. Okuma ve yazma kurallarını kural grubunuza 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;
    }
  }
}

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

  1. Beklenen tüm alanların dokümanda olduğundan emin olmak için veri doğrulaması 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

Katılımcının LCV durumunu kaydetme

Uygulamanız şu anda kullanıcıların yalnızca etkinlikle ilgilendikleri anda sohbet etmesine olanak tanıyor. Ayrıca, bir kullanıcının sohbete gelip gelmediğini anlamanın tek yolu, söz konusu kullanıcının sohbette söylediği zamandır.

Bu adımda organize olur ve kullanıcılara kaç kişinin geldiğini bildirirsiniz. Uygulama durumuna birkaç özellik eklersiniz. İlki, giriş yapmış bir kullanıcının katılıp katılmayacağını belirlemesidir. İkincisi ise kaç kişinin katılacağına ilişkin bir sayaçtır.

  1. Kullanıcı arayüzü kodunun bu durumla etkileşim kurabilmesi için lib/app_state.dart dosyasında ApplicationState öğesinin erişimciler bölümüne aşağıdaki satırları ekleyin:

lib/app_state.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 öğesinin init() yöntemini aşağıdaki şekilde güncelleyin:

lib/app_state.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) {
        _loggedIn = true;
        _emailVerified = user.emailVerified;
        _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 {
        _loggedIn = false;
        _emailVerified = false;
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
        _attendingSubscription?.cancel(); // new
      }
      notifyListeners();
    });
  }

Bu kod, katılımcı sayısını belirlemek için her zaman abone olan bir sorgu ve kullanıcının katılıp katılmadığını belirlemek için yalnızca kullanıcı giriş yapmış durumdayken etkin olan ikinci bir sorgu ekler.

  1. lib/app_state.dart dosyasının en üstüne aşağıdaki numaralandırmayı ekleyin.

lib/app_state.dart

enum Attending { yes, no, unknown }
  1. Yeni bir dosya (yes_no_selection.dart) oluşturun, radyo düğmeleri gibi çalışan yeni bir widget tanımlayın:

lib/yes_no_selection.dart

import 'package:flutter/material.dart';

import 'app_state.dart';
import 'src/widgets.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: [
              FilledButton(
                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),
              FilledButton(
                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'),
              ),
            ],
          ),
        );
    }
  }
}

Parametre, Evet veya Hayır seçilmeden, belirsiz bir durumda başlar. Kullanıcı katılıp katılmayacağını seçtikten sonra bu seçenek doldurulmuş bir düğmeyle vurgulanmış olarak gösterilir ve diğer seçenek düz oluşturma işlemiyle birlikte kaybolur.

  1. YesNoSelection özelliğinden yararlanmak için HomePage adlı kullanıcının build() yöntemini güncelleyin, giriş yapmış bir kullanıcının katılıp katılmayacağını belirlemesini etkinleştirin ve etkinlikteki katılımcı sayısını görüntüleyin:

lib/home_page.dart

Consumer<ApplicationState>(
  builder: (context, appState, _) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      // Add from here...
      switch (appState.attendees) {
        1 => const Paragraph('1 person going'),
        >= 2 => Paragraph('${appState.attendees} people going'),
        _ => 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 ekleyin

Zaten bazı kurallar oluşturduğunuz için düğmelerle eklediğiniz veriler reddedilecek. attendees koleksiyonuna eklemelere izin vermek için kuralları güncellemeniz gerekiyor.

  1. attendees koleksiyonunda, doküman adı olarak kullandığınız Kimlik Doğrulama UID'sini alın ve gönderene ait uid bilgisinin, yazdığı dokümanla 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 sayede, gizli veri olmadığından herkes katılımcı listesini okuyabilir, ancak listeyi yalnızca içerik üretici güncelleyebilir.

  1. Beklenen tüm alanların dokümanda olduğundan emin olmak için veri doğrulaması 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

Android&#39;de uygulamanın ana ekranı

iOS&#39;te uygulamanın ana ekranı

Uygulamanın web&#39;deki ana ekranı

Uygulamanın macOS&#39;teki ana ekranı

10. Tebrikler!

Etkileşimli ve gerçek zamanlı bir web uygulaması geliştirmek için Firebase'i kullandınız.

Daha fazla bilgi