المصادقة بإستخدام Firebase Auth و FlutterFire UI لتطبيقات Flutter

يوجد Package تحت التطوير يسهل العمل مع Firebase ويوفر العديد من Widgets الجاهزة للإستخام، المميز هو تحتاج القليل من الاسطر للتعامل معها وتخصيصها. الآ في مرحلة Beta يدعم Authentication وبعض خصائص Firestore. سنقوم في هذا الدرس بالتعامل مع كل مايخص المستخدم من تسجيل دخول وتسجيل حساب جديد بالإضافة الى العمل على تسجيل الدخول باستخدام حساب Google او ورقم الجوال.

👩🏻‍💻 إضافة FlutterFire UI الى المشروع.

اولًا نحتاج الى إضافة package المسؤول عن UI وهو FlutterFire ويمكن القيام بذلك بكتابة هذا السطر في Terminal.

flutter pub add flutterfire_ui
👨🏻‍💼 1. تسجيل مستخدم جديد وتسجيل الدخول.

سنقوم بإضافة تسجيل مستخم جديد وايضًا صفحة تسجيل دخول. يمكن تحقيق ذلك ببساطة بكتابة Widget مرفقة مع Package تقوم بهذه المهمة.

بداية تحتاج الى اضافة Firebase Authentication الى تطبيقك.عن طريق Terminal او كتابة مباشرة في pubspec.yaml.

عن طريق Command Line
flutter pub add firebase_auth
عن طريق ملف pubspec.yaml
dependencies:
  flutter:
    sdk: flutter

....
  ....
  firebase_auth: ^3.11.2
👮🏻‍♀️ التحقق من المصادقة.

الآن نريد ان نتحقق هل المستخدم مسجل دخول في التطبيق سابقًا؟ هل يحتاج الي تسجيل دخول ام يحتاج الى حساب جديد! سنقوم بالتحقيق باستخدام إحدي الدوال التي يقدمها Package firebase_auth. حتى يكون التطبيق أكثر وضوح سنقوم بانشاء Widget جديد بإسم AuthGate للتحقق. هذا الرسم التوضيحي يعطي فكرة بسيط عن طريقة التحقق في تطبيقنا البسيط.

import 'package:firebase_auth/firebase_auth.dart';

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

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        // ...
      },
    );
  }
}

الآن سنقوم بالتحقق عن طريق هل stream يوجد في بيانات أم لا! اذا كان هناك بيانات سنقوم بتحويل المستخدم الى الشاشة الرئيسية. أما اذا كانت البيانات فارغة او بالأصح لايوجد بيانات سنقوم بتوجيه المستخدم الى الشاشة الخاصة بتسجيل الدخول او إنشاء حساب!

return StreamBuilder<User?>(
  stream: FirebaseAuth.instance.authStateChanges(),
  builder: (context, snapshot) {
    // User is not signed in
    if (!snapshot.hasData) {
      // ...
    }

    // Render your application if authenticated
    return YourApplication();
  },
);
🧗🏻‍♂️ تجهيز شاشة تسجيل الدخول.

الآن في حالة عدم وجود البيانات او المستخدم غير مصرح سنقوم بتحويله الى شاشة تسجيل الدخول وسيكون الكود بالشكل التالي.

return StreamBuilder<User?>(
  stream: FirebaseAuth.instance.authStateChanges(),
  // If the user is already signed-in, use it as initial data
  initialData: FirebaseAuth.instance.currentUser,
  builder: (context, snapshot) {
    // User is not signed in
    if (!snapshot.hasData) {
      return SignInScreen(
        providerConfigs: []
      );
    }

    // Render your application if authenticated
    return YourApplication();
  },
);

عند تشغيل التطبيق الآن بالطبع سيكون شاشة فارغة لايوجد أي مكان تستطيع كتابة بيانات المستخدم فيه او بوابة أخرى لتسجيل الدخول! إذًا مالعمل؟ يوجد مايمسى بـproviderConfigs بحيث يكون هو المسؤول عن كيفية تحكمك في التطبيق. هل تريد فقط ان يقوم المستخدم بتسجيل الدخول فقط بالايميل والباسوورد؟ ام تريد ان يستخدم بوابة أخرى مثل تسجيل الدخول عن طريق قوقل؟

💌 إضافة خاصية التسجيل بإستخدام الايميل والباسوورد.

سنقوم بإضافة سطر واحد فقط وسيقوم بإضافة خاصية تسجيل الدخول بحيث يصبح شكل شاشة SignInScreen بالشكل التالي

return SignInScreen(
  providerConfigs: [
    EmailProviderConfiguration(),
  ],
);

الآن عند تشغيل التطبيق ستلاحظ ان اصبح مكان لكتابة الإيميل والباسوورد.

التطبيق بعد التشغيل

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


☀️ اضافة Google Sign In.

هنا مثال لطريقة اضافة Google تستطيع استخدام العديد من الخدمات الأخرى كما في الصورة التالية.

جميع الخدمات التي يمكن تسجيل الدخول بها الى تطبيق عن طريق Firebase.

الآن نحتاج اولًا الى إضافة package تسجيل الدخول عن طريق google، نفس طريقة اضافة الـpackage لك الرختيار من Terminal او من pubspec.yaml.

  • من الـterminal
flutter pub add google_sign_in
  • من pubspec.yaml
dependencies:
  google_sign_in: ^5.4.2

الان سنقوم بتفعيل تسجيل الدخول باستخدام google من Firebase Console

من الخيار الثاني قم بإختيار ايميلك المراد الوبط معه. الآن نعود الى الكود وتقوم باضافة googlesignin الى الـproviderConfigs. وسيكون شكل الكود لدينا كالتالي.

return SignInScreen(providerConfigs: [
                EmailProviderConfiguration(),
                GoogleProviderConfiguration(
                  clientId: '...',
                ),
              ]);

عند تشغيل التطبيق ستلاحظ وجود خيار تسجيل الدخول عن طريق Google.

شاشة التطبيق بعد إضافة Google

📱 تخصيص الواجهات.

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

تغيير ترتيب تسجيل الدخول.

اذا اردت ان يكون مثلًا تسجيل الدخول عن طريق google هو الاول بعد ذلك مربعات نص الايميل والباسوورد. تستطيع ذلك من خلال ترتيب providerConfigs .

تسجيل الدخول عن طريق Google اصبح يسبق Emai/pasword
اضافة رأس الصفحة.

اذا اردت اضافة شعار لتطبيقك او إسم مخصص يمكنك ذلك عن طريق headerBuilder بحيث تضع داخله نص او صورة او أي شئ يخص تطبيقك٫ سنقوم بإضافة شعار تطبيق بسيط على حسب ذوقي والله يعينك.

return SignInScreen(
                  headerBuilder: (context, constraints, _) {
                    return const Padding(
                      padding: EdgeInsets.all(20),
                      child: AspectRatio(
                        aspectRatio: 1,
                        child: FlutterLogo(
                          size: 200,
                        ),
                      ),
                    );
                  },
                  providerConfigs: [
                    const GoogleProviderConfiguration(
                      clientId: '...',
                    ),
                    const EmailProviderConfiguration(),
                  ]);
تعديل رأس الصفحة
تعديل الصفحة الجانبية (تطبيقات سطح المكتب)

بحكم حجم تطبيقات سطح المكتب من الصعب وضع رأس للصفحة.الافضل هو اضافة الشعار على جانب الصفحة، ولهذا نحتاج اضافة sideBuilder بحيث يكون سهل وارتب للصفحة

return SignInScreen(
                  sideBuilder: (context, constraints) {
                    return const Padding(
                      padding: EdgeInsets.all(20),
                      child: AspectRatio(
                        aspectRatio: 1,
                        child: FlutterLogo(
                          size: 200,
                        ),
                      ),
                    );
                  },
                  headerBuilder: (context, constraints, _) {
                    return const Padding(
                      padding: EdgeInsets.all(20),
                      child: AspectRatio(
                        aspectRatio: 1,
                        child: FlutterLogo(
                          size: 200,
                        ),
                      ),
                    );
                  },
                  providerConfigs: [
                    const GoogleProviderConfiguration(
                      clientId: '...',
                    ),
                    const EmailProviderConfiguration(),
                  ]);

اضافة نصوص توضيحية.

سنقوم بإضافة نصوص توضيحية للمستخدم، يمكنك اضافة صور ايضا، سنقوم بتنبيه المستخدم في حال انه موجود في صفحة الدخول سنقوم له من فضلك سجل دخول للبدء اما اذا كان في صفحة تسجيل حساب جديد سنقوم بكتابة من فضلك قم برنشاء حساب جديد للبدء، ايضا في اسفل الصفحة سنقوم بإضافة شروط الإستخدام مثلا.

return SignInScreen(
                  subtitleBuilder: (context, action) {
                    return Padding(
                      padding: const EdgeInsets.only(bottom: 8),
                      child: Text(
                        action == AuthAction.signIn
                            ? 'Welcome to FlutterFire UI! Please sign in to continue.'
                            : 'Welcome to FlutterFire UI! Please create an account to continue',
                      ),
                    );
                  },
                  footerBuilder: (context, _) {
                    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, constraints) {
                    return const Padding(
                      padding: EdgeInsets.all(20),
                      child: AspectRatio(
                        aspectRatio: 1,
                        child: FlutterLogo(
                          size: 200,
                        ),
                      ),
                    );
                  },
                  headerBuilder: (context, constraints, _) {
                    return const Padding(
                      padding: EdgeInsets.all(20),
                      child: AspectRatio(
                        aspectRatio: 1,
                        child: FlutterLogo(
                          size: 200,
                        ),
                      ),
                    );
                  },
                  providerConfigs: [
                    const GoogleProviderConfiguration(
                      clientId: '...',
                    ),
                    const EmailProviderConfiguration(),
                  ]);
نلاحظ وجود رسائل في أعلى الصفحة وفي تذييل الصفحة.
الغاء الانتقال.

اذا اردت الغاء انتقال المستخدم لتسجيل حساب جديد، وتريد ادزارة ذلك بنفسك لجمع معلومات اضافية يمكنك ذلك من خلال خاصية showAuthActionSwitch وتغيير قيمتها الى false.

return SignInScreen(
  showAuthActionSwitch: false,
  // ...
);

📄 صفحات اضافية.

صفحة تسجيل حساب جديد.

يتوفر في FlutterFire صفحات اضافية مثل تسجيل حساب جديد وأيضا صفحة حساب المستخدم لتعديل ايميلة او تفعيل حسابه، يمكن التعامل معها بنفس طريقة التعامل مع صفحة SiginScreen.

return RegisterScreen(
  providerConfigs: [
    EmailProviderConfiguration(),
    GoogleProviderConfiguration(
      clientId: '...',
    ),
  ],
  // ...
);
نسيت كلمة المرور.

شاشة تتيح للمستخدم استعادة كلمة المرور.

return ForgotPasswordScreen(
  headerBuilder: (context, constraints, shrinkOffset) {
    return Padding(
      padding: const EdgeInsets.all(20).copyWith(top: 40),
      child: Icon(
        Icons.lock,
        color: Colors.blue,
        size: constraints.maxWidth / 4 * (1 - shrinkOffset),
      ),
    );
  },
);
الحساب الشخصي.

شاشة تتيع للمستخدم تعديل اسمه، او حذف الحساب الخاص به من التطبيق.

return ProfileScreen(
  providerConfigs: [
    EmailProviderConfiguration(),
    GoogleProviderConfiguration(
      clientId: '...',
    ),
    FacebookProviderConfiguration(
      clientId: '...',
    ),
    TwitterProviderConfiguration(
      clientId: '...',
    ),
    AppleProviderConfiguration(),
  ],
  avatarSize: 24,
);

🌍 تغيير اللغة

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


class LabelOverrides extends DefaultLocalizations {
  const LabelOverrides();

  @override
  String get emailInputLabel => 'اكتب البريد الإلكتروني';

  @override
  String get passwordInputLabel => 'اكتب كلمة المرور';

  @override
  String get signInButtonText => 'تسجيل الدخول';

  @override
  String get registerActionText => 'تسجيل';

  @override
  String get registerButtonText => 'تسجيل';

  @override
  String get signInActionText => 'تسجيل الدخول';

  @override
  String get forgotPasswordButtonLabel => 'إعادة تعيين كلمة المرور';

  @override
  String get signInWithGoogleButtonText => 'تسجيل الدخول بحساب جوجل';

  @override
  String get signInText => 'تسجيل الدخول';

  @override
  String get registerText => 'تسجيل';

  @override
  String get registerHintText => 'ليس لديك حساب؟';

  @override
  String get signInHintText => 'لديك حساب؟';

  @override
  String get forgotPasswordHintText => 'نسيت كلمة المرور؟';

  @override
  String get confirmPasswordInputLabel => 'تأكيد كلمة المرور';

  @override
  String get goBackButtonLabel => 'رجوع';

  @override
  String get resetPasswordButtonLabel => 'إعادة تعيين كلمة المرور';

  @override
  String get forgotPasswordViewTitle => 'إعادة تعيين كلمة المرور';
}

الآن سنقوم بتعديل MaterialApp واضافة التعديلا التي قمنا بها ليصبح بهذا الشكل.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: [
        // Creates an instance of FirebaseUILocalizationDelegate with overridden labels
        FlutterFireUILocalizations.withDefaultOverrides(const LabelOverrides()),
        
        // Delegates below take care of built-in flutter widgets
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,

        // This delegate is required to provide the labels that are not overridden by LabelOverrides
        FlutterFireUILocalizations.delegate,
      ],
      // ...
    );
  }
}

عند تشغيل التطبيق ستلاحظ تغير اللغة لكل النصوص التي عدلتها سابقًا.

اللغة العربية في التطبيق

⚠️ لا تقم بكتابة اللغة العربية أو أي لغة في التطبيق في الكود مباشرة. ابحث عن طريقة جعل التطبيق متعدد اللغات او عن Localization٫

🌈 النمط والألوان

اذا عرفت ان Flutter عبارة عن Widgets فجميع مايظهر في الشاشة قابل للتعديل والتخصيص. يمكنك تعديل جميع اشكال الأزرار ومربعات النص في تطبيقك بشكل كامل في جميع الشاشات عن طريق تعديل theme في MaterialApp بدون القيام بتكرار نفسك في كل صفحة.

  • سنقوم أولا بتعديل الأزرار.
 return MaterialApp(
...
.....
      theme: ThemeData(
          primarySwatch: generateMaterialColor(color: const Color(0xff6a5ae0)),
          outlinedButtonTheme: OutlinedButtonThemeData(
              style: ButtonStyle(
                  padding: MaterialStateProperty.all<EdgeInsets>(
                    const EdgeInsets.all(8),
                  ),
                  textStyle: MaterialStateProperty.all<TextStyle>(
                    const TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  foregroundColor:
                      MaterialStateProperty.all<Color>(const Color(0xffffffff)),
                  backgroundColor:
                      MaterialStateProperty.all<Color>(const Color(0xff6a5ae0)),
                  shape: MaterialStateProperty.all<OutlinedBorder>(
                    RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(50),
                    ),
                  )))),
   
    );
تغيير التصميم الخاص بالزر
  • تعديل مربعات النص

يمكن تعديل مربعات النص كما فعلنا سابقًا مع Buttons وذلك بتعديل التصميم الخاص InputField

 return MaterialApp(
        theme: ThemeData(
          inputDecorationTheme: InputDecorationTheme(
            border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(20),
            ),
          ),
          primarySwatch: generateMaterialColor(color: const Color(0xff6a5ae0)),
          
    );

الخاتمة 💆🏻‍♂️

يوجد العديد من المميزات، بالإضافة انها مازالت في نسخة Beta والتحديث عليها مستمر. يمكنك الإطلاع على Docs الخاص بها ومشاهدة المزيد من التخصيص والخيارات بالإضافة الى إمكانية اضافة Flow الخاص بك للتطبيق.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *