Flutter के लिए Firebase के बारे में जानें

1. शुरू करने से पहले

इस कोडलैब में, आपको Android और iOS के लिए Flutter मोबाइल ऐप्लिकेशन बनाने के लिए Firebase की बुनियादी बातें पता चलेंगी.

ज़रूरी शर्तें

आपको यह जानकारी मिलेगी

  • Flutter की मदद से Android, iOS, वेब, और macOS पर इवेंट का जवाब देने और गेस्टबुक चैट ऐप्लिकेशन बनाने का तरीका.
  • Firebase Authentication की मदद से उपयोगकर्ताओं की पुष्टि करने और Firestore के साथ डेटा सिंक करने का तरीका.

Android पर ऐप्लिकेशन की होम स्क्रीन पर

iOS पर ऐप्लिकेशन की होम स्क्रीन पर

आपको इन चीज़ों की ज़रूरत होगी

इनमें से कोई भी डिवाइस:

  • एक ऐसा Android या iOS डिवाइस जो आपके कंप्यूटर से कनेक्ट हो और डेवलपर मोड पर सेट हो.
  • iOS सिम्युलेटर (इसके लिए Xcode टूल ज़रूरी हैं).
  • Android एमुलेटर (Android Studio में सेटअप करना ज़रूरी है).

आपको इनकी भी ज़रूरत होगी:

  • आपकी पसंद का ब्राउज़र, जैसे कि Google Chrome.
  • आपकी पसंद का आईडीई या टेक्स्ट एडिटर, जिसे Dart और Flutter प्लग इन के साथ कॉन्फ़िगर किया गया हो. जैसे, Android Studio या Visual Studio Code.
  • अगर आपको अलग-अलग जगहों पर रहना पसंद है, तो Flutter या beta का नया stable वर्शन आज़माएं.
  • आपके Firebase प्रोजेक्ट को बनाने और मैनेज करने के लिए Google खाता.
  • Firebase सीएलआई ने आपके Google खाते में लॉग इन किया हो.

2. सैंपल कोड पाना

GitHub से अपने प्रोजेक्ट का शुरुआती वर्शन डाउनलोड करें:

  1. कमांड लाइन से, flutter-codelabs डायरेक्ट्री में GitHub डेटा स्टोर करने की जगह को क्लोन करें:
git clone https://github.com/flutter/codelabs.git flutter-codelabs

flutter-codelabs डायरेक्ट्री में, कोडलैब के कलेक्शन का कोड शामिल होता है. इस कोडलैब का कोड, flutter-codelabs/firebase-get-to-know-flutter डायरेक्ट्री में है. डायरेक्ट्री में स्नैपशॉट की एक सीरीज़ होती है. इससे पता चलता है कि हर चरण के आखिर में आपका प्रोजेक्ट कैसा दिखेगा. उदाहरण के लिए, आप दूसरे चरण पर हैं.

  1. दूसरे चरण के लिए, मिलती-जुलती फ़ाइलें ढूंढें:
cd flutter-codelabs/firebase-get-to-know-flutter/step_02

अगर आपको आगे जाना है या किसी चरण के बाद किसी चीज़ को देखने का तरीका जानना है, तो उस चरण के नाम पर डायरेक्ट्री देखें.

स्टार्टर ऐप्लिकेशन इंपोर्ट करना

  • अपने पसंदीदा आईडीई में flutter-codelabs/firebase-get-to-know-flutter/step_02 डायरेक्ट्री खोलें या इंपोर्ट करें. इस डायरेक्ट्री में, कोडलैब के लिए स्टार्टर कोड मौजूद है. इसमें Flutter meetup ऐप्लिकेशन शामिल है, जो फ़िलहाल काम नहीं कर रहा है.

उन फ़ाइलों को ढूंढना जिन पर काम करना है

इस ऐप्लिकेशन का कोड, कई डायरेक्ट्री में मौजूद है. फ़ंक्शन के हिसाब से कोड को अलग-अलग रखने से, काम आसान हो जाता है.

  • निम्न फ़ाइलें ढूंढें:
    • lib/main.dart: इस फ़ाइल में मुख्य एंट्री पॉइंट और ऐप्लिकेशन विजेट शामिल होता है.
    • lib/home_page.dart: इस फ़ाइल में होम पेज का विजेट शामिल है.
    • lib/src/widgets.dart: ऐप्लिकेशन की स्टाइल को स्टैंडर्ड बनाने में मदद करने के लिए, इस फ़ाइल में कुछ विजेट शामिल हैं. ये स्टार्टर ऐप्लिकेशन की स्क्रीन बनाते हैं.
    • lib/src/authentication.dart: इस फ़ाइल में Firebase के ईमेल की मदद से पुष्टि करने के लिए, लॉगिन उपयोगकर्ता अनुभव बनाने के लिए विजेट के सेट के साथ पुष्टि करने की प्रक्रिया को कुछ हद तक लागू किया गया है. पुष्टि करने के फ़्लो के लिए, इन विजेट का इस्तेमाल स्टार्टर ऐप्लिकेशन में अभी नहीं किया गया है. हालांकि, इन्हें जल्द ही जोड़ा जा सकता है.

ऐप्लिकेशन के बाकी बचे हिस्से को बनाने के लिए, ज़रूरत पड़ने पर अतिरिक्त फ़ाइलें जोड़ी जा सकती हैं.

lib/main.dart फ़ाइल की समीक्षा करना

यह ऐप्लिकेशन, Roboto को पूरे ऐप्लिकेशन में डिफ़ॉल्ट फ़ॉन्ट बनाने के लिए, google_fonts पैकेज का इस्तेमाल करता है. आपके पास fonts.google.com को एक्सप्लोर करने और ऐप्लिकेशन के अलग-अलग हिस्सों में मिलने वाले फ़ॉन्ट इस्तेमाल करने का विकल्प होता है.

lib/src/widgets.dart फ़ाइल में मौजूद हेल्पर विजेट का इस्तेमाल, Header, Paragraph, और IconAndDetail के तौर पर किया जाता है. ये विजेट, डुप्लीकेट कोड को हटा देते हैं, ताकि HomePage में बताए गए पेज लेआउट में गै़र-ज़रूरी चीज़ें कम की जा सकें. इससे, एक जैसा लुक और स्टाइल भी मिलता है.

Android, iOS, वेब, और macOS पर आपका ऐप्लिकेशन ऐसा दिखता है:

Android पर ऐप्लिकेशन की होम स्क्रीन पर

iOS पर ऐप्लिकेशन की होम स्क्रीन पर

वेब पर ऐप्लिकेशन की होम स्क्रीन

macOS पर ऐप्लिकेशन की होम स्क्रीन

3. Firebase प्रोजेक्ट बनाना और उसे कॉन्फ़िगर करना

इवेंट की जानकारी को दिखाना आपके मेहमानों के लिए अच्छा होता है, लेकिन यह अपने-आप में किसी के लिए भी बहुत काम की नहीं होती. आपको ऐप्लिकेशन में कुछ डाइनैमिक फ़ंक्शन जोड़ने होंगे. ऐसा करने के लिए, आपको Firebase को अपने ऐप्लिकेशन से कनेक्ट करना होगा. Firebase का इस्तेमाल शुरू करने के लिए, आपको एक Firebase प्रोजेक्ट बनाना और कॉन्फ़िगर करना होगा.

Firebase प्रोजेक्ट बनाना

  1. Firebase में साइन इन करें.
  2. कंसोल में, प्रोजेक्ट जोड़ें या प्रोजेक्ट बनाएं पर क्लिक करें.
  3. प्रोजेक्ट का नाम फ़ील्ड में, Firebase-Flutter-Codelab डालें और फिर जारी रखें पर क्लिक करें.

4395e4e67c08043a.png

  1. प्रोजेक्ट बनाने के विकल्पों पर क्लिक करें. अगर कहा जाए, तो Firebase की शर्तें स्वीकार करें. हालांकि, Google Analytics का सेटअप न करें, क्योंकि आपको इसका इस्तेमाल इस ऐप्लिकेशन के लिए नहीं करना है.

b7138cde5f2c7b61.png

Firebase प्रोजेक्ट के बारे में ज़्यादा जानने के लिए, Firebase प्रोजेक्ट के बारे में जानकारी लेख पढ़ें.

यह ऐप्लिकेशन, Firebase के इन प्रॉडक्ट का इस्तेमाल करता है, जो वेब ऐप्लिकेशन के लिए उपलब्ध हैं:

  • पुष्टि करना: इससे उपयोगकर्ताओं को आपके ऐप्लिकेशन में साइन इन करने की सुविधा मिलती है.
  • फ़ायरस्टोर: इससे स्ट्रक्चर्ड डेटा को क्लाउड पर सेव किया जाता है और डेटा में बदलाव होने पर तुरंत सूचनाएं मिलती हैं.
  • Firebase के सुरक्षा के नियम: आपके डेटाबेस को सुरक्षित रखता है.

इनमें से कुछ प्रॉडक्ट के लिए खास कॉन्फ़िगरेशन की ज़रूरत होती है या आपको उन्हें Firebase कंसोल में चालू करना पड़ता है.

ईमेल साइन इन की पुष्टि करने की सुविधा चालू करें

  1. Firebase कंसोल के प्रोजेक्ट की खास जानकारी वाले पैनल में, बिल्ड मेन्यू को बड़ा करें.
  2. पुष्टि करें > शुरू करें > साइन इन करने का तरीका > ईमेल/पासवर्ड > चालू करें > सेव करें पर क्लिक करें.

58e3e3e23c2f16a4.png

Firestore सेट अप करना

चैट मैसेज सेव करने और नए चैट मैसेज पाने के लिए वेब ऐप्लिकेशन Firestore का इस्तेमाल करता है.

अपने Firebase प्रोजेक्ट में Firestore सेट अप करने का तरीका यहां बताया गया है:

  1. Firebase कंसोल के बाएं पैनल में, Build को बड़ा करें. इसके बाद, Firestore डेटाबेस को चुनें.
  2. डेटाबेस बनाएं पर क्लिक करें.
  3. डेटाबेस आईडी को (default) पर सेट रहने दें.
  4. अपने डेटाबेस के लिए कोई जगह चुनें. इसके बाद, आगे बढ़ें पर क्लिक करें.
    असल ऐप्लिकेशन के लिए, आपको ऐसी जगह चुननी होगी जो आपके उपयोगकर्ताओं के आस-पास हो.
  5. टेस्ट मोड में चालू करें पर क्लिक करें. सुरक्षा के नियमों से जुड़ा डिसक्लेमर पढ़ें.
    इस कोडलैब में, बाद में अपने डेटा को सुरक्षित रखने के लिए आपको सुरक्षा के नियम जोड़ने होंगे. अपने डेटाबेस के लिए सुरक्षा नियम जोड़े बिना, ऐप्लिकेशन को सार्वजनिक तौर पर डिस्ट्रिब्यूट या एक्सपोज़ करें.
  6. बनाएं पर क्लिक करें.

4. Firebase कॉन्फ़िगर करना

Flutter के साथ Firebase का इस्तेमाल करने के लिए, आपको Flutter प्रोजेक्ट को कॉन्फ़िगर करना होगा, ताकि FlutterFire लाइब्रेरी का सही तरीके से इस्तेमाल किया जा सके. इसके लिए, आपको ये काम करने होंगे:

  1. अपने प्रोजेक्ट में FlutterFire डिपेंडेंसी जोड़ें.
  2. Firebase प्रोजेक्ट पर, अपनी पसंद का प्लैटफ़ॉर्म रजिस्टर करें.
  3. प्लैटफ़ॉर्म के हिसाब से कॉन्फ़िगरेशन फ़ाइल डाउनलोड करें और फिर उसे कोड में जोड़ें.

आपके Flutter ऐप्लिकेशन की टॉप-लेवल डायरेक्ट्री में android, ios, macos, और web सबडायरेक्ट्री हैं. ये सबडायरेक्ट्री, iOS और Android के लिए प्लैटफ़ॉर्म के हिसाब से कॉन्फ़िगरेशन फ़ाइलें सेव करती हैं.

डिपेंडेंसी कॉन्फ़िगर करें

आपको इस ऐप्लिकेशन में इस्तेमाल किए जाने वाले दो Firebase प्रॉडक्ट के लिए, FlutterFire लाइब्रेरी जोड़नी होंगी: पुष्टि करने की सुविधा और Firestore.

  • कमांड लाइन से, ये डिपेंडेंसी जोड़ें:
$ flutter pub add firebase_core

firebase_core पैकेज एक ऐसा सामान्य कोड है जो सभी Firebase Flutter प्लगिन के लिए ज़रूरी है.

$ flutter pub add firebase_auth

firebase_auth पैकेज, पुष्टि करने की सुविधा के साथ इंटिग्रेशन की सुविधा देता है.

$ flutter pub add cloud_firestore

cloud_firestore पैकेज, Firestore डेटा स्टोरेज को ऐक्सेस करने की सुविधा देता है.

$ flutter pub add provider

firebase_ui_auth पैकेज, विजेट और सुविधाओं का एक सेट उपलब्ध कराता है. इससे, पुष्टि करने के फ़्लो से डेवलपर को मिलने वाली संभावित पहुंच बढ़ती है.

$ flutter pub add firebase_ui_auth

आपने ज़रूरी पैकेज जोड़ दिए हैं. हालांकि, Firebase का सही तरीके से इस्तेमाल करने के लिए, आपको iOS, Android, macOS, और वेब रनर प्रोजेक्ट भी कॉन्फ़िगर करने होंगे. provider पैकेज का भी इस्तेमाल किया जाता है, ताकि कारोबार के लॉजिक को डिसप्ले लॉजिक से अलग किया जा सके.

FlutterFire CLI इंस्टॉल करना

FlutterFire CLI, Firebase CLI पर निर्भर करता है.

  1. अगर आपने पहले से ऐसा नहीं किया है, तो अपनी मशीन पर Firebase सीएलआई इंस्टॉल करें.
  2. FlutterFire सीएलआई इंस्टॉल करें:
$ dart pub global activate flutterfire_cli

इंस्टॉल होने के बाद, flutterfire निर्देश दुनिया भर में उपलब्ध होता है.

अपने ऐप्लिकेशन कॉन्फ़िगर करना

सीएलआई आपके Firebase प्रोजेक्ट और चुने गए प्रोजेक्ट ऐप्लिकेशन से जानकारी इकट्ठा करता है, ताकि किसी प्लैटफ़ॉर्म के लिए सभी कॉन्फ़िगरेशन जनरेट किए जा सकें.

अपने ऐप्लिकेशन के रूट में, configure कमांड चलाएं:

$ flutterfire configure

कॉन्फ़िगरेशन कमांड की मदद से, ये प्रोसेस की जा सकती हैं:

  1. .firebaserc फ़ाइल या Firebase कंसोल से कोई Firebase प्रोजेक्ट चुनें.
  2. कॉन्फ़िगरेशन के लिए प्लैटफ़ॉर्म तय करें. जैसे, Android, iOS, macOS, और वेब.
  3. उन Firebase ऐप्लिकेशन की पहचान करें जिनसे कॉन्फ़िगरेशन एक्सट्रैक्ट करना है. डिफ़ॉल्ट रूप से, सीएलआई आपके मौजूदा प्रोजेक्ट कॉन्फ़िगरेशन के आधार पर, Firebase ऐप्लिकेशन को अपने-आप मैच करने की कोशिश करता है.
  4. अपने प्रोजेक्ट में firebase_options.dart फ़ाइल जनरेट करें.

macOS कॉन्फ़िगर करना

macOS पर Flutter, पूरी तरह से सैंडबॉक्स किए गए ऐप्लिकेशन बनाता है. यह ऐप्लिकेशन, Firebase सर्वर से संपर्क करने के लिए नेटवर्क के साथ इंटिग्रेट होता है. इसलिए, आपको अपने ऐप्लिकेशन को नेटवर्क क्लाइंट की अनुमतियों के साथ कॉन्फ़िगर करना होगा.

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>

ज़्यादा जानकारी के लिए, Flutter के लिए डेस्कटॉप सहायता देखें.

5. जवाब देने की सुविधा जोड़ना

ऐप्लिकेशन में Firebase जोड़ने के बाद, हां में जवाब देने के लिए एक बटन बनाया जा सकता है. इस बटन की मदद से, लोग पुष्टि करके रजिस्टर कर सकते हैं. Android नेटिव, iOS नेटिव, और वेब के लिए, पहले से बने FirebaseUI Auth पैकेज उपलब्ध हैं. हालांकि, आपको Flutter के लिए यह सुविधा बनानी होगी.

आपने जिस प्रोजेक्ट को पहले वापस लाया था उसमें विजेट का एक सेट शामिल था. इसकी मदद से, पुष्टि करने के ज़्यादातर फ़्लो के लिए यूज़र इंटरफ़ेस लागू किया जाता है. ऐप्लिकेशन के साथ पुष्टि करने की सुविधा को इंटिग्रेट करने के लिए, आपने कारोबारी नियम लागू किया हो.

Provider पैकेज के साथ कारोबार का लॉजिक जोड़ें

Flutter विजेट के ऐप्लिकेशन के ट्री में, ऐप्लिकेशन स्टेटस का एक सेंट्रलाइज़्ड ऑब्जेक्ट उपलब्ध कराने के लिए, provider पैकेज का इस्तेमाल करें:

  1. app_state.dart नाम की नई फ़ाइल बनाएं और उसमें यह कॉन्टेंट शामिल करें:

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 स्टेटमेंट में Firebase Core और Auth की जानकारी दी जाती है. इनमें provider पैकेज शामिल होता है, जो पूरे विजेट ट्री में ऐप्लिकेशन की स्थिति से जुड़ा ऑब्जेक्ट उपलब्ध कराता है. साथ ही, इसमें firebase_ui_auth पैकेज से मिलने वाले, पुष्टि करने वाले विजेट शामिल होते हैं.

इस चरण के लिए, इस ApplicationState ऐप्लिकेशन की स्थिति वाले ऑब्जेक्ट की एक मुख्य ज़िम्मेदारी है. इसका मकसद, विजेट ट्री को यह बताना है कि पुष्टि की गई स्थिति में कोई अपडेट हुआ है.

ऐप्लिकेशन में उपयोगकर्ता के लॉगिन स्टेटस की जानकारी देने के लिए, सिर्फ़ कंपनी का इस्तेमाल किया जाता है. उपयोगकर्ता को लॉग इन करने की अनुमति देने के लिए, firebase_ui_auth पैकेज से मिले यूज़र इंटरफ़ेस (यूआई) का इस्तेमाल करें. यह आपके ऐप्लिकेशन में लॉगिन स्क्रीन को तेज़ी से बूटस्ट्रैप करने का एक शानदार तरीका है.

पुष्टि करने का फ़्लो इंटिग्रेट करना

  1. lib/main.dart फ़ाइल में सबसे ऊपर मौजूद इंपोर्ट में बदलाव करें:

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. ऐप्लिकेशन के स्टेटस को ऐप्लिकेशन के शुरू होने से कनेक्ट करें. इसके बाद, HomePage में पुष्टि करने का फ़्लो जोड़ें:

lib/main.dart

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

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

main() फ़ंक्शन में बदलाव करने पर, प्रोवाइडर पैकेज ChangeNotifierProvider विजेट के साथ, ऐप्लिकेशन की स्थिति बताने वाले ऑब्जेक्ट को इंस्टैंशिएट करता है. आपको इस खास provider क्लास का इस्तेमाल करना है, क्योंकि ऐप्लिकेशन की स्थिति से जुड़ा ऑब्जेक्ट, ChangeNotifier क्लास को बड़ा करता है. इससे provider पैकेज को यह पता चलता है कि डिपेंडेंट विजेट फिर से कब दिखाना है.

  1. Firebase यूज़र इंटरफ़ेस (यूआई) से मिलने वाली अलग-अलग स्क्रीन पर नेविगेशन मैनेज करने के लिए, अपने ऐप्लिकेशन को अपडेट करें. ऐसा करने के लिए, GoRouter कॉन्फ़िगरेशन बनाएं:

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

पुष्टि करने के फ़्लो की नई स्थिति के आधार पर, हर स्क्रीन के लिए अलग-अलग तरह की कार्रवाई की जाती है. पुष्टि करने की प्रक्रिया में ज़्यादातर बदलाव होने के बाद, आपके पास अपनी पसंदीदा स्क्रीन पर वापस जाने का विकल्प होता है. भले ही, वह डिवाइस होम स्क्रीन हो या कोई दूसरी स्क्रीन, जैसे कि प्रोफ़ाइल.

  1. HomePage क्लास के बिल्ड तरीके में, ऐप्लिकेशन की स्थिति को AuthFunc विजेट के साथ इंटिग्रेट करें:

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 विजेट को इंस्टैंशिएट करके, उसे Consumer विजेट में रैप किया जाता है. कंज्यूमर विजेट, आम तौर पर इस्तेमाल किया जाने वाला तरीका है. इसकी मदद से, ऐप्लिकेशन की स्थिति में बदलाव होने पर, ट्री के कुछ हिस्से को फिर से बनाया जा सकता है. AuthFunc विजेट ऐसा पूरक विजेट है जिसकी जांच की जाती है.

पुष्टि करने की प्रोसेस की जांच करना

cdf2d25e436bd48d.png

  1. SignInScreen शुरू करने के लिए, ऐप्लिकेशन में जवाब दें बटन पर टैप करें.

2a2cd6d69d172369.png

  1. कोई ईमेल पता डालें. अगर आपने पहले से रजिस्टर किया हुआ है, तो सिस्टम आपको पासवर्ड डालने के लिए कहता है. ऐसा न करने पर, सिस्टम आपसे रजिस्ट्रेशन फ़ॉर्म भरने के लिए कहेगा.

e5e65065dba36b54.png

  1. गड़बड़ी को ठीक करने के फ़्लो की जांच करने के लिए, छह से कम वर्णों वाला पासवर्ड डालें. अगर आप रजिस्टर हैं, तो आपको इसके बजाय का पासवर्ड दिखेगा.
  2. गड़बड़ी को ठीक करने के फ़्लो की जांच करने के लिए, गलत पासवर्ड डालें.
  3. सही पासवर्ड डालें. आपको लॉग इन किया गया अनुभव दिखता है, जिसमें उपयोगकर्ता को लॉग आउट करने की सुविधा मिलती है.

4ed811a25b0cf816.png

6. Firestore पर मैसेज लिखो

यह जानकर अच्छा लगा कि उपयोगकर्ता आ रहे हैं, लेकिन आपको मेहमानों को ऐप्लिकेशन में करने के लिए कुछ और देना होगा. अगर वे गेस्टबुक में मैसेज छोड़ सकें, तो कैसा रहेगा? वे दर्शकों को बता सकते हैं कि वे चैनल पर आने के लिए क्यों उत्साहित हैं या उन्हें किससे मिलने की उम्मीद है.

ऐप्लिकेशन में उपयोगकर्ताओं के लिखे गए चैट मैसेज सेव करने के लिए, Firestore का इस्तेमाल किया जा सकता है.

डेटा मॉडल

Firestore एक NoSQL डेटाबेस है. इसमें सेव किए गए डेटा को कलेक्शन, दस्तावेज़, फ़ील्ड, और सब-कलेक्शन में बांटा जाता है. चैट के हर मैसेज को दस्तावेज़ के तौर पर guestbook कलेक्शन में सेव किया जाता है. यह टॉप-लेवल कलेक्शन होता है.

7c20dc8424bb1d84.png

Firestore में मैसेज जोड़ें

इस सेक्शन में, उपयोगकर्ताओं को डेटाबेस में मैसेज लिखने की सुविधा जोड़ी जाती है. सबसे पहले, फ़ॉर्म फ़ील्ड और 'भेजें' बटन जोड़ें. इसके बाद, वह कोड जोड़ें जो इन एलिमेंट को डेटाबेस से जोड़ता है.

  1. guest_book.dart नाम की एक नई फ़ाइल बनाएं. मैसेज फ़ील्ड और भेजें बटन के यूज़र इंटरफ़ेस (यूआई) एलिमेंट बनाने के लिए, GuestBook स्टेटफ़ुल विजेट जोड़ें:

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

यहां कुछ अहम बातें बताई गई हैं. सबसे पहले, आप एक फ़ॉर्म इंस्टैंशिएट करते हैं, ताकि आप यह पुष्टि कर सकें कि मैसेज में वाकई कॉन्टेंट है या न होने पर, उपयोगकर्ता को गड़बड़ी का मैसेज दिखाएं. फ़ॉर्म की पुष्टि करने के लिए, GlobalKey की मदद से फ़ॉर्म में मौजूद फ़ॉर्म की स्थिति को ऐक्सेस किया जाता है. कुंजियों और उन्हें इस्तेमाल करने के तरीके के बारे में ज़्यादा जानकारी के लिए, पासकोड का इस्तेमाल कब करना चाहिए देखें.

यह भी ध्यान रखें कि विजेट कैसे रखे गए हैं. आपके पास TextFormField के साथ Row और StyledButton है, जिसमें Row है. यह भी ध्यान रखें कि TextFormField को Expanded विजेट में रैप किया गया है, जो TextFormField को पंक्ति में ज़्यादा जगह भरने के लिए मजबूर करता है. यह ज़रूरी क्यों है, यह बेहतर तरीके से समझने के लिए सीमाओं को समझना लेख पढ़ें.

अब आपके पास एक ऐसा विजेट है जो लोगों को 'मेहमान किताब' में जोड़ने के लिए कुछ टेक्स्ट डालने की सुविधा देता है, तो आपको उसे स्क्रीन पर लाना होगा.

  1. ListView के चाइल्ड एलिमेंट के आखिर में, ये दो लाइन जोड़ने के लिए, HomePage के मुख्य हिस्से में बदलाव करें:
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)),

विजेट दिखाने के लिए यह काफ़ी है, लेकिन इससे कोई काम नहीं हो सकता. इस कोड को जल्द ही अपडेट किया जाएगा, ताकि यह काम करे.

ऐप्लिकेशन की झलक

चैट इंटिग्रेशन के साथ Android पर ऐप्लिकेशन की होम स्क्रीन

iOS पर चैट इंटिग्रेशन के साथ ऐप्लिकेशन की होम स्क्रीन

चैट इंटिग्रेशन के साथ वेब पर ऐप्लिकेशन की होम स्क्रीन

macOS पर ऐप्लिकेशन की होम स्क्रीन पर, चैट करने की सुविधा

जब कोई उपयोगकर्ता भेजें पर क्लिक करता है, तो यह नीचे दिया गया कोड स्निपेट ट्रिगर करता है. यह मैसेज इनपुट फ़ील्ड के कॉन्टेंट को डेटाबेस के guestbook कलेक्शन में जोड़ देता है. खास तौर पर, addMessageToGuestBook तरीका मैसेज के कॉन्टेंट को guestbook कलेक्शन में अपने-आप जनरेट हुए आईडी वाले नए दस्तावेज़ में जोड़ता है.

ध्यान दें कि FirebaseAuth.instance.currentUser.uid, अपने-आप जनरेट हुए उस यूनीक आईडी का रेफ़रंस है जो पुष्टि करने की सुविधा, लॉग इन किए हुए सभी उपयोगकर्ताओं को देती है.

  • lib/app_state.dart फ़ाइल में, addMessageToGuestBook तरीका जोड़ें. अगले चरण में, इस सुविधा को यूज़र इंटरफ़ेस से कनेक्ट किया जाएगा.

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

यूज़र इंटरफ़ेस (यूआई) और डेटाबेस को कनेक्ट करें

आपके पास एक यूज़र इंटरफ़ेस (यूआई) है, जहां उपयोगकर्ता वह टेक्स्ट डाल सकता है जिसे उसे मेहमान की किताब में जोड़ना है. साथ ही, आपके पास Firestore में एंट्री जोड़ने का कोड है. अब आपको बस दोनों को कनेक्ट करना है.

  • lib/home_page.dart फ़ाइल में, HomePage विजेट में यह बदलाव करें:

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

आपने इस चरण की शुरुआत में जोड़ी गई दो लाइनों को, पूरी तरह से लागू करने के साथ बदल दिया है. Consumer<ApplicationState> का फिर से इस्तेमाल करके, ऐप्लिकेशन की स्थिति को उस हिस्से के लिए उपलब्ध कराया जा सकता है जिसे रेंडर किया जाता है. इसकी मदद से, यूज़र इंटरफ़ेस (यूआई) में मैसेज डालकर, उस पर प्रतिक्रिया दी जा सकती है. साथ ही, उसे डेटाबेस में पब्लिश किया जा सकता है. अगले सेक्शन में, यह जांच की जाती है कि जोड़े गए मैसेज, डेटाबेस में पब्लिश किए गए हैं या नहीं.

मैसेज भेजने की जांच करना

  1. अगर ज़रूरी हो, तो ऐप्लिकेशन में साइन इन करें.
  2. कोई मैसेज डालें, जैसे कि Hey there!. इसके बाद, भेजें पर क्लिक करें.

यह कार्रवाई, मैसेज को आपके Firestore डेटाबेस में सेव करती है. हालांकि, आपको अपने असल Flutter ऐप्लिकेशन में मैसेज नहीं दिखता है. ऐसा इसलिए, क्योंकि आपको अब भी डेटा वापस पाने की प्रोसेस लागू करनी है. यह कार्रवाई अगले चरण में की जाती है. हालांकि, Firebase कंसोल के डेटाबेस डैशबोर्ड में, जोड़ा गया मैसेज guestbook कलेक्शन में देखा जा सकता है. ज़्यादा मैसेज भेजने पर, आपके guestbook कलेक्शन में और दस्तावेज़ जुड़ जाते हैं. उदाहरण के लिए, यह कोड स्निपेट देखें:

713870af0b3b63c.png

7. मैसेज पढ़ना

यह सुविधा अच्छी है कि मेहमान डेटाबेस में मैसेज लिख सकते हैं. हालांकि, वे उन्हें ऐप्लिकेशन में अभी नहीं देख सकते. इसे ठीक करने का समय आ गया है!

मैसेज सिंक करना

मैसेज दिखाने के लिए, आपको लिसनर जोड़ना होगा जो डेटा में बदलाव होने पर ट्रिगर होता है. इसके बाद, आपको नए मैसेज दिखाने वाला यूज़र इंटरफ़ेस (यूआई) एलिमेंट बनाना होगा. ऐप्लिकेशन की स्थिति में कोड जोड़ा जाता है, जो ऐप्लिकेशन के जोड़े गए नए मैसेज को सुनता है.

  1. एक नई फ़ाइल guest_book_message.dart बनाएं. Firestore में सेव किए गए डेटा का स्ट्रक्चर्ड व्यू दिखाने के लिए, नीचे दी गई क्लास जोड़ें.

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 फ़ाइल में, ये इंपोर्ट जोड़ें:

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 के उस सेक्शन में जहां आप स्थिति और गैटर तय करते हैं, ये पंक्तियां जोड़ें:

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. ApplicationState के इनिशलाइज़ेशन सेक्शन में, जब कोई उपयोगकर्ता लॉग इन करता है, तो दस्तावेज़ के कलेक्शन पर किसी क्वेरी की सदस्यता लेने के लिए ये लाइनें जोड़ें और लॉग आउट करने पर सदस्यता छोड़ें:

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

यह सेक्शन अहम है, क्योंकि यहां आप guestbook कलेक्शन पर क्वेरी तैयार करते हैं. साथ ही, यहां से इस कलेक्शन की सदस्यता और सदस्यता छोड़ने की कार्रवाई मैनेज की जाती है. स्ट्रीम को सुनने पर, guestbook कलेक्शन में मैसेज का एक स्थानीय कैश मेमोरी फिर से बन जाता है. साथ ही, इस सदस्यता का रेफ़रंस भी सेव हो जाता है, ताकि आप बाद में इसकी सदस्यता छोड़ सकें. यहां बहुत कुछ हो रहा है. इसलिए, आपको इसे डीबगर में एक्सप्लोर करना चाहिए, ताकि आपको साफ़ तौर पर यह पता चल सके कि क्या हो रहा है. ज़्यादा जानकारी के लिए, Firestore के साथ रीयलटाइम अपडेट पाना देखें.

  1. lib/guest_book.dart फ़ाइल में, यह इंपोर्ट जोड़ें:
import 'guest_book_message.dart';
  1. इस बदलती स्थिति को यूज़र इंटरफ़ेस से कनेक्ट करने के लिए, GuestBook विजेट में, कॉन्फ़िगरेशन के तहत मैसेज की एक सूची जोड़ें:

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. _GuestBookState में, इस कॉन्फ़िगरेशन को सार्वजनिक करने के लिए build तरीके में नीचे बताए गए तरीके से बदलाव करें:

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() तरीके के पिछले कॉन्टेंट को Column विजेट के साथ रैप करें. इसके बाद, Column की चाइल्ड एंट्री में इसके लिए कलेक्शन जोड़ें, ताकि मैसेज की सूची में हर मैसेज के लिए एक नया Paragraph जनरेट किया जा सके.

  1. नए messages पैरामीटर के साथ GuestBook को सही तरीके से बनाने के लिए, HomePage के मुख्य हिस्से को अपडेट करें:

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

मैसेज सिंक करने की सुविधा की जांच करना

Firestore, डेटाबेस की सदस्यता वाले क्लाइंट के साथ डेटा को अपने-आप और तुरंत सिंक करता है.

मैसेज सिंक होने की जांच करें:

  1. ऐप्लिकेशन में, डेटाबेस में पहले से मौजूद मैसेज ढूंढें.
  2. नए मैसेज लिखना. वे तुरंत दिखाई देते हैं.
  3. अपने फ़ाइल फ़ोल्डर को एक से ज़्यादा विंडो या टैब में खोलें. मैसेज, सभी विंडो और टैब में रीयल टाइम में सिंक होते हैं.
  4. ज़रूरी नहीं: Firebase कंसोल के डेटाबेस मेन्यू में, मैन्युअल तरीके से मैसेज मिटाएं, उनमें बदलाव करें या नए मैसेज जोड़ें. सभी बदलाव यूज़र इंटरफ़ेस (यूआई) में दिखते हैं.

बधाई हो! आपने अपने ऐप्लिकेशन में Firestore दस्तावेज़ पढ़ लिए हैं!

ऐप्लिकेशन की झलक

चैट इंटिग्रेशन के साथ Android पर ऐप्लिकेशन की होम स्क्रीन

iOS पर चैट इंटिग्रेशन के साथ ऐप्लिकेशन की होम स्क्रीन

चैट इंटिग्रेशन के साथ वेब पर ऐप्लिकेशन की होम स्क्रीन

चैट इंटिग्रेशन के साथ macOS पर ऐप्लिकेशन की होम स्क्रीन

8. सुरक्षा के बुनियादी नियम सेट अप करना

शुरुआत में आपने टेस्ट मोड का इस्तेमाल करने के लिए Firestore को सेट अप किया. इसका मतलब है कि आपके डेटाबेस में पढ़ने और लिखने की अनुमति है. हालांकि, आपको टेस्ट मोड का इस्तेमाल सिर्फ़ डेवलपमेंट के शुरुआती चरणों में करना चाहिए. सबसे सही तरीका यह है कि ऐप्लिकेशन डेवलप करते समय, अपने डेटाबेस के लिए सुरक्षा से जुड़े नियम सेट अप करें. सुरक्षा, आपके ऐप्लिकेशन के स्ट्रक्चर और काम करने के तरीके के लिए ज़रूरी है.

Firebase के सुरक्षा नियमों की मदद से, अपने डेटाबेस में मौजूद दस्तावेज़ों और कलेक्शन का ऐक्सेस कंट्रोल किया जा सकता है. सुविधाजनक नियमों के सिंटैक्स की मदद से ऐसे नियम बनाए जा सकते हैं जो पूरे डेटाबेस में, सभी लिखे गए कॉन्टेंट से लेकर किसी दस्तावेज़ पर की गई कार्रवाइयों तक मैच करते हैं.

सुरक्षा से जुड़े बुनियादी नियम सेट अप करें:

  1. Firebase कंसोल के डेवलप करें मेन्यू में, डेटाबेस > नियम पर क्लिक करें. आपको नीचे दिए गए डिफ़ॉल्ट सुरक्षा नियम दिखेंगे. साथ ही, नियमों को सार्वजनिक होने से जुड़ी एक चेतावनी भी दिखेगी:

7767a2d2e64e7275.png

  1. उन कलेक्शन की पहचान करें जिनमें ऐप्लिकेशन डेटा सेव करता है:

match /databases/{database}/documents में, उस कलेक्शन की पहचान करें जिसे आपको सुरक्षित करना है:

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

आपने हर मेहमान की किताब के दस्तावेज़ में, पुष्टि करने के लिए यूआईडी को फ़ील्ड के तौर पर इस्तेमाल किया है. इसलिए, पुष्टि करने के लिए यूआईडी को देखा जा सकता है और पुष्टि की जा सकती है कि दस्तावेज़ में लिखने की कोशिश करने वाले व्यक्ति के पास, पुष्टि करने के लिए यूआईडी है या नहीं.

  1. अपने नियम सेट में 'पढ़ें और लिखें' नियम जोड़ें:
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;
    }
  }
}

अब सिर्फ़ साइन इन किए हुए उपयोगकर्ता, मेहमान की किताब में मौजूद मैसेज पढ़ सकते हैं. हालांकि, मैसेज का लेखक ही उसमें बदलाव कर सकता है.

  1. डेटा की पुष्टि करने की सुविधा जोड़ें, ताकि यह पक्का किया जा सके कि दस्तावेज़ में सभी ज़रूरी फ़ील्ड मौजूद हैं:
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. बोनस स्टेप: सीखी गई बातों की प्रैक्टिस करें

किसी व्यक्ति के जवाब का स्टेटस रिकॉर्ड करना

फ़िलहाल, आपका ऐप्लिकेशन सिर्फ़ उन लोगों को चैट करने की अनुमति देता है जिनकी दिलचस्पी इवेंट में है. साथ ही, यह जानने का सिर्फ़ एक तरीका है कि कोई व्यक्ति मीटिंग में शामिल होगा या नहीं. इसके लिए, वह व्यक्ति चैट में बताएगा.

इस चरण में, आप व्यवस्थित हो जाते हैं और लोगों को बताते हैं कि कितने लोग आ रहे हैं. आपने ऐप्लिकेशन स्टेटस में कुछ सुविधाएं जोड़ी हैं. पहला विकल्प, लॉग इन किए हुए उपयोगकर्ता को यह बताने की सुविधा देता है कि वह इस इवेंट में शामिल हो रहा है या नहीं. दूसरा काउंटर है, जिससे पता चलता है कि कितने लोग इवेंट में शामिल हो रहे हैं.

  1. lib/app_state.dart फ़ाइल में, ApplicationState के ऐक्सेसर सेक्शन में ये लाइनें जोड़ें, ताकि यूज़र इंटरफ़ेस (यूआई) कोड इस स्थिति के साथ इंटरैक्ट कर सके:

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 की init() तरीके को इस तरह से अपडेट करें:

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

यह कोड, हमेशा सदस्यता वाली एक क्वेरी जोड़ता है, ताकि मीटिंग में शामिल लोगों की संख्या का पता लगाया जा सके. साथ ही, यह एक दूसरी क्वेरी भी जोड़ता है, जो सिर्फ़ तब चालू रहती है, जब कोई उपयोगकर्ता लॉग इन होता है. इससे यह पता चलता है कि उपयोगकर्ता मीटिंग में शामिल है या नहीं.

  1. lib/app_state.dart फ़ाइल में सबसे ऊपर ये सूचियां जोड़ें.

lib/app_state.dart

enum Attending { yes, no, unknown }
  1. एक नई फ़ाइल yes_no_selection.dart बनाएं और रेडियो बटन की तरह काम करने वाला नया विजेट तय करें:

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

यह तय नहीं की जाती है. इसमें हां या नहीं चुना गया होता है. जब उपयोगकर्ता यह चुन लेता है कि वह मीटिंग में शामिल होगा या नहीं, तो उस विकल्प को हाइलाइट करके दिखाया जाता है. साथ ही, दूसरे विकल्प को फ़्लैट रेंडरिंग के साथ दिखाया जाता है.

  1. YesNoSelection का फ़ायदा पाने के लिए, HomePage के build() तरीके को अपडेट करें. साथ ही, लॉग इन किए हुए उपयोगकर्ता को यह बताने की सुविधा दें कि वह इवेंट में शामिल होगा या नहीं. साथ ही, इवेंट में शामिल होने वाले लोगों की संख्या दिखाएं:

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

नियम जोड़ें

आपने पहले ही कुछ नियम सेट कर लिए हैं. इसलिए, बटन की मदद से जोड़ा जाने वाला डेटा अस्वीकार कर दिया जाएगा. attendees कलेक्शन में जोड़ने की अनुमति देने के लिए, आपको नियमों को अपडेट करना होगा.

  1. attendees कलेक्शन में, पुष्टि करने का वह यूआईडी लें जिसका इस्तेमाल आपने दस्तावेज़ के नाम के तौर पर किया है. साथ ही, पुष्टि करें कि सबमिट करने वाले का uid और उसका दस्तावेज़, दोनों एक ही हैं:
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId;
    }
  }
}

इससे सभी मेहमानों की सूची पढ़ सकते हैं, क्योंकि वहां कोई निजी डेटा नहीं होता. इस डेटा को सिर्फ़ क्रिएटर ही अपडेट कर सकता है.

  1. डेटा की पुष्टि करने की सुविधा जोड़ें, ताकि यह पक्का किया जा सके कि दस्तावेज़ में सभी ज़रूरी फ़ील्ड मौजूद हैं:
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. ज़रूरी नहीं: ऐप्लिकेशन में, Firebase कंसोल के Firestore डैशबोर्ड में नतीजे देखने के लिए बटन पर क्लिक करें.

ऐप्लिकेशन की झलक

Android पर ऐप्लिकेशन की होम स्क्रीन पर

iOS पर ऐप्लिकेशन की होम स्क्रीन पर

वेब पर ऐप्लिकेशन की होम स्क्रीन

macOS पर ऐप्लिकेशन की होम स्क्रीन

10. बधाई हो!

आपने रीयल-टाइम में काम करने वाला इंटरैक्टिव वेब ऐप्लिकेशन बनाने के लिए, Firebase का इस्तेमाल किया है!

और जानें