درس تطبيقي حول ترميز Firebase لنظام التشغيل Android - إنشاء محادثة بسيطة

1- نظرة عامة

لقطة شاشة

الصورة: تطبيق Working Friendly Chat

مرحبًا بك في مختبر رموز Friendly Chat. في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية استخدام منصة Firebase لإنشاء تطبيق محادثات على Android.

ما ستتعرّف عليه

  • كيفية استخدام Firebase Authentication للسماح للمستخدمين بتسجيل الدخول
  • كيفية مزامنة البيانات باستخدام قاعدة بيانات Firebase في الوقت الفعلي
  • كيفية تخزين الملفات الثنائية في "التخزين في السحابة الإلكترونية" لـ Firebase
  • كيفية استخدام مجموعة أدوات المحاكاة المحلية لمنصة Firebase لتطوير تطبيق Android باستخدام Firebase

المتطلبات

  • أحدث إصدار من استوديو Android
  • محاكي Android يعمل بالإصدار 5.0 من Android أو إصدار أحدث
  • الإصدار 10 من Node.js أو إصدار أحدث (لاستخدام حزمة المحاكيات)
  • ‫Java 8 أو إصدار أحدث لتثبيت Java، اتّبِع هذه التعليمات. للتحقّق من إصدارك، شغِّل java -version.
  • الإلمام بلغة البرمجة Kotlin

2- الحصول على نموذج الرمز

استنساخ المستودع

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

$ git clone https://github.com/firebase/codelab-friendlychat-android

الاستيراد إلى "استوديو Android"

في "استوديو Android"، اختَر ملف > فتح، ثم اختَر دليل build-android-start ( android_studio_folder) من الدليل الذي نزّلت منه نموذج الرمز.

من المفترض أن يكون مشروع build-android-start مفتوحًا الآن في "استوديو Android". إذا ظهر لك تحذير بشأن عدم توفّر ملف google-services.json، لا داعي للقلق. ستتم إضافته في خطوة لاحقة.

التحقّق من التبعيات

في هذا الدليل التعليمي حول الرموز البرمجية، سبق أن تمت إضافة جميع التبعيات التي ستحتاج إليها، ولكن من المهم فهم كيفية إضافة حزمة تطوير البرامج (SDK) لمنصّة Firebase إلى تطبيقك:

build.gradle.kts

plugins {
    id("com.android.application") version "8.0.0" apply false
    id("com.android.library") version "8.0.0" apply false
    id("org.jetbrains.kotlin.android") version "1.8.20" apply false

    // The google-services plugin is required to parse the google-services.json file
    id("com.google.gms.google-services") version "4.3.15" apply false
}

app/build.gradle.kts

plugins {
    id("com.android.application")
    id("kotlin-android")
    id("com.google.gms.google-services")
}

android {
    // ...
}

dependencies {
    // ...

    // Google Sign In SDK
    implementation("com.google.android.gms:play-services-auth:20.5.0")

    // Firebase SDK
    implementation(platform("com.google.firebase:firebase-bom:32.0.0"))
    implementation("com.google.firebase:firebase-database-ktx")
    implementation("com.google.firebase:firebase-storage-ktx")
    implementation("com.google.firebase:firebase-auth-ktx")

    // Firebase UI Library
    implementation("com.firebaseui:firebase-ui-auth:8.0.2")
    implementation("com.firebaseui:firebase-ui-database:8.0.2")
}

3- تثبيت Firebase CLI

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

تثبيت Firebase CLI

عليك أولاً تثبيت واجهة برمجة التطبيقات Firebase CLI. إذا كنت تستخدم نظام التشغيل macOS أو Linux، يمكنك تنفيذ الأمر cURL التالي:

curl -sL https://firebase.tools | bash

إذا كنت تستخدم نظام التشغيل Windows، اطّلِع على تعليمات التثبيت للحصول على ملف ثنائي مستقل أو للتثبيت من خلال npm.

بعد تثبيت واجهة برمجة التطبيقات، من المفترض أن يؤدي تشغيل firebase --version إلى عرض الإصدار 9.0.0 أو إصدار أحدث:

$ firebase --version
9.0.0

تسجيل الدخول

شغِّل firebase login لربط وحدة تحكّم سطر الأوامر بحسابك على Google. سيؤدي ذلك إلى فتح نافذة متصفّح جديدة لإكمال عملية تسجيل الدخول. احرص على اختيار الحساب نفسه الذي استخدمته عند إنشاء مشروعك على Firebase في وقت سابق.

4. الاتصال بمجموعة أدوات المحاكاة في Firebase

ابدأ تشغيل المحاكيات.

في الوحدة الطرفية، نفِّذ الأمر التالي من جذر دليل codelab-friendlychat-android المحلي:

firebase emulators:start --project=demo-friendlychat-android

من المفترض أن تظهر لك بعض السجلات على النحو التالي. تم تحديد قيم المنفذ في ملف firebase.json الذي تم تضمينه في نموذج التعليمات البرمجية التي تم استنساخها.

$ firebase emulators:start --project=demo-friendlychat-android
i  emulators: Starting emulators: auth, database, storage
i  emulators: Detected demo project ID "demo-friendlychat-android", emulated services will use a demo configuration and attempts to access non-emulated services for this project will fail.
i  database: Database Emulator logging to database-debug.log
i  ui: Emulator UI logging to ui-debug.log

┌─────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! It is now safe to connect your app. │
│ i  View Emulator UI at http://localhost:4000                │
└─────────────────────────────────────────────────────────────┘

┌────────────────┬────────────────┬────────────────────────────────┐
│ Emulator       │ Host:Port      │ View in Emulator UI            │
├────────────────┼────────────────┼────────────────────────────────┤
│ Authentication │ localhost:9099 │ http://localhost:4000/auth     │
├────────────────┼────────────────┼────────────────────────────────┤
│ Database       │ localhost:9000 │ http://localhost:4000/database │
├────────────────┼────────────────┼────────────────────────────────┤
│ Storage        │ localhost:9199 │ http://localhost:4000/storage  │
└────────────────┴────────────────┴────────────────────────────────┘
  Emulator Hub running at localhost:4400
  Other reserved ports: 4500

Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.

انتقِل إلى http://localhost:4000 في متصفّح الويب لعرض واجهة مستخدم "مجموعة أدوات المحاكاة في Firebase":

الصفحة الرئيسية لواجهة مستخدم "مجموعة أدوات المحاكاة"

اترك الأمر emulators:start قيد التشغيل لبقية جلسة إنشاء الرمز البرمجي.

ربط تطبيقك

في Android Studio، افتح MainActivity.kt، ثم أضِف الرمز التالي داخل طريقة onCreate:

// When running in debug mode, connect to the Firebase Emulator Suite.
// "10.0.2.2" is a special IP address which allows the Android Emulator
// to connect to "localhost" on the host computer. The port values (9xxx)
// must match the values defined in the firebase.json file.
if (BuildConfig.DEBUG) {
    Firebase.database.useEmulator("10.0.2.2", 9000)
    Firebase.auth.useEmulator("10.0.2.2", 9099)
    Firebase.storage.useEmulator("10.0.2.2", 9199)
}

5- تشغيل التطبيق النموذجي

إضافة ملف google-services.json

لكي يتصل تطبيق Android بمنصّة Firebase، عليك إضافة ملف google-services.json داخل مجلد app في مشروع Android. لأغراض هذا الدليل التعليمي حول الرموز البرمجية، قدّمنا ملفًا وهميًا بتنسيق JSON سيتيح لك الاتصال بمجموعة أدوات محاكي Firebase.

انسخ ملف mock-google-services.json إلى المجلد build-android-start/app باسم google-services.json:

cp mock-google-services.json build-android-start/app/google-services.json

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

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

بعد استيراد المشروع إلى Android Studio وإضافة ملف JSON لإعدادات Firebase، أصبحت مستعدًا لتشغيل التطبيق للمرة الأولى.

  1. ابدأ تشغيل "محاكي Android".
  2. في "استوديو Android"، انقر على تشغيل ( تنفيذ) في شريط الأدوات.

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

6- تفعيل المصادقة

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

إضافة وظيفة تسجيل الدخول الأساسية

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

البحث عن المستخدم الحالي

أضِف أولاً متغيّر المثيل التالي إلى فئة MainActivity.kt:

MainActivity.kt

// Firebase instance variables
private lateinit var auth: FirebaseAuth

لنعدِّل الآن MainActivity لإرسال المستخدم إلى شاشة تسجيل الدخول كلما فتح التطبيق ولم يتم مصادقة بياناته. أضِف ما يلي إلى طريقة onCreate() بعد إرفاق binding بالعرض:

MainActivity.kt

// Initialize Firebase Auth and check if the user is signed in
auth = Firebase.auth
if (auth.currentUser == null) {
    // Not signed in, launch the Sign In activity
    startActivity(Intent(this, SignInActivity::class.java))
    finish()
    return
}

نريد أيضًا التحقّق مما إذا كان المستخدم مسجِّلاً الدخول أثناء onStart():

MainActivity.kt

public override fun onStart() {
    super.onStart()
    // Check if user is signed in.
    if (auth.currentUser == null) {
        // Not signed in, launch the Sign In activity
        startActivity(Intent(this, SignInActivity::class.java))
        finish()
        return
    }
}

بعد ذلك، نفِّذ الطريقتَين getUserPhotoUrl() وgetUserName() لعرض المعلومات المناسبة عن مستخدِم Firebase الذي تمّت مصادقة هويته حاليًا:

MainActivity.kt

private fun getPhotoUrl(): String? {
    val user = auth.currentUser
    return user?.photoUrl?.toString()
}

private fun getUserName(): String? {
    val user = auth.currentUser
    return if (user != null) {
        user.displayName
    } else ANONYMOUS
}

بعد ذلك، طبِّق طريقة signOut() للتعامل مع زر تسجيل الخروج:

MainActivity.kt

private fun signOut() {
    AuthUI.getInstance().signOut()
    startActivity(Intent(this, SignInActivity::class.java))
    finish()
}

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

تنفيذ شاشة تسجيل الدخول

افتح الملف SignInActivity.kt. في ما يلي زر تسجيل دخول بسيط لبدء المصادقة. في هذا القسم، ستستخدم FirebaseUI لتنفيذ منطق تسجيل الدخول.

أضِف متغيّر مثيل Auth في فئة SignInActivity ضمن التعليق // Firebase instance variables:

SignInActivity.kt

// Firebase instance variables
private lateinit var auth: FirebaseAuth

بعد ذلك، عدِّل طريقة onCreate() لإعداد Firebase بالطريقة نفسها التي اتّبعتها في MainActivity:

SignInActivity.kt

// Initialize FirebaseAuth
auth = Firebase.auth

أضِف حقل ActivityResultLauncher إلى SignInActivity:

SignInActivity.kt

// ADD THIS
private val signIn: ActivityResultLauncher<Intent> =
        registerForActivityResult(FirebaseAuthUIActivityResultContract(), this::onSignInResult)

override fun onCreate(savedInstanceState: Bundle?) {
    // ...
}

بعد ذلك، عدِّل طريقة onStart() لبدء عملية تسجيل الدخول في FirebaseUI:

SignInActivity.kt

public override fun onStart() {
    super.onStart()

    // If there is no signed in user, launch FirebaseUI
    // Otherwise head to MainActivity
    if (Firebase.auth.currentUser == null) {
        // Sign in with FirebaseUI, see docs for more details:
        // https://firebase.google.com/docs/auth/android/firebaseui
        val signInIntent = AuthUI.getInstance()
                .createSignInIntentBuilder()
                .setLogo(R.mipmap.ic_launcher)
                .setAvailableProviders(listOf(
                        AuthUI.IdpConfig.EmailBuilder().build(),
                        AuthUI.IdpConfig.GoogleBuilder().build(),
                ))
                .build()

        signIn.launch(signInIntent)
    } else {
        goToMainActivity()
    }
}

بعد ذلك، نفِّذ طريقة onSignInResult للتعامل مع نتيجة تسجيل الدخول. إذا كانت نتيجة تسجيل الدخول ناجحة، تابِع إلى MainActivity:

SignInActivity.kt

private fun onSignInResult(result: FirebaseAuthUIAuthenticationResult) {
    if (result.resultCode == RESULT_OK) {
        Log.d(TAG, "Sign in successful!")
        goToMainActivity()
    } else {
        Toast.makeText(
                this,
                "There was an error signing in",
                Toast.LENGTH_LONG).show()

        val response = result.idpResponse
        if (response == null) {
            Log.w(TAG, "Sign in canceled")
        } else {
            Log.w(TAG, "Sign in error", response.error)
        }
    }
}

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

اختبار عملك

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

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

7- قراءة الرسائل

في هذه الخطوة، سنضيف وظيفة لقراءة الرسائل المخزّنة في "قاعدة بيانات الوقت الفعلي" وعرضها.

استيراد نماذج الرسائل

  1. في واجهة مستخدم Firebase Emulator Suite، اختَر علامة التبويب قاعدة بيانات فورية الاستجابة.
  2. اسحب ملف initial_messages.json وأفلِته من نسختك المحلية لمستودع codelab في أداة عرض البيانات.

من المفترض أن تظهر لك الآن بعض الرسائل ضمن عقدة messages في قاعدة البيانات.

قراءة البيانات

مزامنة الرسائل

في هذا القسم، نضيف رمزًا برمجيًا يُزامن الرسائل المُضافة حديثًا مع واجهة مستخدم التطبيق من خلال:

  • بدء قاعدة بيانات Firebase في الوقت الفعلي وإضافة مستمع للتعامل مع التغييرات التي يتم إجراؤها على البيانات
  • تعديل محوِّل RecyclerView لعرض الرسائل الجديدة
  • إضافة متغيّرات مثيل قاعدة البيانات مع متغيّرات مثيل Firebase الأخرى في فئة MainActivity:

MainActivity.kt

// Firebase instance variables
// ...
private lateinit var db: FirebaseDatabase
private lateinit var adapter: FriendlyMessageAdapter

عدِّل طريقة onCreate() في MainActivity تحت التعليق // Initialize Realtime Database and FirebaseRecyclerAdapter باستخدام الرمز المحدَّد أدناه. يضيف هذا الرمز جميع الرسائل الحالية من "قاعدة بيانات Firebase في الوقت الفعلي"، ثم يستمع إلى الإدخالات الفرعية الجديدة ضمن مسار messages في "قاعدة بيانات Firebase في الوقت الفعلي". وتضيف عنصرًا جديدًا إلى واجهة المستخدم لكل رسالة:

MainActivity.kt

// Initialize Realtime Database
db = Firebase.database
val messagesRef = db.reference.child(MESSAGES_CHILD)

// The FirebaseRecyclerAdapter class and options come from the FirebaseUI library
// See: https://github.com/firebase/FirebaseUI-Android
val options = FirebaseRecyclerOptions.Builder<FriendlyMessage>()
    .setQuery(messagesRef, FriendlyMessage::class.java)
    .build()
adapter = FriendlyMessageAdapter(options, getUserName())
binding.progressBar.visibility = ProgressBar.INVISIBLE
manager = LinearLayoutManager(this)
manager.stackFromEnd = true
binding.messageRecyclerView.layoutManager = manager
binding.messageRecyclerView.adapter = adapter

// Scroll down when a new message arrives
// See MyScrollToBottomObserver for details
adapter.registerAdapterDataObserver(
    MyScrollToBottomObserver(binding.messageRecyclerView, adapter, manager)
)

بعد ذلك، في فئة FriendlyMessageAdapter.kt، نفِّذ الطريقة bind() داخل الفئة الداخلية MessageViewHolder():

FriendlyMessageAdapter.kt

inner class MessageViewHolder(private val binding: MessageBinding) : ViewHolder(binding.root) {
    fun bind(item: FriendlyMessage) {
        binding.messageTextView.text = item.text
        setTextColor(item.name, binding.messageTextView)

        binding.messengerTextView.text = if (item.name == null) ANONYMOUS else item.name
        if (item.photoUrl != null) {
            loadImageIntoView(binding.messengerImageView, item.photoUrl!!)
        } else {
            binding.messengerImageView.setImageResource(R.drawable.ic_account_circle_black_36dp)
        }
    }
    ...
}

نحتاج أيضًا إلى عرض الرسائل التي تكون صورًا، لذا يجب أيضًا تنفيذ الطريقة bind() داخل الفئة الداخلية ImageMessageViewHolder():

FriendlyMessageAdapter.kt

inner class ImageMessageViewHolder(private val binding: ImageMessageBinding) :
    ViewHolder(binding.root) {
    fun bind(item: FriendlyMessage) {
        loadImageIntoView(binding.messageImageView, item.imageUrl!!)

        binding.messengerTextView.text = if (item.name == null) ANONYMOUS else item.name
        if (item.photoUrl != null) {
            loadImageIntoView(binding.messengerImageView, item.photoUrl!!)
        } else {
            binding.messengerImageView.setImageResource(R.drawable.ic_account_circle_black_36dp)
        }
    }
}

أخيرًا، في MainActivity، ابدأ الاستماع إلى آخر الأخبار من "قاعدة بيانات Firebase في الوقت الفعلي" وأوقِف هذا الاستماع. عدِّل الطريقتَين onPause() وonResume() في MainActivity كما هو موضّح أدناه:

MainActivity.kt

public override fun onPause() {
    adapter.stopListening()
    super.onPause()
}

public override fun onResume() {
    super.onResume()
    adapter.startListening()
}

اختبار مزامنة الرسائل

  1. انقر على تشغيل ( تنفيذ).
  2. في واجهة مستخدم "مجموعة المحاكيات"، ارجع إلى علامة التبويب قاعدة بيانات الوقت الفعلي، ثم أضِف رسالة جديدة يدويًا. تأكَّد من ظهور الرسالة في تطبيق Android:

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

8- إرسال الرسائل

تنفيذ إرسال الرسائل النصية

في هذا القسم، ستضيف إمكانية إرسال رسائل نصية لمستخدمي التطبيق. ترصد مقتطف الرموز البرمجية أدناه أحداث النقر على زر الإرسال، وتُنشئ عنصرًا جديدًا من النوع FriendlyMessage يحتوي على محتوى حقل الرسالة، وتُرسِل الرسالة إلى قاعدة البيانات. تُضيف الطريقة push() معرّفًا يتم إنشاؤه تلقائيًا إلى مسار العنصر الذي تمّ دفعه. هذه الأرقام التعريفية متسلسلة، ما يضمن إضافة الرسائل الجديدة إلى نهاية القائمة.

عدِّل مستمع النقرات لزر الإرسال في طريقة onCreate() في فئة MainActivity. يظهر هذا الرمز في أسفل طريقة onCreate(). عدِّل نص onClick() ليتطابق مع الرمز أدناه:

MainActivity.kt

// Disable the send button when there's no text in the input field
// See MyButtonObserver for details
binding.messageEditText.addTextChangedListener(MyButtonObserver(binding.sendButton))

// When the send button is clicked, send a text message
binding.sendButton.setOnClickListener {
    val friendlyMessage = FriendlyMessage(
        binding.messageEditText.text.toString(),
        getUserName(),
        getPhotoUrl(),
        null /* no image */
    )
    db.reference.child(MESSAGES_CHILD).push().setValue(friendlyMessage)
    binding.messageEditText.setText("")
}

تفعيل ميزة إرسال رسائل الصور

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

  • اختيار صورة
  • اختيار صورة الاسم المعرِّف
  • كتابة رسالة صورة مؤقتة في قاعدة بيانات "الوقت الفعلي"
  • بدء تحميل الصورة المحدّدة
  • تعديل عنوان URL لرسالة الصورة ليكون عنوان URL للصورة التي تم تحميلها، بعد اكتمال التحميل

اختيار صورة

لإضافة الصور، يستخدم هذا الدليل التعليمي أداة Cloud Storage لبرنامج Firebase. ‫Cloud Storage هو مكان جيد لتخزين البيانات الثنائية لتطبيقك.

التعامل مع اختيار الصورة وكتابة رسالة مؤقتة

بعد اختيار المستخدم صورة، يتم تشغيل Intent اختيار الصورة. تم تنفيذ ذلك في الرمز البرمجي في نهاية طريقة onCreate(). وعند الانتهاء، تستدعي الطريقة onImageSelected() في MainActivity. باستخدام مقتطف الرمز أدناه، يمكنك كتابة رسالة تتضمّن عنوان URL مؤقتًا للصورة في قاعدة البيانات يشير إلى أنّه يتم تحميل الصورة.

MainActivity.kt

private fun onImageSelected(uri: Uri) {
    Log.d(TAG, "Uri: $uri")
    val user = auth.currentUser
    val tempMessage = FriendlyMessage(null, getUserName(), getPhotoUrl(), LOADING_IMAGE_URL)
    db.reference
            .child(MESSAGES_CHILD)
            .push()
            .setValue(
                    tempMessage,
                    DatabaseReference.CompletionListener { databaseError, databaseReference ->
                        if (databaseError != null) {
                            Log.w(
                                    TAG, "Unable to write message to database.",
                                    databaseError.toException()
                            )
                            return@CompletionListener
                        }

                        // Build a StorageReference and then upload the file
                        val key = databaseReference.key
                        val storageReference = Firebase.storage
                                .getReference(user!!.uid)
                                .child(key!!)
                                .child(uri.lastPathSegment!!)
                        putImageInStorage(storageReference, uri, key)
                    })
}

تحميل الصورة وتعديل الرسالة

أضِف الطريقة putImageInStorage() إلى MainActivity. يتمّ استدعاؤه في onImageSelected() لبدء تحميل الصورة المحدّدة. بعد اكتمال عملية التحميل، عليك تعديل الرسالة لاستخدام الصورة المناسبة.

MainActivity.kt

private fun putImageInStorage(storageReference: StorageReference, uri: Uri, key: String?) {
    // First upload the image to Cloud Storage
    storageReference.putFile(uri)
        .addOnSuccessListener(
            this
        ) { taskSnapshot -> // After the image loads, get a public downloadUrl for the image
            // and add it to the message.
            taskSnapshot.metadata!!.reference!!.downloadUrl
                .addOnSuccessListener { uri ->
                    val friendlyMessage =
                        FriendlyMessage(null, getUserName(), getPhotoUrl(), uri.toString())
                    db.reference
                        .child(MESSAGES_CHILD)
                        .child(key!!)
                        .setValue(friendlyMessage)
                }
        }
        .addOnFailureListener(this) { e ->
            Log.w(
                TAG,
                "Image upload task was unsuccessful.",
                e
            )
        }
}

اختبار إرسال الرسائل

  1. في Android Studio، انقر على الزر تنفيذRun (تشغيل).
  2. في "محاكي Android"، أدخِل رسالة، ثم انقر على زر الإرسال. من المفترض أن تظهر الرسالة الجديدة في واجهة مستخدم التطبيق وفي واجهة مستخدم مجموعة أدوات محاكي Firebase.
  3. في "محاكي Android"، انقر على صورة "+" لاختيار صورة من جهازك. من المفترض أن تظهر الرسالة الجديدة أولاً مع صورة نائبة، ثم مع الصورة المحدّدة بعد اكتمال تحميل الصورة. من المفترض أن تظهر الرسالة الجديدة أيضًا في واجهة مستخدم Emulator Suite، وتحديدًا كعنصر في علامة التبويب "قاعدة بيانات في الوقت الفعلي" وككتلة بيانات في علامة التبويب "التخزين".

9- تهانينا!

لقد أنشأت للتو تطبيق محادثة في الوقت الفعلي باستخدام Firebase.

ما تعلمته

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

بعد ذلك، جرِّب استخدام ما تعلمته في هذا الدرس التطبيقي حول الترميز لإضافة Firebase إلى تطبيق Android الخاص بك. لمزيد من المعلومات عن Firebase، يُرجى الانتقال إلى firebase.google.com.

إذا كنت تريد معرفة كيفية إعداد مشروع حقيقي على Firebase واستخدام موارد حقيقية على Firebase (بدلاً من مشروع تجريبي وموارد محاكية فقط)، انتقِل إلى الخطوة التالية.

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

10- اختياري: إنشاء مشروع على Firebase وإعداده

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

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

  1. في المتصفّح، انتقِل إلى وحدة تحكّم Firebase.
  2. انقر على إضافة مشروع.
  3. اختَر اسم مشروع أو أدخِله. يمكنك استخدام أي اسم تريده.
  4. لا تحتاج إلى "إحصاءات Google" لاستخدام هذا الدليل التعليمي حول الرموز البرمجية، لذا يمكنك تخطّي تفعيلها لمشروعك.
  5. انقر على إنشاء مشروع. عندما يصبح مشروعك جاهزًا، انقر على متابعة.

ترقية خطة أسعار Firebase

لاستخدام Cloud Storage لبرنامج Firebase، يجب أن يكون مشروعك على Firebase مُدرَجًا في خطة الأسعار "الدفع حسب الاستخدام" (Blaze)، ما يعني أنّه مرتبط بحساب على "الفوترة في السحابة الإلكترونية".

لترقية مشروعك إلى خطة Blaze، اتّبِع الخطوات التالية:

  1. في "وحدة تحكّم Firebase"، اختَر ترقية خطتك.
  2. اختَر خطة Blaze. اتّبِع التعليمات الظاهرة على الشاشة لربط حساب "فوترة على Cloud" بمشروعك.
    إذا كنت بحاجة إلى إنشاء حساب "فوترة على Cloud" كجزء من هذه الترقية، قد تحتاج إلى الرجوع إلى مسار الترقية في وحدة تحكّم Firebase لإكمال الترقية.

إضافة Firebase إلى مشروع Android

قبل بدء هذه الخطوة، احصل على تجزئة SHA1 لتطبيقك. شغِّل الأمر التالي من دليل build-android-start على جهازك لتحديد SHA1 لمفتاح تصحيح الأخطاء:

./gradlew signingReport

Store: /Users/<username>/.android/debug.keystore
Alias: AndroidDebugKey
MD5: A5:88:41:04:8F:06:59:6A:AE:33:76:87:AA:AD:19:23
SHA1: A7:89:F5:06:A8:07:A1:22:EC:90:6A:A6:EA:C3:D4:8B:3A:30:AB:18
SHA-256: 05:A2:2A:35:EE:F2:51:23:72:4D:72:67:A5:6A:8A:58:22:2C:00:A6:AB:F6:45:D5:A1:82:D8:90:A4:69:C8:FE
Valid until: Wednesday, August 10, 2044

من المفترض أن تظهر لك بعض النتائج كما هو موضّح أعلاه. السطر المهم هو تجزئة SHA1. إذا لم تتمكّن من العثور على تجزئة SHA1، يُرجى الاطّلاع على هذه الصفحة للحصول على مزيد من المعلومات.

ارجع إلى "وحدة تحكّم Firebase" واتّبِع الخطوات التالية لتسجيل مشروع Android في مشروعك على Firebase:

  1. من شاشة النظرة العامة على مشروعك الجديد، انقر على رمز Android لبدء سير عمل الإعداد: إضافة تطبيق Android
  2. في الشاشة التالية، أدخِل com.google.firebase.codelab.friendlychat كاسم حزمة تطبيقك.
  3. انقر على تسجيل التطبيق، ثم انقر على تنزيل google-services.json لتنزيل ملف إعدادات Firebase.
  4. انسخ ملف google-services.json إلى الدليل app في مشروع Android.
  5. تخطّى الخطوات التالية المعروضة في سير عمل الإعداد في وحدة التحكّم (سبق أن تم إكمالها نيابةً عنك في مشروع build-android-start).
  6. تأكَّد من توفّر جميع التبعيات لتطبيقك من خلال مزامنة مشروعك مع ملفات Gradle. من شريط أدوات "استوديو Android"، اختَر ملف > مزامنة المشروع مع ملفات Gradle. قد تحتاج أيضًا إلى تنفيذ إنشاء/تنظيف المشروع وإنشاء/إعادة إنشاء المشروع لكي يتم تطبيق تغييرات الإعداد.

ضبط إعدادات "مصادقة Firebase"

لكي يتمكّن تطبيقك من الوصول إلى واجهات برمجة التطبيقات في Firebase Authentication نيابةً عن المستخدمين، عليك تفعيل Firebase Authentication ومقدّمي خدمات تسجيل الدخول الذين تريد استخدامهم في تطبيقك.

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

إذا ظهرت لك أخطاء في وقت لاحق من هذا الدليل التعليمي للترميز تتضمّن الرسالة "CONFIGURATION_NOT_FOUND"، يُرجى الرجوع إلى هذه الخطوة والتحقّق من عملك مرة أخرى.

إعداد "قاعدة بيانات في الوقت الفعلي"

يخزِّن التطبيق في هذا الدليل التعليمي رسائل المحادثة في قاعدة بيانات Firebase في الوقت الفعلي. في هذا القسم، سننشئ قاعدة بيانات ونضبط إعدادات الأمان فيها من خلال لغة إعدادات JSON تُعرف باسم "قواعد أمان Firebase".

  1. في اللوحة اليمنى من "وحدة تحكّم Firebase"، وسِّع الإنشاء، ثم اختَر قاعدة بيانات في الوقت الفعلي.
  2. انقر على إنشاء قاعدة بيانات.
  3. اختَر موقعًا لقاعدة بياناتك، ثم انقر على التالي.
    بالنسبة إلى التطبيق الحقيقي، عليك اختيار موقع قريب من المستخدمين.
  4. انقر على البدء في وضع الاختبار. اقرأ بيان إخلاء المسؤولية عن قواعد الأمان.
    في الخطوات التالية من هذا البرنامج التعليمي، ستضيف قواعد أمان لتأمين بياناتك. لا توزِّع تطبيقًا علنًا أو تعرضه بدون إضافة قواعد أمان لقاعدة بياناتك.
  5. انقر على إنشاء.
  6. بعد إنشاء مثيل قاعدة البيانات، اختَر علامة التبويب القواعد، ثم عدِّل إعدادات القواعد باستخدام ما يلي:
     {
       "rules": {
         "messages": {
           ".read": "auth.uid != null",
           ".write": "auth.uid != null"
         }
       }
     }
    

لمزيد من المعلومات عن كيفية عمل "قواعد الأمان" (بما في ذلك مستندات عن المتغيّر "auth")، اطّلِع على مستندات أمان "قاعدة بيانات الوقت الفعلي".

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

  1. في اللوحة اليسرى من وحدة تحكّم Firebase، وسِّع الإصدار، ثم اختَر مساحة التخزين.
  2. انقر على البدء.
  3. اختَر موقعًا جغرافيًا لحزمة التخزين التلقائية.
    يمكن للحِزم في US-WEST1 وUS-CENTRAL1 وUS-EAST1 الاستفادة من المستوى"مجاني دائمًا" في Google Cloud Storage. تخضع الحِزم في جميع المواقع الجغرافية الأخرى لأسعار Google Cloud Storage واستخدامها.
  4. انقر على البدء في وضع الاختبار. اقرأ بيان إخلاء المسؤولية بشأن قواعد الأمان.
    في وقت لاحق من هذا الدليل التعليمي، ستضيف قواعد أمان لتأمين بياناتك. لا توزِّع تطبيقًا علنًا أو تعرضه بدون إضافة قواعد أمان لحزمة التخزين.
  5. انقر على إنشاء.

الربط بموارد Firebase

في خطوة سابقة من هذا الدليل التعليمي حول الرموز البرمجية، أضفت ما يلي إلى MainActivity.kt. ربطت هذه الكتلة الشَرطية مشروع Android بمجموعة محاكيات Firebase.

// REMOVE OR DISABLE THIS
if (BuildConfig.DEBUG) {
    Firebase.database.useEmulator("10.0.2.2", 9000)
    Firebase.auth.useEmulator("10.0.2.2", 9099)
    Firebase.storage.useEmulator("10.0.2.2", 9199)
}

إذا كنت تريد ربط تطبيقك بمشروعك الجديد الحقيقي على Firebase وموارد الحقيقي على Firebase، يمكنك إزالة هذا الجزء أو تشغيل تطبيقك في وضع الإصدار حتى يكون BuildConfig.DEBUG هو false.