إنشاء تطبيق Android باستخدام Firebase وJetpack Compose

1- مقدمة

تاريخ آخر تعديل: 16‏/11‏/2022

إنشاء تطبيق Android باستخدام Firebase وJetpack Compose

في هذا الدرس التطبيقي حول الترميز، ستنشئ تطبيق Android باسم Make It So. تم إنشاء واجهة المستخدم لهذا التطبيق بالكامل باستخدام Jetpack Compose، وهي مجموعة أدوات حديثة من Android لإنشاء واجهة مستخدم أصلية. إنّها بسيطة وتتطلب رمزًا برمجيًا أقل من كتابة ملفات .xml وربطها بالأنشطة أو الأجزاء أو طرق العرض.

إنّ الخطوة الأولى لفهم مدى كفاءة عمل Firebase وJetpack Compose معًا هي فهم بنية Android الحديثة. تجعل البنية الجيدة النظام سهل الفهم والتطوير والصيانة، لأنّها توضّح بوضوح كيفية تنظيم المكوّنات والتواصل مع بعضها. وفي عالم Android، يُطلق على البنية المقترَحة النموذج - View - ViewModel. يمثل النموذج الطبقة التي تصل إلى "البيانات" في التطبيق. العرض هو طبقة واجهة المستخدم، ومن المفترض ألا يعرف أي شيء عن منطق الأنشطة التجارية. وViewModel هو المكان الذي يتم فيه تطبيق منطق الأنشطة التجارية، والذي يتطلب أحيانًا استخدام ViewModel لاستدعاء طبقة النموذج.

ننصحك بشدة بقراءة هذه المقالة لفهم كيفية تطبيق النموذج - العرض - نموذج العرض على تطبيق Android تم إنشاؤه باستخدام Jetpack Compose، لأنّ ذلك سيسهّل فهم قاعدة البيانات وإكمال الخطوات التالية.

التطبيق الذي ستصممه

Make It So هو تطبيق بسيط لقائمة المهام يتيح للمستخدم إضافة المهام وتعديلها وإضافة علامات وأولويات وتواريخ استحقاق ووضع علامة على المهام كمكتملة. تعرض الصور أدناه الصفحتَين الرئيسيتَين لهذا التطبيق: صفحة إنشاء المهام والصفحة الرئيسية التي تتضمّن قائمة بالمهام التي تم إنشاؤها.

شاشة "إضافة مهمة" الضبط على الشاشة الرئيسية

ستضيف بعض الميزات غير المتوفّرة في هذا التطبيق:

  • مصادقة المستخدمين باستخدام البريد الإلكتروني وكلمة المرور
  • يمكنك إضافة أداة استماع إلى مجموعة Firestore وجعل واجهة المستخدم تتفاعل مع التغييرات
  • إضافة آثار الأنشطة المخصَّصة لمراقبة أداء رمز معيّن في التطبيق
  • يمكنك تفعيل ميزة "الإعداد عن بُعد" واستخدام ميزة "الطرح على مراحل" لإطلاقها.

المعلومات التي ستطّلع عليها

  • كيفية استخدام مصادقة Firebase ومراقبة الأداء والإعداد عن بُعد وCloud Firestore في تطبيق Android عصري
  • كيفية جعل واجهات برمجة تطبيقات Firebase تناسب بنية MVVM
  • كيفية إظهار التغييرات التي تم إجراؤها باستخدام واجهات برمجة تطبيقات Firebase في واجهة مستخدم Compose

المتطلبات

  • استوديو Android Flamingo+
  • محاكي Android الذي يحتوي على واجهة برمجة التطبيقات 21 أو الإصدارات الأحدث
  • الإلمام بلغة البرمجة Kotlin

2- الحصول على نموذج التطبيق وإعداد Firebase

الحصول على رمز نموذج التطبيق

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

git clone https://github.com/FirebaseExtended/make-it-so-android.git

إنشاء مشروع على Firebase

عليك أولاً الانتقال إلى وحدة تحكُّم Firebase وإنشاء مشروع في Firebase من خلال النقر على الزر "+ إضافة مشروع"، كما هو موضّح أدناه:

وحدة تحكُّم Firebase

اتبع الخطوات التي تظهر على الشاشة لإكمال إنشاء المشروع.

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

في مشروعك على Firebase، يمكنك تسجيل تطبيقات مختلفة: لنظامَي التشغيل Android وiOS والويب وFlutter وUnity.

اختَر خيار Android، كما هو موضّح هنا:

نظرة عامة على مشروع Firebase

بعد ذلك، اتبع الخطوات التالية:

  1. أدخِل com.example.makeitso كاسم الحزمة، ويمكنك إدخال لقب إذا أردت. في هذا الدليل التعليمي حول الرموز البرمجية، لا تحتاج إلى إضافة شهادة التوقيع لتصحيح الأخطاء.
  2. انقر على التالي لتسجيل تطبيقك والوصول إلى ملف إعداد Firebase.
  3. انقر على تنزيل google-services.json لتنزيل ملف الإعدادات وحفظه في الدليل make-it-so-android/app.
  4. انقر على التالي. بما أنّ حِزم تطوير البرامج (SDK) لمنصة Firebase مضمّنة حاليًا في ملف build.gradle في نموذج المشروع، انقر على التالي للانتقال إلى الخطوات التالية.
  5. انقر على متابعة إلى وحدة التحكّم لإنهاء العملية.

لكي يعمل تطبيق Make it So بشكل صحيح، عليك تنفيذ أمرَين في وحدة التحكّم قبل الانتقال إلى الرمز البرمجي: تفعيل مقدّمي المصادقة وإنشاء قاعدة بيانات Firestore.

إعداد المصادقة

أولاً، يجب تفعيل المصادقة ليتمكّن المستخدمون من تسجيل الدخول إلى التطبيق:

  1. من قائمة إنشاء، اختَر المصادقة، ثم انقر على البدء.
  2. من بطاقة طريقة تسجيل الدخول، اختَر البريد الإلكتروني/كلمة المرور وفعِّلها.
  3. بعد ذلك، انقر على إضافة مقدّم خدمة جديد واختَر غير محدّد وفعِّله.

إعداد Cloud Firestore

بعد ذلك، عليك إعداد Firestore. ستستخدم Firestore لتخزين مهام المستخدم الذي سجّل الدخول. سيحصل كل مستخدم على مستند خاص به ضمن مجموعة من قاعدة البيانات.

  1. في اللوحة اليمنى من "وحدة تحكُّم Firebase"، وسِّع إنشاء، ثم اختَر قاعدة بيانات Firestore.
  2. انقر على إنشاء قاعدة بيانات.
  3. اترك معرّف قاعدة البيانات مضبوطًا على (default).
  4. اختَر موقعًا لقاعدة بياناتك، ثم انقر على التالي.
    بالنسبة إلى التطبيق الحقيقي، عليك اختيار موقع قريب من المستخدمين.
  5. انقر على البدء في وضع الاختبار. اقرأ بيان إخلاء المسؤولية عن قواعد الأمان.
    في الخطوات التالية من هذا القسم، ستضيف قواعد أمان لتأمين بياناتك. لا توزِّع تطبيقًا أو تعرضه علنًا بدون إضافة قواعد أمان لقاعدة البيانات.
  6. انقر على إنشاء.

لنخصّص بعض الوقت لإنشاء قواعد أمان قوية في قاعدة بيانات Firestore.

  1. افتح لوحة بيانات Firestore وانتقِل إلى علامة التبويب القواعد.
  2. حدِّث "قواعد الأمان" لتبدو كالتالي:
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow create: if request.auth != null;
      allow read, update, delete: if request.auth != null && resource.data.userId == request.auth.uid;
    }
  }
}

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

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

أنت الآن جاهز لتشغيل التطبيق! افتح مجلد make-it-so-android/start في Android Studio وشغِّل التطبيق (يمكن إجراء ذلك باستخدام محاكي Android أو جهاز Android حقيقي).

3- مصادقة Firebase

ما هي الميزة التي ستضيفها؟

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

حان وقت الترميز

بعد أن ينشئ المستخدم حسابًا، ومن خلال كتابة عنوان بريد إلكتروني وكلمة مرور، ستحتاج إلى طلب بيانات اعتماد البريد الإلكتروني من Firebase Authentication API، ثم ربط بيانات الاعتماد الجديدة بالحساب المجهول. افتح ملف AccountServiceImpl.kt في "استوديو Android" وعدِّل الدالة linkAccount لتظهر على النحو التالي:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String) {
    val credential = EmailAuthProvider.getCredential(email, password)
    auth.currentUser!!.linkWithCredential(credential).await()
}

افتح الآن SignUpViewModel.kt واستدعِ الدالة linkAccount داخل المجموعة launchCatching من الدالة onSignUpClick:

screens/sign_up/SignUpViewModel.kt

launchCatching {
    accountService.linkAccount(email, password)
    openAndPopUp(SETTINGS_SCREEN, SIGN_UP_SCREEN)
}

يحاول أولاً المصادقة، وإذا نجحت المكالمة، ينتقل إلى الشاشة التالية (SettingsScreen). أثناء تنفيذ هذه المكالمات داخل كتلة launchCatching، إذا حدث خطأ في السطر الأول، سيتمّ رصد الاستثناء ومعالجته، ولن يتمّ الوصول إلى السطر الثاني على الإطلاق.

بعد فتح SettingsScreen مرة أخرى، عليك التأكّد من أنّ خيارَي تسجيل الدخول وإنشاء حساب قد اختفيا، لأنّه تمّت مصادقة المستخدم الآن. لإجراء ذلك، سيتم السماح لـ SettingsViewModel بالاستماع إلى حالة المستخدم الحالي (المتوفّرة في AccountService.kt)، وذلك للتحقّق مما إذا كان الحساب مجهول الهوية أو لا. لإجراء ذلك، يجب تعديل "uiState" في "SettingsViewModel.kt" ليبدو كالتالي:

screen/settings/SettingsViewModel.kt

val uiState = accountService.currentUser.map {
    SettingsUiState(it.isAnonymous)
}

آخر إجراء عليك فعله هو تعديل uiState في SettingsScreen.kt لجمع الحالات الصادرة عن SettingsViewModel:

screen/settings/Settingsscreen.kt

val uiState by viewModel.uiState.collectAsState(
    initial = SettingsUiState(false)
)

والآن في كل مرة يجري فيها المستخدم أي تغيير، سيُعاد إنشاء SettingsScreen تلقائيًا لعرض الخيارات وفقًا لحالة المصادقة الجديدة للمستخدم.

حان وقت الاختبار.

شغِّل Make it So وانتقِل إلى الإعدادات بالنقر على رمز الترس في أعلى يسار الشاشة. من هناك، انقر على خيار إنشاء الحساب:

شاشة إعدادات "جعلها تعمل" شاشة الاشتراك في Make it So

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

4. Cloud Firestore

ما هي الميزة التي ستتم إضافتها؟

بالنسبة إلى Cloud Firestore، ستضيف مستمعًا إلى مجموعة Firestore التي تخزِّن المستندات التي تمثّل المهام المعروضة في Make it So. بعد إضافة هذا المستمع، ستتلقّى كل تعديل يتم إجراؤه على هذه المجموعة.

حان وقت الترميز

عدِّل Flow المتاح في StorageServiceImpl.kt ليصبح على النحو التالي:

model/service/impl/StorageServiceImpl.kt

override val tasks: Flow<List<Task>>
    get() =
      auth.currentUser.flatMapLatest { user ->
        firestore.collection(TASK_COLLECTION).whereEqualTo(USER_ID_FIELD, user.id).dataObjects()
      }

تضيف هذه التعليمة البرمجية مستمعًا إلى مجموعة المهام استنادًا إلى user.id. يتم تمثيل كل مهمة من خلال مستند في مجموعة باسم tasks، ويحتوي كل مستند على حقل باسم userId. يُرجى العِلم أنّه سيتم إصدار Flow جديد إذا تغيّرت حالة currentUser (عن طريق تسجيل الخروج، على سبيل المثال).

عليك الآن جعل Flow في TasksViewModel.kt تظهر كما هي في الخدمة:

screens/tasks/TasksViewModel.kt

val tasks = storageService.tasks

وسيكون الإجراء الأخير هو جعل composable function في TasksScreens.kt، الذي يمثّل واجهة المستخدم، على دراية بهذا المسار وجمعه كحالة. وفي كل مرة تتغير فيها الحالة، ستعيد الدالة القابلة للإنشاء إنشاء نفسها تلقائيًا وتعرض أحدث حالة للمستخدم. إضافة هذا إلى TasksScreen composable function:

screens/tasks/TasksScreen.kt

val tasks = viewModel
    .tasks
    .collectAsStateWithLifecycle(emptyList())

بعد منح الدالة القابلة للإنشاء إذن الوصول إلى هذه الحالات، يمكنك تعديل LazyColumn (وهي البنية التي تستخدمها لعرض قائمة على الشاشة) لتظهر على النحو التالي:

screen/tasks/Tasksscreen.kt

LazyColumn {
    items(tasks.value, key = { it.id }) { taskItem ->
        TaskItem( [...] )
    }
}

حان وقت الاختبار.

من أجل اختبار نجاحها، أضف مهمة جديدة باستخدام التطبيق (بالنقر على زر الإضافة في أسفل يسار الشاشة). بعد الانتهاء من إنشاء المهمة، من المفترض أن تظهر في مجموعة Firestore في وحدة تحكّم Firestore. إذا سجّلت الدخول إلى تطبيق Make it So على أجهزة أخرى باستخدام الحساب نفسه، ستتمكّن من تعديل المهام ومتابعة تعديلها على جميع الأجهزة في الوقت الفعلي.

5- مراقبة الأداء

ما هي الميزة التي ستضيفها؟

يُعدّ الأداء أمرًا مهمًا جدًا يجب الانتباه إليه لأنّه من المرجّح أن يتوقف المستخدمون عن استخدام تطبيقك إذا لم يكن الأداء جيدًا واستغرقوا وقتًا طويلاً لإكمال مهمة بسيطة باستخدامه. لهذا السبب، من المفيد في بعض الأحيان جمع بعض المقاييس عن رحلة معيّنة يقوم بها المستخدم في تطبيقك. ولمساعدتك في ذلك، تقدِّم ميزة "مراقبة الأداء في Firebase" تتبُّعات مخصّصة. اتّبِع الخطوات التالية لإضافة عمليات تتبُّع مخصّصة وقياس الأداء في أجزاء مختلفة من الرمز في مقالة إجراء ذلك.

حان وقت الترميز

إذا فتحت ملف Performance.kt، ستظهر لك دالة مضمّنة تسمى "التتبُّع". تستدعي هذه الدالة Performance Monitoring API لإنشاء تتبع مخصّص، مع تمرير اسم التتبّع كمَعلمة. المعلمة الأخرى التي تظهر لك هي مجموعة الرموز البرمجية التي تريد مراقبتها. المقياس التلقائي الذي يتم جمعه لكلّ عملية تتبُّع هو الوقت الذي يستغرقه تنفيذها بالكامل:

model/service/Performance.kt

inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)

يمكنك اختيار أجزاء قاعدة الرموز التي تعتقد أنّها مهمّة لقياسها وإضافة بيانات تتبُّع مخصّصة إليها. في ما يلي مثال على إضافة تتبع مخصّص إلى الدالة linkAccount التي رأيتها سابقًا (في AccountServiceImpl.kt) في هذا الدليل التعليمي للترميز:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String): Unit =
  trace(LINK_ACCOUNT_TRACE) {
      val credential = EmailAuthProvider.getCredential(email, password)
      auth.currentUser!!.linkWithCredential(credential).await()
  }

حان دورك الآن! أضِف بعض بيانات آثار الأنشطة المخصّصة إلى تطبيق Make it So وتابِع إلى القسم التالي لاختبار ما إذا كان يعمل على النحو المتوقع.

حان وقت الاختبار.

وبعد الانتهاء من إضافة بيانات التتبُّع المخصَّصة، شغِّل التطبيق وتأكَّد من استخدام الميزات التي تريد قياسها بضع مرات. بعد ذلك، انتقِل إلى وحدة تحكُّم Firebase ثم إلى لوحة بيانات الأداء. في أسفل الشاشة، ستظهر ثلاث علامات تبويب: طلبات الشبكة وعمليات التتبُّع المخصَّصة وعرض الشاشة.

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

6- الإعداد عن بُعد

ما هي الميزة التي ستتم إضافتها؟

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

حان وقت الترميز

عليك أولاً إنشاء الإعدادات في وحدة تحكُّم Firebase. لإجراء ذلك، عليك الانتقال إلى لوحة بيانات "الإعداد عن بُعد" والنقر على الزر إضافة مَعلمة. املأ الحقول وفقًا للصورة أدناه:

مربّع الحوار &quot;إنشاء مَعلمة&quot; في ميزة &quot;الإعداد عن بُعد&quot;

بعد ملء جميع الحقول، يمكنك النقر على الزر حفظ ثم نشر. والآن بعد أن تم إنشاء المَعلمة وأصبحت متاحة لقاعدة الرموز البرمجية، عليك إضافة الرمز الذي سيجلب القيم الجديدة إلى تطبيقك. افتح ملف ConfigurationServiceImpl.kt وعدِّل تنفيذ هاتين الدالتين:

model/service/impl/ConfigurationServiceImpl.kt

override suspend fun fetchConfiguration(): Boolean {
  return remoteConfig.fetchAndActivate().await()
}

override val isShowTaskEditButtonConfig: Boolean
  get() = remoteConfig[SHOW_TASK_EDIT_BUTTON_KEY].asBoolean()

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

ترجع الدالة الثانية القيمة المنطقية التي تم نشرها للمعلمة التي أنشأتها للتو في وحدة التحكم. وستحتاج إلى استرداد هذه المعلومات في TasksViewModel.kt، من خلال إضافة ما يلي إلى الدالة loadTaskOptions:

screen/tasks/TasksViewModel.kt

fun loadTaskOptions() {
  val hasEditOption = configurationService.isShowTaskEditButtonConfig
  options.value = TaskActionOption.getOptions(hasEditOption)
}

يتم استرداد القيمة في السطر الأول واستخدامها لتحميل خيارات القائمة لعناصر المهام في السطر الثاني. إذا كانت القيمة false، يعني ذلك أنّ القائمة لن تحتوي على خيار التعديل. بعد أن أصبحت لديك قائمة الخيارات، عليك جعل واجهة المستخدم تعرِضها بشكل صحيح. أثناء إنشاء تطبيق باستخدام Jetpack Compose، عليك البحث عن composable function التي تحدّد شكل واجهة مستخدم TasksScreen. لذا، افتح ملف TasksScreen.kt وعدِّل LazyColum للإشارة إلى الخيارات المتاحة في TasksViewModel.kt:

screen/tasks/Tasksscreen.kt

val options by viewModel.options

LazyColumn {
  items(tasks.value, key = { it.id }) { taskItem ->
    TaskItem(
      options = options,
      [...]
    )
  }
}

TaskItem هو composable function آخر يوضّح الشكل الذي يجب أن يظهر به واجهة المستخدم لمهمة واحدة. وتحتوي كل مهمة على قائمة بها خيارات يتم عرضها عندما ينقر المستخدم على أيقونة النقاط الثلاث في نهايتها.

حان وقت الاختبار

أنت الآن جاهز لتشغيل التطبيق! تأكَّد من أنّ القيمة التي نشرتها باستخدام وحدة تحكّم Firebase تتطابق مع سلوك التطبيق:

  • إذا كان false، من المفترض أن يظهر لك خياران فقط عند النقر على رمز النقاط الثلاث:
  • إذا كانت القيمة true، من المفترض أن تظهر ثلاثة خيارات عند النقر على رمز النقاط الثلاث.

جرِّب تغيير القيمة مرّتين في وحدة التحكّم ثم إعادة تشغيل التطبيق. هذه هي الطريقة التي يسهل بها إطلاق ميزات جديدة في تطبيقك باستخدام ميزة "الإعداد عن بُعد".

7- تهانينا

تهانينا، لقد نجحت في إنشاء تطبيق Android باستخدام Firebase وJetpack Compose.

لقد أضفت مصادقة Firebase ومراقبة الأداء والإعداد عن بُعد وCloud Firestore إلى تطبيق Android تم إنشاؤه بالكامل باستخدام Jetpack Compose لواجهة المستخدم، وجعلته متوافقًا مع بنية MVVM المقترَحة.

مراجع إضافية

مستندات المرجع