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

1- نظرة عامة

لقطة شاشة

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

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

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

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

المتطلبات

  • أحدث إصدار من استوديو Android
  • محاكي Android يعمل بالإصدار Android 5.0 أو الإصدارات الأحدث
  • الإصدار 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) من الدليل الذي نزّلت منه نموذج الرمز.

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

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

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

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. إذا كنت تستخدم نظام التشغيل 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 Emulator Suite:

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

اترك الأمر 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" وأضفت ملف 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 Emulator Suite في المتصفّح، ثم انقر على علامة التبويب المصادقة للاطّلاع على حساب المستخدم الأول الذي سجّل الدخول.

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

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

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

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

من المفترض أن تكون لديك الآن بعض الرسائل ضمن العقدة 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 باستخدام الرمز المحدَّد أدناه. يضيف هذا الرمز جميع الرسائل الحالية من قاعدة بيانات "الوقت الفعلي"، ثم يستمع إلى الإدخالات الفرعية الجديدة ضمن مسار 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 for 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"، انقر على الزر التنفيذتشغيل.
  2. في "محاكي Android"، أدخِل رسالة ثم انقر على زر الإرسال. من المفترض أن تظهر الرسالة الجديدة في واجهة مستخدم التطبيق وفي واجهة مستخدم مجموعة أدوات محاكي Firebase.
  3. في محاكي Android، انقر على الصورة "+" لاختيار صورة من جهازك. من المفترض أن تظهر الرسالة الجديدة أولاً مع صورة نائبة، ثم مع الصورة المحدّدة بعد اكتمال تحميل الصورة. من المفترض أن تظهر الرسالة الجديدة أيضًا في واجهة مستخدم Emulator Suite، وتحديدًا كعنصر في علامة التبويب &quot;قاعدة بيانات في الوقت الفعلي&quot; وككتلة بيانات في علامة التبويب &quot;التخزين&quot;.

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. انقر على إنشاء مشروع. عندما يصبح مشروعك جاهزًا، انقر على Continue (متابعة).

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

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

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

  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.