يمكنك إضافة مسار مصادقة المستخدم إلى تطبيق Flutter باستخدام FirebaseUI

1. قبل البدء

في هذا الدرس التطبيقي حول الترميز، ستتعلّم كيفية إضافة خدمة "المصادقة من Firebase" إلى تطبيق Flutter باستخدام حزمة FlutterFire UI. باستخدام هذه الحزمة، ستتمكّن من إضافة ميزة المصادقة باستخدام كلّ من عنوان البريد الإلكتروني وكلمة المرور، وميزة "تسجيل الدخول باستخدام حساب Google" إلى تطبيق Flutter. ستتعرّف أيضًا على كيفية إعداد مشروع على Firebase واستخدام واجهة سطر الأوامر FlutterFire لبدء استخدام Firebase في تطبيق Flutter.

المتطلبات الأساسية

يفترض هذا الدرس التطبيقي حول الترميز أنّ لديك بعض الخبرة في استخدام Flutter. إذا لم يكن الأمر كذلك، ننصحك بالتعرّف أولاً على الأساسيات. الروابط التالية مفيدة:

يجب أن يكون لديك أيضًا بعض الخبرة في Firebase، ولكن لا بأس إذا لم يسبق لك إضافة Firebase إلى مشروع Flutter. إذا لم تكن على دراية بوحدة تحكّم Firebase، أو إذا كنت مستخدمًا جديدًا تمامًا لبرنامج Firebase، يُرجى الاطّلاع أولاً على الروابط التالية:

ما ستنشئه

يرشدك هذا الدرس التطبيقي حول الترميز إلى كيفية إنشاء مسار المصادقة لتطبيق Flutter باستخدام خدمة "Firebase للمصادقة". سيتضمّن التطبيق شاشة تسجيل دخول وشاشة "تسجيل" وشاشة استرداد كلمة المرور وشاشة ملف شخصي للمستخدم.

6604fc9157f2c6ae.png eab9509a41074930.png da49189a5838e0bb.png b2ccfb3632b77878.png

أهداف الدورة التعليمية

يتناول هذا الدرس التطبيقي حول الترميز المواضيع التالية:

  • إضافة Firebase إلى تطبيق Flutter
  • إعداد "وحدة تحكّم Firebase"
  • استخدام Firebase CLI لإضافة Firebase إلى تطبيقك
  • استخدام FlutterFire CLI لإنشاء إعدادات Firebase في Dart
  • إضافة خدمة "مصادقة Firebase" إلى تطبيق Flutter
  • إعداد "مصادقة Firebase" في وحدة التحكّم
  • إضافة ميزة تسجيل الدخول باستخدام عنوان البريد الإلكتروني وكلمة المرور من خلال حزمة firebase_ui_auth
  • إضافة تسجيل المستخدمين باستخدام حزمة firebase_ui_auth
  • إضافة صفحة "هل نسيت كلمة المرور؟"
  • إضافة ميزة "تسجيل الدخول باستخدام حساب Google" مع firebase_ui_auth
  • ضبط تطبيقك للعمل مع عدة موفّري خدمات تسجيل الدخول
  • إضافة شاشة ملف مستخدم إلى تطبيقك باستخدام حزمة firebase_ui_auth

يهتم هذا الدرس البرمجي بشكل خاص بإضافة نظام مصادقة قوي باستخدام حزمة firebase_ui_auth. كما سترى، يمكن تنفيذ هذا التطبيق بأكمله، مع جميع الميزات المذكورة أعلاه، باستخدام حوالي 100 سطر من الرمز البرمجي.

المتطلبات

  • معرفة عملية بـ Flutter وتثبيت حزمة تطوير البرامج (SDK)
  • محرّر نصوص (يتوافق Flutter مع بيئات التطوير المتكاملة من JetBrains و"استوديو Android" وVS Code)
  • متصفّح Google Chrome أو هدف التطوير المفضّل الآخر لتطبيق Flutter (ستفترض بعض أوامر الوحدة الطرفية في هذا الدرس التطبيقي العملي أنّك تشغّل تطبيقك على Chrome)

2. إنشاء مشروع Firebase وإعداده

أول مهمة عليك إكمالها هي إنشاء مشروع Firebase في وحدة تحكّم Firebase على الويب.

إنشاء مشروع Firebase

  1. سجِّل الدخول إلى وحدة تحكّم Firebase باستخدام حسابك على Google.
  2. انقر على الزر لإنشاء مشروع جديد، ثم أدخِل اسم المشروع (على سبيل المثال، FlutterFire-UI-Codelab).
  3. انقر على متابعة.
  4. إذا طُلب منك ذلك، راجِع بنود Firebase واقبلها، ثم انقر على متابعة.
  5. (اختياري) فعِّل ميزة "المساعدة المستندة إلى الذكاء الاصطناعي" في وحدة تحكّم Firebase (المعروفة باسم "Gemini في Firebase").
  6. في هذا الدرس العملي، لا تحتاج إلى "إحصاءات Google"، لذا أوقِف خيار "إحصاءات Google".
  7. انقر على إنشاء مشروع، وانتظِر إلى أن يتم توفير مشروعك، ثم انقر على متابعة.

لمزيد من المعلومات عن مشاريع Firebase، اطّلِع على مقالة التعرّف على مشاريع Firebase.

تفعيل تسجيل الدخول باستخدام البريد الإلكتروني في خدمة "مصادقة Firebase"

يستخدم التطبيق الذي تنشئه Firebase Authentication للسماح للمستخدمين بتسجيل الدخول إلى تطبيقك، كما يسمح للمستخدمين الجدد بالتسجيل من تطبيق Flutter.

يجب تفعيل Firebase Authentication باستخدام "وحدة تحكّم Firebase"، ويجب إجراء إعدادات خاصة بعد التفعيل.

للسماح للمستخدمين بتسجيل الدخول إلى تطبيق الويب، عليك أولاً استخدام طريقة تسجيل الدخول البريد الإلكتروني/كلمة المرور. ستضيف طريقة تسجيل الدخول باستخدام حساب Google لاحقًا.

  1. في وحدة تحكّم Firebase، وسِّع قائمة إنشاء في اللوحة اليمنى.
  2. انقر على المصادقة، ثم على الزر البدء، ثم على علامة التبويب طريقة تسجيل الدخول (أو انتقِل مباشرةً إلى علامة التبويب طريقة تسجيل الدخول).
  3. انقر على البريد الإلكتروني/كلمة المرور في قائمة مزوّدو خدمة تسجيل الدخول، واضبط مفتاح تفعيل على وضع التشغيل، ثم انقر على حفظ.

58e3e3e23c2f16a4.png

3- إعداد تطبيق Flutter

عليك تنزيل رمز البداية وتثبيت واجهة سطر الأوامر (CLI) في Firebase قبل أن نبدأ.

الحصول على الرمز الأوّلي

استنسِخ مستودع GitHub من سطر الأوامر:

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

بدلاً من ذلك، إذا كانت أداة سطر الأوامر من GitHub مثبّتة:

gh repo clone flutter/codelabs flutter-codelabs

يجب استنساخ الرمز النموذجي في الدليل flutter-codelabs على جهازك، والذي يحتوي على الرمز الخاص بمجموعة من الدروس البرمجية. يتوفّر رمز هذا الدرس التطبيقي حول الترميز في الدليل الفرعي flutter-codelabs/firebase-auth-flutterfire-ui.

يحتوي الدليل flutter-codelabs/firebase-auth-flutterfire-ui على مشروعَين من مشاريع Flutter. أحدهما اسمه complete والآخر اسمه start. يحتوي الدليل start على مشروع غير مكتمل، وهو المكان الذي ستقضي فيه معظم الوقت.

cd flutter-codelabs/firebase-auth-flutterfire-ui/start

إذا أردت الانتقال إلى الأمام أو معرفة الشكل الذي يجب أن يبدو عليه شيء ما عند اكتماله، يمكنك الرجوع إلى الدليل المسمى "مكتمل" للتحقق من المراجع.

إذا أردت متابعة الدرس التطبيقي حول الترميز وإضافة الرمز بنفسك، عليك البدء بتطبيق Flutter على flutter-codelabs/firebase-auth-flutterfire-ui/start، وإضافة الرمز إلى هذا المشروع خلال الدرس التطبيقي حول الترميز. افتح هذا الدليل أو استورِده إلى بيئة التطوير المتكاملة (IDE) المفضّلة لديك.

تثبيت Firebase CLI

توفّر واجهة سطر الأوامر (CLI) في Firebase أدوات لإدارة مشاريعك على Firebase. يجب تثبيت واجهة سطر الأوامر لاستخدام FlutterFire CLI، وسنثبّتها بعد قليل.

تتوفّر مجموعة متنوعة من الطرق لتثبيت واجهة سطر الأوامر. راجِع جميع الخيارات المتاحة لنظام التشغيل على firebase.google.com/docs/cli.

بعد تثبيت واجهة سطر الأوامر، يجب إثبات ملكية حسابك على Firebase.

  1. سجِّل الدخول إلى Firebase باستخدام حسابك على Google من خلال تنفيذ الأمر التالي:
    firebase login
    
  2. يربط هذا الأمر جهازك المحلي بخدمة Firebase ويمنحك إذن الوصول إلى مشاريعك على Firebase.
  3. اختبِر تثبيت واجهة سطر الأوامر بشكلٍ صحيح وإمكانية وصولها إلى حسابك من خلال إدراج مشاريعك على Firebase. نفِّذ الأمر التالي:
    firebase projects:list
    
  4. يجب أن تكون القائمة المعروضة هي نفسها مشاريع Firebase المُدرَجة في وحدة تحكّم Firebase. يجب أن يظهر لك flutterfire-ui-codelab. على الأقل

تثبيت FlutterFire CLI

‫FlutterFire CLI هي أداة تساعد في تسهيل عملية تثبيت Firebase على جميع الأنظمة الأساسية المتوافقة في تطبيق Flutter، وهي تستند إلى Firebase CLI.

أولاً، ثبِّت واجهة سطر الأوامر:

dart pub global activate flutterfire_cli

تأكَّد من تثبيت واجهة سطر الأوامر. نفِّذ الأمر التالي وتأكَّد من أنّ واجهة سطر الأوامر تعرض قائمة المساعدة.

flutterfire --help

إضافة مشروع Firebase إلى تطبيق Flutter

ضبط FlutterFire

يمكنك استخدام FlutterFire لإنشاء رموز Dart البرمجية اللازمة لاستخدام Firebase في تطبيق Flutter.

flutterfire configure

عند تنفيذ هذا الأمر، سيُطلب منك اختيار مشروع Firebase الذي تريد استخدامه والمنصات التي تريد إعدادها.

تعرض لقطات الشاشة التالية الطلبات التي عليك الإجابة عنها.

  1. اختَر المشروع الذي تريد استخدامه. في هذه الحالة، استخدِم flutterfire-ui-codelab1359cdeb83204baa.png
  2. اختَر المنصات التي تريد استخدامها. في هذا الدرس العملي، هناك خطوات لإعداد خدمة "المصادقة في Firebase" على Flutter للويب وiOS وAndroid، ولكن يمكنك إعداد مشروعك على Firebase لاستخدام جميع الخيارات. 301c9534f594f472.png
  3. تعرض لقطة الشاشة هذه الناتج في نهاية العملية. إذا كنت على دراية بمنصة Firebase، ستلاحظ أنّه لم يكن عليك إنشاء تطبيقات على المنصات (مثل تطبيق Android) في وحدة التحكّم، وأنّ واجهة سطر الأوامر FlutterFire CLI قد نفّذت ذلك نيابةً عنك. 12199a85ade30459.png

بعد اكتمال ذلك، اطّلِع على تطبيق Flutter في محرّر النصوص. عدّل FlutterFire CLI ملفًا باسم firebase_options.dart. يحتوي هذا الملف على فئة باسم FirebaseOptions، تتضمّن متغيّرات ثابتة تحتوي على إعدادات Firebase اللازمة لكل نظام أساسي. إذا اخترت جميع المنصات عند تنفيذ flutterfire configure، ستظهر لك قيم ثابتة باسم web وandroid وios وmacos.

lib/firebase_options.dart

import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
    show defaultTargetPlatform, kIsWeb, TargetPlatform;

class DefaultFirebaseOptions {
  static FirebaseOptions get currentPlatform {
    if (kIsWeb) {
      return web;
    }

    switch (defaultTargetPlatform) {
      case TargetPlatform.android:
        return android;
      case TargetPlatform.iOS:
        return ios;
      case TargetPlatform.macOS:
        return macos;
      default:
        throw UnsupportedError(
          'DefaultFirebaseOptions are not supported for this platform.',
        );
    }
  }

  static const FirebaseOptions web = FirebaseOptions(
    apiKey: 'AIzaSyCqFjCV_9CZmYeIvcK9FVy4drmKUlSaIWY',
    appId: '1:963656261848:web:7219f7fca5fc70afb237ad',
    messagingSenderId: '963656261848',
    projectId: 'flutterfire-ui-codelab',
    authDomain: 'flutterfire-ui-codelab.firebaseapp.com',
    storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
    measurementId: 'G-DGF0CP099H',
  );

  static const FirebaseOptions android = FirebaseOptions(
    apiKey: 'AIzaSyDconZaCQpkxIJ5KQBF-3tEU0rxYsLkIe8',
    appId: '1:963656261848:android:c939ccc86ab2dcdbb237ad',
    messagingSenderId: '963656261848',
    projectId: 'flutterfire-ui-codelab',
    storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
  );

  static const FirebaseOptions ios = FirebaseOptions(
    apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
    appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
    messagingSenderId: '963656261848',
    projectId: 'flutterfire-ui-codelab',
    storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
    iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
    iosBundleId: 'com.example.complete',
  );

  static const FirebaseOptions macos = FirebaseOptions(
    apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
    appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
    messagingSenderId: '963656261848',
    projectId: 'flutterfire-ui-codelab',
    storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
    iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
    iosBundleId: 'com.example.complete',
  );
}

تستخدِم Firebase كلمة "تطبيق" للإشارة إلى إصدار معيّن لمنصة معيّنة في مشروع Firebase. على سبيل المثال، يحتوي مشروع Firebase الذي يُطلق عليه اسم FlutterFire-ui-codelab على تطبيقات متعددة: تطبيق واحد لنظام التشغيل Android، وتطبيق واحد لنظام التشغيل iOS، وتطبيق واحد لنظام التشغيل macOS، وتطبيق واحد للويب.

تستخدم الطريقة DefaultFirebaseOptions.currentPlatform التعداد TargetPlatform الذي يعرضه Flutter لرصد النظام الأساسي الذي يعمل عليه تطبيقك، ثم تعرض قيم إعدادات Firebase اللازمة لتطبيق Firebase الصحيح.

إضافة حِزم Firebase إلى تطبيق Flutter

تتمثّل خطوة الإعداد الأخيرة في إضافة حِزم Firebase ذات الصلة إلى مشروع Flutter. من المفترض أن يحتوي الملف firebase_options.dart على أخطاء، لأنّه يعتمد على حِزم Firebase التي لم تتم إضافتها بعد. في نافذة الوحدة الطرفية، تأكَّد من أنّك في جذر مشروع Flutter في flutter-codelabs/firebase-emulator-suite/start. بعد ذلك، شغِّل الأوامر الثلاثة التالية:

flutter pub add firebase_core firebase_auth firebase_ui_auth

هذه هي الحِزم الوحيدة التي تحتاج إليها في هذه المرحلة.

إعداد Firebase

لاستخدام الحِزم المُضافة، يجب DefaultFirebaseOptions.currentPlatform, تعديل الرمز في الدالة main في الملف main.dart.

lib/main.dart

import 'package:firebase_core/firebase_core.dart';                  // Add this import
import 'package:flutter/material.dart';

import 'app.dart';
import 'firebase_options.dart';                                     // And this import

// TODO(codelab user): Get API key
const clientId = 'YOUR_CLIENT_ID';

void main() async {
  // Add from here...
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  // To here.

  runApp(const MyApp(clientId: clientId));
}

يفعل هذا الرمز أمرين.

  1. يطلب WidgetsFlutterBinding.ensureInitialized() من Flutter عدم بدء تنفيذ رمز التطبيق المصغّر للتطبيق إلى أن يتم تشغيل إطار عمل Flutter بالكامل. تستخدم Firebase قنوات النظام الأساسي الأصلية التي تتطلّب تشغيل إطار العمل.
  2. تُنشئ Firebase.initializeApp اتصالاً بين تطبيق Flutter ومشروعك على Firebase. يتم استيراد DefaultFirebaseOptions.currentPlatform من ملف firebase_options.dart الذي تم إنشاؤه. تحدّد هذه القيمة الثابتة المنصّة التي تستخدمها، وتمرِّر مفاتيح Firebase المقابلة.

4. إضافة صفحة Firebase UI Auth الأولية

توفّر Firebase UI for Auth أدوات تمثّل شاشات كاملة في تطبيقك. تتعامل هذه الشاشات مع تدفّقات المصادقة المختلفة في جميع أنحاء تطبيقك، مثل "تسجيل الدخول" و"التسجيل" و"نسيت كلمة المرور" و"الملف الشخصي للمستخدم" وغير ذلك. للبدء، أضِف صفحة مقصودة إلى تطبيقك تعمل كحارس مصادقة للتطبيق الرئيسي.

تطبيق Material أو تطبيق Cupertino

تتطلّب واجهة مستخدم FlutterFire أن يكون تطبيقك مضمّنًا في MaterialApp أو CupertinoApp. استنادًا إلى اختيارك، ستعرض واجهة المستخدم تلقائيًا الاختلافات بين أدوات Material أو Cupertino. في هذا الدرس البرمجي، استخدِم MaterialApp، الذي تمت إضافته إلى التطبيق في app.dart.

lib/app.dart

import 'package:flutter/material.dart';

import 'auth_gate.dart';

class MyApp extends StatelessWidget {
  const MyApp({super.key, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: AuthGate(clientId: clientId),
    );
  }
}

التحقّق من حالة المصادقة

قبل عرض شاشة تسجيل الدخول، عليك تحديد ما إذا تم إثبات هوية المستخدم. الطريقة الأكثر شيوعًا للتحقّق من ذلك هي الاستماع إلى FirebaseAuth في authStateChanges باستخدام مكوّن Firebase Auth الإضافي.

في نموذج الرمز البرمجي أعلاه، ينشئ MaterialApp أداة AuthGate في طريقة build. (هذا تطبيق مصغّر مخصّص، وليس من FlutterFire UI).

يجب تحديث هذا التطبيق المصغّر لتضمين بث authStateChanges.

تعرض واجهة برمجة التطبيقات authStateChanges الرمز المميز Stream مع المستخدم الحالي (في حال تسجيل الدخول)، أو تعرض قيمة فارغة في حال عدم تسجيل الدخول. للاشتراك في هذه الحالة في تطبيقنا، يمكنك استخدام أداة StreamBuilder في Flutter وتمرير البث إليها.

StreamBuilder هي أداة تنشئ نفسها استنادًا إلى آخر لقطة للبيانات من مصدر بيانات تمرّره إليها. ويتم إعادة إنشائه تلقائيًا عندما ينبعث من Stream لقطة جديدة.

عدِّل الرمز في auth_gate.dart.

lib/auth_gate.dart

import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider; // Add this import
import 'package:firebase_ui_auth/firebase_ui_auth.dart';                  // And this import
import 'package:flutter/material.dart';

import 'home.dart';

class AuthGate extends StatelessWidget {
  const AuthGate({super.key, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(                                       // Modify from here...
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(providers: []);
        }

        return const HomeScreen();
      },
    );                                                                 // To here.
  }
}
  • يتم تمرير StreamBuilder.stream إلى FirebaseAuth.instance.authStateChanged، وهو البث المذكور أعلاه، والذي سيعرض عنصر User من Firebase إذا تمت مصادقة المستخدم، وإلا سيعرض null.
  • بعد ذلك، يستخدم الرمز snapshot.hasData للتحقّق مما إذا كانت القيمة من البث تحتوي على العنصر User.
  • إذا لم يكن هناك أي أداة، سيتم عرض أداة SignInScreen. في الوقت الحالي، لن تفعل هذه الشاشة أي شيء، وسيتم تعديلها في الخطوة التالية.
  • بخلاف ذلك، يعرض HomeScreen، وهو الجزء الرئيسي من التطبيق الذي يمكن للمستخدمين الذين تمّت مصادقتهم فقط الوصول إليه.

SignInScreen هو تطبيق مصغّر يأتي من حزمة FlutterFire UI. سيكون هذا هو محور الخطوة التالية من هذا الدرس العملي. عند تشغيل التطبيق في هذه المرحلة، من المفترض أن تظهر لك شاشة تسجيل دخول فارغة.

5- شاشة تسجيل الدخول

تضيف أداة SignInScreen، التي توفّرها حزمة FlutterFire UI، الوظائف التالية:

  • تسمح للمستخدمين بتسجيل الدخول
  • إذا نسي المستخدمون كلمة المرور، يمكنهم النقر على "هل نسيت كلمة المرور؟" وسيتم نقلهم إلى نموذج لإعادة ضبط كلمة المرور.
  • إذا لم يكن المستخدم مسجّلاً بعد، يمكنه النقر على "تسجيل"، وسيتم نقله إلى نموذج آخر يتيح له الاشتراك.

ومرة أخرى، لا يتطلّب ذلك سوى بضعة أسطر من الرمز البرمجي. استرجِع الرمز في الأداة AuthGate:

lib/auth_gate.dart

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

import 'home.dart';

class AuthGate extends StatelessWidget {
  const AuthGate({super.key, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(providers: [EmailAuthProvider()]);  // Modify this line
        }

        return const HomeScreen();
      },
    );
  }
}

إنّ الأداة SignInScreen والوسيطة providers هما الرمز الوحيد المطلوب للحصول على جميع الوظائف المذكورة أعلاه. من المفترض أن تظهر لك الآن شاشة تسجيل دخول تتضمّن حقلَي إدخال نص "البريد الإلكتروني" و"كلمة المرور"، بالإضافة إلى زر "تسجيل الدخول".

على الرغم من أنّها تعمل بشكل جيد، إلا أنّها تفتقر إلى التصميم. تعرض الأداة مَعلمات لتخصيص شكل شاشة تسجيل الدخول. على سبيل المثال، يمكنك إضافة شعار شركتك.

تخصيص شاشة تسجيل الدخول

headerBuilder

باستخدام الوسيطة SignInScreen.headerBuilder، يمكنك إضافة أي تطبيقات مصغّرة تريدها فوق نموذج تسجيل الدخول. لا يتم عرض هذه الأداة إلا على الشاشات الضيّقة، مثل الأجهزة الجوّالة. على الشاشات العريضة، يمكنك استخدام SignInScreen.sideBuilder، وهو ما سنتناوله لاحقًا في هذا الدرس العملي.

عدِّل ملف lib/auth_gate.dart باستخدام الرمز التالي:

lib/auth_gate.dart

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

import 'home.dart';

class AuthGate extends StatelessWidget {
  const AuthGate({super.key, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(                                         // Modify from here...
            providers: [EmailAuthProvider()],
            headerBuilder: (context, constraints, shrinkOffset) {
              return Padding(
                padding: const EdgeInsets.all(20),
                child: AspectRatio(
                  aspectRatio: 1,
                  child: Image.asset('assets/flutterfire_300x.png'),
                ),
              );
            },
          );                                                           // To here.
        }

        return const HomeScreen();
      },
    );
  }
}```

The headerBuilder argument requires a function of the type HeaderBuilder, which
is defined in the FlutterFire UI package.

```dart
typedef HeaderBuilder = Widget Function(
 BuildContext context,
 BoxConstraints constraints,
 double shrinkOffset,
);

بما أنّها دالة ردّ الاتصال، فإنّها تعرض قيمًا يمكنك استخدامها، مثل BuildContext وBoxConstraints، وتتطلّب منك عرض أداة. يظهر أي تطبيق مصغّر يتم إرجاعه في أعلى الشاشة. في هذا المثال، يضيف الرمز الجديد صورة إلى أعلى الشاشة. يجب أن يبدو تطبيقك الآن على النحو التالي.

73d7548d91bbd2ab.png

أداة إنشاء العناوين الفرعية

تعرض شاشة تسجيل الدخول ثلاث مَعلمات إضافية تتيح لك تخصيص الشاشة: subtitleBuilder وfooterBuilder وsideBuilder.

يختلف subtitleBuilder قليلاً من حيث أنّ وسيطات معاودة الاتصال تتضمّن إجراءً من النوع AuthAction. ‫AuthAction هو تعداد يمكنك استخدامه لرصد ما إذا كانت الشاشة التي يظهر عليها المستخدم هي شاشة "تسجيل الدخول" أو شاشة "التسجيل".

عدِّل الرمز في ملف auth_gate.dart لاستخدام subtitleBuilder.

lib/auth_gate.dart

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

import 'home.dart';

class AuthGate extends StatelessWidget {
  const AuthGate({super.key, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(
            providers: [EmailAuthProvider()],
            headerBuilder: (context, constraints, shrinkOffset) {
              return Padding(
                padding: const EdgeInsets.all(20),
                child: AspectRatio(
                  aspectRatio: 1,
                  child: Image.asset('assets/flutterfire_300x.png'),
                ),
              );
            },
            subtitleBuilder: (context, action) {                     // Add from here...
              return Padding(
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                child: action == AuthAction.signIn
                    ? const Text('Welcome to FlutterFire, please sign in!')
                    : const Text('Welcome to Flutterfire, please sign up!'),
              );
            },                                                       // To here.
          );
        }

        return const HomeScreen();
      },
    );
  }
}

الوسيطة footerBuilder هي نفسها الوسيطة subtitleBuilder. لا يعرض هذا الحقل BoxConstraints أو shrinkOffset، لأنّه مخصّص للنصوص وليس للصور. يمكنك بالطبع إضافة أي تطبيق مصغّر تريده.

أضِف تذييلاً إلى شاشة تسجيل الدخول باستخدام هذا الرمز.

lib/auth_gate.dart

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

import 'home.dart';

class AuthGate extends StatelessWidget {
  const AuthGate({super.key, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(
            providers: [EmailAuthProvider()],
            headerBuilder: (context, constraints, shrinkOffset) {
              return Padding(
                padding: const EdgeInsets.all(20),
                child: AspectRatio(
                  aspectRatio: 1,
                  child: Image.asset('assets/flutterfire_300x.png'),
                ),
              );
            },
            subtitleBuilder: (context, action) {
              return Padding(
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                child: action == AuthAction.signIn
                    ? const Text('Welcome to FlutterFire, please sign in!')
                    : const Text('Welcome to Flutterfire, please sign up!'),
              );
            },
            footerBuilder: (context, action) {                       // Add from here...
              return const Padding(
                padding: EdgeInsets.only(top: 16),
                child: Text(
                  'By signing in, you agree to our terms and conditions.',
                  style: TextStyle(color: Colors.grey),
                ),
              );
            },                                                       // To here.
          );
        }

        return const HomeScreen();
      },
    );
  }
}

Side Builder

تقبل وسيطة SignInScreen.sidebuilder رد اتصال، وتكون وسيطتا رد الاتصال هذه المرة BuildContext وdouble shrinkOffset. سيتم عرض الأداة التي تعرضها الدالة sideBuilder على يمين نموذج تسجيل الدخول، وذلك على الشاشات العريضة فقط. يعني ذلك أنّ الأداة لن يتم عرضها إلا على أجهزة الكمبيوتر المكتبي وتطبيقات الويب.

داخليًا، تستخدم حزمة FlutterFire UI نقطة توقّف لتحديد ما إذا كان يجب عرض محتوى العنوان (على الشاشات الطويلة، مثل الأجهزة الجوّالة) أو المحتوى الجانبي (على الشاشات العريضة، مثل أجهزة الكمبيوتر أو الويب). على وجه التحديد، إذا كان عرض الشاشة يزيد عن 800 بكسل، سيظهر محتوى الشريط الجانبي، ولن يظهر محتوى الرأس. إذا كان عرض الشاشة أقل من 800 بكسل، يكون العكس صحيحًا.

عدِّل الرمز في auth_gate.dart لإضافة عناصر واجهة مستخدم sideBuilder.

lib/auth_gate.dart

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

import 'home.dart';

class AuthGate extends StatelessWidget {
  const AuthGate({super.key, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(
            providers: [EmailAuthProvider()],
            headerBuilder: (context, constraints, shrinkOffset) {
              return Padding(
                padding: const EdgeInsets.all(20),
                child: AspectRatio(
                  aspectRatio: 1,
                  child: Image.asset('assets/flutterfire_300x.png'),
                ),
              );
            },
            subtitleBuilder: (context, action) {
              return Padding(
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                child: action == AuthAction.signIn
                    ? const Text('Welcome to FlutterFire, please sign in!')
                    : const Text('Welcome to Flutterfire, please sign up!'),
              );
            },
            footerBuilder: (context, action) {
              return const Padding(
                padding: EdgeInsets.only(top: 16),
                child: Text(
                  'By signing in, you agree to our terms and conditions.',
                  style: TextStyle(color: Colors.grey),
                ),
              );
            },
            sideBuilder: (context, shrinkOffset) {
              return Padding(
                padding: const EdgeInsets.all(20),
                child: AspectRatio(
                  aspectRatio: 1,
                  child: Image.asset('flutterfire_300x.png'),
                ),
              );
            },
          );
        }

        return const HomeScreen();
      },
    );
  }
}

من المفترض أن يظهر تطبيقك الآن على النحو التالي عند توسيع عرض النافذة (إذا كنت تستخدم Flutter على الويب أو نظام التشغيل macOS).

8dc60b4e5d7dd2d0.png

إنشاء مستخدم

في هذه المرحلة، يكون قد تم الانتهاء من جميع الرموز البرمجية لهذه الشاشة. قبل أن تتمكّن من تسجيل الدخول، عليك إنشاء مستخدم. يمكنك إجراء ذلك من خلال شاشة "التسجيل"، أو يمكنك إنشاء مستخدم في وحدة تحكّم Firebase.

لاستخدام وحدة التحكّم:

  1. انتقِل إلى جدول"المستخدمون" في وحدة تحكّم Firebase. اختَر flutterfire-ui-codelab أو مشروعًا آخر إذا كنت قد استخدمت اسمًا مختلفًا. سيظهر لك هذا الجدول: f038fd9a58ed60d9.png
  2. انقر على الزر "إضافة مستخدم". 2d78390d4c5dbbfa.png
  3. أدخِل عنوان بريد إلكتروني وكلمة مرور للمستخدم الجديد. يمكن أن يكون هذا عنوان بريد إلكتروني وكلمة مرور مزيفَين، كما هو موضّح في الصورة أدناه. سيكون ذلك ممكنًا، ولكن لن تعمل وظيفة "نسيت كلمة المرور" إذا استخدمت عنوان بريد إلكتروني مزيفًا. 62ba0feb33d54add.png
  4. انقر على "إضافة مستخدم" 32b236b3ef94d4c7.png.

يمكنك الآن الرجوع إلى تطبيق Flutter وتسجيل دخول المستخدم باستخدام صفحة تسجيل الدخول. يجب أن يبدو تطبيقك على النحو التالي:

dd43d260537f3b1a.png

6. شاشة الملف الشخصي

توفّر حزمة FlutterFire UI أيضًا أداة ProfileScreen، والتي تمنحك الكثير من الوظائف في بضعة أسطر من الرمز البرمجي.

إضافة تطبيق "ProfileScreen" المصغّر

انتقِل إلى ملف home.dart في محرِّر النصوص. عدِّله باستخدام الرمز التالي:

lib/home.dart

import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          IconButton(
            icon: const Icon(Icons.person),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute<ProfileScreen>(
                  builder: (context) => const ProfileScreen(),
                ),
              );
            },
          ),
        ],
        automaticallyImplyLeading: false,
      ),
      body: Center(
        child: Column(
          children: [
            SizedBox(width: 250, child: Image.asset('assets/dash.png')),
            Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
            const SignOutButton(),
          ],
        ),
      ),
    );
  }
}

رمز الملاحظة الجديد هو دالة معاودة الاتصال التي تم تمريرها إلى الطريقة IconButton.isPressed. عند الضغط على IconButton، ينشئ تطبيقك مسارًا مجهول الهوية جديدًا وينتقل إليه. سيعرض هذا المسار الأداة ProfileScreen التي يتم إرجاعها من معاودة الاتصال MaterialPageRoute.builder.

أعِد تحميل تطبيقك، وانقر على الرمز في أعلى اليسار (في شريط التطبيق)، وستظهر لك صفحة مثل هذه:

36487fc4ab4f26a7.png

هذه هي واجهة المستخدم العادية التي توفّرها صفحة FlutterFire UI. يتم ربط جميع الأزرار وحقول النص بخدمة Firebase Auth، وتعمل هذه الأزرار والحقول بدون أي إعدادات إضافية. على سبيل المثال، يمكنك إدخال اسم في حقل النص "الاسم"، وستستدعي حزمة FlutterFire UI الطريقة FirebaseAuth.instance.currentUser?.updateDisplayName التي ستحفظ هذا الاسم في Firebase.

تسجيل الخروج

في الوقت الحالي، إذا ضغطت على الزر "تسجيل الخروج"، لن يتغيّر التطبيق. سيتم تسجيل خروجك، ولكن لن تتم إعادة توجيهك إلى أداة AuthGate. لتنفيذ ذلك، استخدِم المَعلمة ProfileScreen.actions.

أولاً، عدِّل الرمز في ملف home.dart.

lib/home.dart

import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          IconButton(
            icon: const Icon(Icons.person),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute<ProfileScreen>(
                  builder: (context) => ProfileScreen(
                    actions: [
                      SignedOutAction((context) {
                        Navigator.of(context).pop();
                      }),
                    ],
                  ),
                ),
              );
            },
          ),
        ],
        automaticallyImplyLeading: false,
      ),
      body: Center(
        child: Column(
          children: [
            SizedBox(width: 250, child: Image.asset('assets/dash.png')),
            Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
            const SignOutButton(),
          ],
        ),
      ),
    );
  }
}

الآن، عند إنشاء مثيل من ProfileScreen، يمكنك أيضًا تمرير قائمة بالإجراءات إلى الوسيطة ProfileScreen.actions. تكون هذه الإجراءات من النوع FlutterFireUiAction. هناك العديد من الفئات المختلفة التي تمثّل أنواعًا فرعية من FlutterFireUiAction، وبشكل عام، يمكنك استخدامها لإخبار تطبيقك بالتفاعل مع تغييرات مختلفة في حالة المصادقة. يستدعي SignedOutAction دالة ردّ اتصال تقدّمها له عندما تتغير حالة مصادقة Firebase إلى أن يكون currentUser فارغًا.

من خلال إضافة دالة ردّ الاتصال التي تستدعي Navigator.of(context).pop() عند تشغيل SignedOutAction، سينتقل التطبيق إلى الصفحة السابقة. في هذا التطبيق النموذجي، لا يوجد سوى مسار دائم واحد يعرض شاشة "تسجيل الدخول" إذا لم يكن هناك مستخدم مسجّل الدخول، ويعرض الصفحة الرئيسية إذا كان هناك مستخدم مسجّل الدخول. وبما أنّ ذلك يحدث عند تسجيل خروج المستخدم، سيعرض التطبيق شاشة "تسجيل الدخول".

تخصيص صفحة الملف الشخصي

يمكن تخصيص صفحة الملف الشخصي، كما هو الحال مع شاشة "تسجيل الدخول". أولاً، لا يمكن الانتقال من الصفحة الحالية إلى الصفحة الرئيسية بعد أن ينتقل المستخدم إلى صفحة الملف الشخصي. يمكنك حلّ هذه المشكلة من خلال منح الأداة ProfileScreen شريط تطبيق.

lib/home.dart

import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          IconButton(
            icon: const Icon(Icons.person),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute<ProfileScreen>(
                  builder: (context) => ProfileScreen(
                    appBar: AppBar(title: const Text('User Profile')),
                    actions: [
                      SignedOutAction((context) {
                        Navigator.of(context).pop();
                      }),
                    ],
                  ),
                ),
              );
            },
          ),
        ],
        automaticallyImplyLeading: false,
      ),
      body: Center(
        child: Column(
          children: [
            SizedBox(width: 250, child: Image.asset('assets/dash.png')),
            Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
            const SignOutButton(),
          ],
        ),
      ),
    );
  }
}

يقبل الوسيط ProfileScreen.appBar عنصر واجهة مستخدم AppBar من حزمة Flutter Material، لذا يمكن التعامل معه مثل أي AppBar آخر أنشأته ومرّرته إلى Scaffold. في هذا المثال، يتم الاحتفاظ بالوظيفة التلقائية المتمثّلة في إضافة زر "رجوع" تلقائيًا، وأصبح للشاشة الآن عنوان.

إضافة أطفال إلى شاشة الملف الشخصي

يحتوي التطبيق المصغّر ProfileScreen أيضًا على وسيط اختياري باسم children. يقبل هذا الوسيط قائمة بالتطبيقات المصغّرة، وسيتم وضع هذه التطبيقات المصغّرة عموديًا داخل تطبيق مصغّر Column مستخدَم داخليًا لإنشاء ProfileScreen. سيؤدي عنصر واجهة المستخدم Column هذا في طريقة الإنشاء ProfileScreen إلى وضع العناصر الفرعية التي تمرّرها فوق الزر "تسجيل الخروج".

عدِّل الرمز في home.dart لعرض شعار الشركة هنا، على غرار شاشة "تسجيل الدخول".

lib/home.dart

import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          IconButton(
            icon: const Icon(Icons.person),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute<ProfileScreen>(
                  builder: (context) => ProfileScreen(
                    appBar: AppBar(title: const Text('User Profile')),
                    actions: [
                      SignedOutAction((context) {
                        Navigator.of(context).pop();
                      }),
                    ],
                    children: [
                      const Divider(),
                      Padding(
                        padding: const EdgeInsets.all(2),
                        child: AspectRatio(
                          aspectRatio: 1,
                          child: Image.asset('flutterfire_300x.png'),
                        ),
                      ),
                    ],
                  ),
                ),
              );
            },
          ),
        ],
        automaticallyImplyLeading: false,
      ),
      body: Center(
        child: Column(
          children: [
            SizedBox(width: 250, child: Image.asset('assets/dash.png')),
            Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
            const SignOutButton(),
          ],
        ),
      ),
    );
  }
}

أعِد تحميل تطبيقك، وسيظهر لك ما يلي على الشاشة:

ebe5792b765dbf87.png

7. تسجيل الدخول باستخدام ميزة "المصادقة من Google" على أجهزة متعدّدة

توفّر حزمة FlutterFire UI أيضًا أدوات ووظائف للمصادقة باستخدام مقدّمي خدمات تابعين لجهات خارجية، مثل Google وTwitter وFacebook وApple وGitHub.

للتكامل مع مصادقة Google، ثبِّت المكوّن الإضافي الرسمي firebase_ui_oauth_google والملفات التابعة له، والتي ستتعامل مع مسار المصادقة الأصلي. في الوحدة الطرفية، انتقِل إلى جذر مشروع Flutter وأدخِل الأمر التالي:

flutter pub add google_sign_in firebase_ui_oauth_google

تفعيل موفّر "تسجيل الدخول باستخدام حساب Google"

بعد ذلك، فعِّل موفّر Google في وحدة تحكّم Firebase باتّباع الخطوات التالية:

  1. انتقِل إلى شاشة مقدّمو خدمة تسجيل الدخول باستخدام المصادقة في وحدة التحكّم.
  2. انقر على "إضافة مقدّم خدمة جديد". 8286fb28be94bf30.png
  3. اختَر "Google". c4e28e6f4974be7f.png
  4. انقر على مفتاح التبديل بجانب "تفعيل"، ثم انقر على "حفظ". e74ff86990763826.png
  5. إذا ظهرت نافذة مشروطة تتضمّن معلومات حول تنزيل ملفات الإعداد، انقر على "تم".
  6. تأكَّد من إضافة موفّر خدمة تسجيل الدخول باستخدام Google. 5329ce0543c90d95.png

إضافة زر "تسجيل الدخول باستخدام حساب Google"

بعد تفعيل ميزة "تسجيل الدخول باستخدام حساب Google"، أضِف الأداة اللازمة لعرض زر أنيق لتسجيل الدخول باستخدام حساب Google على شاشة تسجيل الدخول. انتقِل إلى ملف auth_gate.dart وعدِّل الرمز إلى ما يلي:

lib/auth_gate.dart

import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart';  // Add this import
import 'package:flutter/material.dart';

import 'home.dart';

class AuthGate extends StatelessWidget {
  const AuthGate({super.key, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(
            providers: [
              EmailAuthProvider(),
              GoogleProvider(clientId: clientId),                         // Add this line
            ],
            headerBuilder: (context, constraints, shrinkOffset) {
              return Padding(
                padding: const EdgeInsets.all(20),
                child: AspectRatio(
                  aspectRatio: 1,
                  child: Image.asset('assets/flutterfire_300x.png'),
                ),
              );
            },
            subtitleBuilder: (context, action) {
              return Padding(
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                child: action == AuthAction.signIn
                    ? const Text('Welcome to FlutterFire, please sign in!')
                    : const Text('Welcome to Flutterfire, please sign up!'),
              );
            },
            footerBuilder: (context, action) {
              return const Padding(
                padding: EdgeInsets.only(top: 16),
                child: Text(
                  'By signing in, you agree to our terms and conditions.',
                  style: TextStyle(color: Colors.grey),
                ),
              );
            },
            sideBuilder: (context, shrinkOffset) {
              return Padding(
                padding: const EdgeInsets.all(20),
                child: AspectRatio(
                  aspectRatio: 1,
                  child: Image.asset('flutterfire_300x.png'),
                ),
              );
            },
          );
        }

        return const HomeScreen();
      },
    );
  }
}

الرمز الجديد الوحيد هنا هو إضافة GoogleProvider(clientId: "YOUR_WEBCLIENT_ID") إلى إعدادات الأداة SignInScreen.

بعد إضافة ذلك، أعِد تحميل تطبيقك وسيظهر لك زر تسجيل الدخول باستخدام حساب Google.

aca71a46a011bfb5.png

ضبط زر تسجيل الدخول

لا يعمل الزر بدون ضبط إعدادات إضافية. إذا كنت تستخدم Flutter Web، هذه هي الخطوة الوحيدة التي عليك اتّخاذها لكي يعمل هذا الإعداد. تتطلّب المنصات الأخرى خطوات إضافية، وسنتناولها بالتفصيل لاحقًا.

  1. انتقِل إلى صفحة "موفّرو المصادقة" في وحدة تحكّم Firebase.
  2. انقر على موفّر Google. 9b3a325c5eca6e49.png
  3. انقر على لوحة التوسيع "إعدادات حزمة تطوير البرامج (SDK) على الويب".
  4. انسخ القيمة من "معرّف عميل الويب". 711a79f0d931c60f.png
  5. ارجع إلى محرّر النصوص وعدِّل مثيل GoogleProvider في الملف auth_gate.dart من خلال تمرير رقم التعريف هذا إلى المَعلمة المسماة clientId.
GoogleProvider(
   clientId: "YOUR_WEBCLIENT_ID"
)

بعد إدخال معرّف عميل الويب، أعِد تحميل تطبيقك. وعند الضغط على الزر "تسجيل الدخول باستخدام حساب Google"، ستظهر نافذة جديدة إذا كنت تستخدم الويب، وستوجهك خلال عملية تسجيل الدخول باستخدام حساب Google. في البداية، يبدو على النحو التالي:

14e73e3c9de704bb.png

ضبط إعدادات iOS

ولكي تعمل هذه الميزة على أجهزة iOS، يجب إجراء عملية إعداد إضافية.

  1. انتقِل إلى شاشة "إعدادات المشروع" في وحدة تحكّم Firebase. ستظهر بطاقة تعرض تطبيقاتك على Firebase على النحو التالي: fefa674acbf213cc.png
  2. اختَر iOS. يُرجى العِلم أنّ اسم تطبيقك سيكون مختلفًا عن الاسم الظاهر في لقطة الشاشة. إذا كانت لقطة الشاشة تعرض "مكتمل"، سيظهر لك "بدء" إذا كنت قد استخدمت مشروع flutter-codelabs/firebase-auth-flutterfire-ui/start لمتابعة هذا الدرس البرمجي.
  3. انقر على الزر GoogleServices-Info.plist لتنزيل ملف الإعداد المطلوب. f89b3192871dfbe3.png
  4. اسحب الملف الذي تم تنزيله إلى الدليل المسمّى /ios/Runner في مشروع Flutter.
  5. افتح Xcode من خلال تنفيذ أمر الوحدة الطرفية التالي من جذر مشروعك: open ios/Runner.xcworkspace
  6. انقر بزر الماوس الأيمن على دليل Runner واختَر Add Files to "Runner" (إضافة ملفات إلى "Runner"). 858986063a4c5201.png
  7. انقر على GoogleService-Info.plist من مدير الملفات.
  8. في أداة تعديل النصوص (غير Xcode)، أضِف سمات CFBundleURLTypes أدناه إلى ملف ios/Runner/Info.plist.
    <!-- Put me in the [my_project]/ios/Runner/Info.plist file -->
    <!-- Google Sign-in Section -->
    <key>CFBundleURLTypes</key>
    <array>
      <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
          <!-- TODO Replace this value: -->
          <!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID -->
          <string>com.googleusercontent.apps.861823949799-vc35cprkp249096uujjn0vvnmcvjppkn</string>
        </array>
      </dict>
    </array>
    <!-- End of the Google Sign-in Section -->
    
  9. عليك استبدال GoogleProvider.clientId الذي أضفته في إعداد الويب بمعرّف العميل المرتبط بمعرّف عميل iOS في Firebase. أولاً، يمكنك العثور على هذا المعرّف في الملف firebase_options.dart، كجزء من الثابت iOS. انسخ القيمة التي تم تمريرها إلى iOSClientId.
    static const FirebaseOptions ios = FirebaseOptions(
      apiKey: 'YOUR API KEY',
      appId: 'YOUR APP ID',
      messagingSenderId: '',
      projectId: 'PROJECT_ID',
      storageBucket: 'PROJECT_ID.firebasestorage.app',
      iosClientId: 'IOS CLIENT ID', // Find your iOS client Id here.
      iosBundleId: 'com.example.BUNDLE',
    );
    
  10. ألصِق هذه القيمة في المتغيّر clientId في الملف lib/main.dart.

lib/main.dart

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

import 'app.dart';
import 'firebase_options.dart';

const clientId = 'YOUR_CLIENT_ID'; // Replace this value with your Client ID.

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);

  runApp(const MyApp(clientId: clientId));
}

إذا كان تطبيق Flutter يعمل على نظام التشغيل iOS، عليك إيقافه تمامًا ثم إعادة تشغيله. بخلاف ذلك، شغِّل التطبيق على جهاز iOS.

8. تهانينا!

لقد أكملت الدرس التطبيقي حول واجهة مستخدم Firebase Auth لتطبيق Flutter . يمكنك العثور على الرمز البرمجي المكتمل لهذا الدرس التطبيقي حول الترميز في الدليل firebase-auth-flutterfire-ui/complete على GitHub.

المواضيع التي تناولناها

  • إعداد تطبيق Flutter لاستخدام Firebase
  • إعداد مشروع Firebase في "وحدة تحكّم Firebase"
  • FlutterFire CLI
  • Firebase CLI
  • استخدام خدمة "مصادقة Firebase"
  • استخدام واجهة مستخدم FlutterFire للتعامل مع مصادقة Firebase في تطبيق Flutter

الخطوات التالية

مزيد من المعلومات

"سباركي" هنا للاحتفال معك!

2a0ad195769368b1.gif