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

1- نظرة عامة

لقطة شاشة

صورة: تطبيق Chat سهل الاستخدام

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

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

  • كيفية استخدام مصادقة Firebase للسماح للمستخدمين بتسجيل الدخول.
  • كيفية مزامنة البيانات باستخدام "قاعدة بيانات Firebase في الوقت الفعلي".
  • كيفية تخزين الملفات الثنائية في Cloud Storage لبرنامج 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

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

تثبيت واجهة سطر الأوامر في Firebase

ستحتاج أولاً إلى تثبيت واجهة سطر الأوامر في 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"، افتح 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 Emulator.

انسخ الملف 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 على Firebase كي تتمكّن من استبدال ملف JSON التجريبي هذا بإعداداتك الخاصة.

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

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

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

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

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

سيستخدم هذا التطبيق "قاعدة بيانات 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 لتنفيذ منطق تسجيل الدخول.

أضِف متغيّر مثيل مصادقة في الفئة 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. في واجهة مستخدم Emulator Suite، ارجع إلى علامة التبويب قاعدة البيانات في الوقت الفعلي، ثم أضِف رسالة جديدة يدويًا. تأكَّد من ظهور الرسالة في تطبيق 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 لرسالة الصورة التي تم تحميلها إلى عنوان الصورة التي تم تحميلها، بعد اكتمال التحميل

اختيار صورة

لإضافة صور، تستخدم هذه الدروس التطبيقية حول الترميز خدمة 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، وعلى وجه التحديد ككائن في علامة التبويب Realtime Database وكثنائي ثنائي كبير في علامة التبويب Storage.

9- تهانينا

لقد أنشأت للتو تطبيق دردشة في الوقت الفعلي باستخدام Firebase!

ما تعلمته

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

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

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

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

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

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

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

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

إضافة 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 قد تحتاج أيضًا إلى تشغيل Build/Clean Project (بناء/تنظيف مشروع) وBuild/Rebuild Project (إنشاء/إعادة إنشاء المشروع) ليتم إجراء تغييرات الإعدادات.

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

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

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

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

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

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

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

للحصول على مزيد من المعلومات حول كيفية عمل قواعد الأمان (بما في ذلك الوثائق المتعلقة بمتغير "auth")، اطلع على وثائق أمان قاعدة البيانات في الوقت الفعلي.

ضبط خدمة Cloud Storage لمنصّة Firebase

  1. في وحدة تحكُّم Firebase، اختَر مساحة التخزين من لوحة التنقّل اليمنى.
  2. انقر على البدء لتفعيل Cloud Storage لمشروعك.
  3. اتّبِع الخطوات الواردة في مربّع الحوار لإعداد الحزمة باستخدام الإعدادات التلقائية المقترَحة.

الربط بموارد 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.