إنشاء تطبيق 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، لأنّ ذلك سيسهّل فهم قاعدة الرموز ويسهّل إكمال الخطوات التالية.

ما الذي ستنشئه

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

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

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

  • مصادقة المستخدمين باستخدام البريد الإلكتروني وكلمة المرور
  • يمكنك إضافة أداة استماع إلى مجموعة 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

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

ويمكنك إنشاء تطبيقات مختلفة داخل كل مشروع في Firebase: لنظام التشغيل Android وiOS وWeb و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 بشكلٍ صحيح، عليك تنفيذ أمرين في Console قبل الانتقال إلى الرمز: تفعيل موفّري المصادقة وإنشاء قاعدة بيانات Firestore. أولاً، يجب تفعيل المصادقة حتى يتمكّن المستخدمون من تسجيل الدخول إلى التطبيق:

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

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

  1. من القائمة إنشاء، اختَر Firestore، ثم انقر على إنشاء قاعدة بيانات.
  2. إبقاء البدء في وضع الإنتاج مفعّلاً والنقر على التالي
  3. اختَر الموقع الجغرافي الذي سيتم تخزين بيانات Cloud Firestore فيه عندما يُطلب منك ذلك. عند تطوير تطبيق إنتاج، يجب أن يكون هذا التطبيق في منطقة قريبة من غالبية المستخدمين، وأن يكون مشتركًا مع خدمات Firebase الأخرى، مثل الدوال. في هذا الدرس التطبيقي، يمكنك الاحتفاظ بالمنطقة التلقائية أو اختيار المنطقة الأقرب إليك.
  4. انقر على تفعيل لإدارة قاعدة بيانات Firestore.

لنخصص بعض الوقت لإنشاء قواعد أمان قوية لقاعدة بيانات Firestore. افتح لوحة بيانات Firestore وانتقِل إلى علامة التبويب القواعد. ثم حدِّث "قواعد الأمان" لتبدو كالتالي:

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" وشغِّل التطبيق (يمكن إجراء ذلك باستخدام محاكي 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:

screen/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 وانتقِل إلى الإعدادات بالنقر على رمز الترس في أعلى يسار الشاشة. انقر بعد ذلك على الخيار "إنشاء حساب":

شاشة إعدادات "جعلها تعمل" شاشة صفحة الاشتراك

اكتب عنوان بريد إلكتروني صالحًا وكلمة مرور قوية لإنشاء حسابك. ومن المفترض أن يعمل هذا الإجراء، ومن المفترض أن تتم إعادة توجيهك إلى صفحة الإعدادات، حيث سيظهر لك خياران جديدان: الخروج وحذف حسابك. يمكنك التحقق من الحساب الجديد الذي تم إنشاؤه في لوحة بيانات المصادقة في وحدة تحكم 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 تظهر كما هي في الخدمة:

screen/tasks/TasksViewModel.kt

val tasks = storageService.tasks

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

screen/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- الإعداد عن بُعد

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

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

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

عليك أولاً إنشاء الإعدادات في وحدة تحكُّم 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، من المفترض أن تظهر ثلاثة خيارات عند النقر على رمز النقاط الثلاث.

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

7- تهانينا

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

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

قراءة إضافية

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