استلام الرسائل في تطبيق Android

تختلف طريقة عمل إشعارات Firebase حسب حالة التطبيق المستلِم (في المقدّمة أو في الخلفية). إذا كنت تريد أن تتلقّى التطبيقات التي تعمل في المقدّمة رسائل إشعارات أو رسائل بيانات، عليك كتابة رمز للتعامل مع عملية الاستدعاء onMessageReceived. للحصول على توضيح حول الفرق بين رسائل الإشعارات ورسائل البيانات، راجِع أنواع الرسائل.

التعامل مع الرسائل

لتلقّي الرسائل، استخدِم خدمة تتضمّن FirebaseMessagingService. يجب أن تتجاهل خدمتك عمليات الاسترجاع onMessageReceived وonDeletedMessages.

يتم توفير onMessageReceived لمعظم أنواع الرسائل، باستثناء ما يلي:

  • رسائل الإشعارات التي يتم تسليمها عندما يكون تطبيقك يعمل في الخلفية في هذه الحالة، يتم تسليم الإشعار إلى لوحة النظام على الجهاز. عندما ينقر المستخدم على إشعار، يتم فتح لوحة تشغيل التطبيقات تلقائيًا.

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

وباختصار:

حالة التطبيق إشعار البيانات كلاهما
لون الواجهة onMessageReceived onMessageReceived onMessageReceived
الخلفية لوحة النظام onMessageReceived الإشعار: شريط النظام
البيانات: في الإضافات الخاصة بالغرض.
لمزيد من المعلومات حول أنواع الرسائل، راجِع الإشعارات ورسائل البيانات.

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

إذا كنت تتوقّع أنّ تطبيقك قد يحتاج إلى ما يقرب من 10 ثوانٍ لمعالجة رسالة، عليك جدولة مهمة WorkManager أو اتّباع إرشادات WakeLock الواردة أدناه. في بعض الحالات، قد تكون الفترة الزمنية المتاحة لمعالجة الرسالة أقل من 10 ثوانٍ، وذلك حسب التأخيرات التي تحدث قبل طلب onMessageReceived، بما في ذلك تأخيرات نظام التشغيل أو وقت بدء تشغيل التطبيق أو حظر سلسلة التعليمات الرئيسية بسبب عمليات أخرى أو استغراق طلبات onMessageReceived السابقة وقتًا طويلاً. وبعد انتهاء مدة هذا الموقّت، قد يخضع تطبيقك إلى إيقاف العملية أو حدود التنفيذ في الخلفية. يُرجى العِلم أنّ حالات التأخير في معاملات الشبكة وبدء تشغيل التطبيق يمكن أن تكون كبيرة، لذا، عند الشك، خطِّط لتنفيذ معالجة الرسائل لفترة طويلة إذا كانت هناك أي تبعيات غير متزامنة، مثل الوصول إلى الشبكة أو متطلبات تحميل البيانات المكثّف.

تعديل ملف بيان التطبيق

لاستخدام FirebaseMessagingService، عليك إضافة ما يلي إلى بيان التطبيق:

<service
    android:name=".java.MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

يُنصح أيضًا بضبط القيم التلقائية لتخصيص مظهر الإشعارات. يمكنك تحديد رمز تلقائي مخصّص ولون تلقائي مخصّص يتم تطبيقهما كلما لم يتم ضبط قيم مكافئة في حمولة الإشعار.

أضِف الأسطر التالية داخل علامة application لضبط الرمز التلقائي المخصّص واللون المخصّص:

<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
     See README(https://goo.gl/l4GJaQ) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
     notification message. See README(https://goo.gl/6BKBk7) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

يعرض نظام التشغيل Android الرمز التلقائي المخصّص لـ

  • جميع رسائل الإشعارات المرسَلة من أداة إنشاء الإشعارات
  • أي رسالة إشعار لا تحدّد الرمز بشكل صريح في حمولة الإشعار

يستخدم نظام التشغيل Android اللون التلقائي المخصّص في ما يلي:

  • جميع رسائل الإشعارات المرسَلة من أداة إنشاء الإشعارات
  • أي رسالة إشعار لا تحدّد اللون بشكل صريح في حمولة الإشعار

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

تجاهل onMessageReceived

من خلال إلغاء طريقة FirebaseMessagingService.onMessageReceived، يمكنك تنفيذ إجراءات استنادًا إلى كائن RemoteMessage المستلَم والحصول على بيانات الرسالة:

Kotlin

override fun onMessageReceived(remoteMessage: RemoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    Log.d(TAG, "From: ${remoteMessage.from}")

    // Check if message contains a data payload.
    if (remoteMessage.data.isNotEmpty()) {
        Log.d(TAG, "Message data payload: ${remoteMessage.data}")

        // Check if data needs to be processed by long running job
        if (needsToBeScheduled()) {
            // For long-running tasks (10 seconds or more) use WorkManager.
            scheduleJob()
        } else {
            // Handle message within 10 seconds
            handleNow()
        }
    }

    // Check if message contains a notification payload.
    remoteMessage.notification?.let {
        Log.d(TAG, "Message Notification Body: ${it.body}")
    }

    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
}

Java

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    Log.d(TAG, "From: " + remoteMessage.getFrom());

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());

        if (/* Check if data needs to be processed by long running job */ true) {
            // For long-running tasks (10 seconds or more) use WorkManager.
            scheduleJob();
        } else {
            // Handle message within 10 seconds
            handleNow();
        }

    }

    // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    }

    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
}

إبقاء الجهاز مشغَّلاً أثناء معالجة رسائل FCM

إذا كان تطبيقك بحاجة إلى إبقاء الجهاز نشطًا أثناء معالجة رسالة من &quot;المراسلة عبر السحابة الإلكترونية من Firebase&quot;، يجب أن يحتفظ بقفل تنشيط الشاشة خلال هذه الفترة أو أن ينشئ مهمة WorkManager. تعمل WakeLocks بشكل جيد مع أنشطة المعالجة القصيرة التي قد تتجاوز مهلات onMessageReceived التلقائية. بالنسبة إلى مهام سير العمل الموسّعة، مثل إرسال عدة طلبات RPC متسلسلة إلى خوادمك، يكون استخدام مهمة WorkManager أكثر ملاءمة من WakeLock. في هذا القسم، نركّز على كيفية استخدام WakeLocks. يمنع WakeLock الجهاز من الانتقال إلى وضع السكون أثناء تشغيل تطبيقك، ما قد يؤدي إلى زيادة استهلاك البطارية، لذا يجب استخدام WakeLock في الحالات التي لا يجب فيها إيقاف تطبيقك مؤقتًا أثناء معالجة الرسالة، مثل:

  • إشعارات للمستخدم تكون حساسة للوقت
  • التفاعلات مع شيء خارج الجهاز لا يجب مقاطعتها (مثل عمليات نقل البيانات على الشبكة أو عمليات التواصل مع جهاز آخر، مثل ساعة مقترنة)

عليك أولاً التأكّد من أنّ تطبيقك يطلب إذن WakeLock (تتضمّن حزمة تطوير البرامج (SDK) لخدمة FCM هذا الإذن تلقائيًا، لذا لا تحتاج عادةً إلى إضافة أي شيء).

<uses-permission android:name="android.permission.WAKE_LOCK" />

بعد ذلك، سيحتاج تطبيقك إلى الحصول على WakeLock في بداية معاودة الاتصال FirebaseMessagingService.onMessageReceived() وإصداره في نهاية معاودة الاتصال.

FirebaseMessagingService المخصّص للتطبيق:

@Override
public void onMessageReceived(final RemoteMessage message) {
  // If this is a message that is time sensitive or shouldn't be interrupted
  WakeLock wakeLock = getSystemService(PowerManager.class).newWakeLock(PARTIAL_WAKE_LOCK, "myApp:messageReceived");
  try {
    wakeLock.acquire(TIMEOUT_MS);
    // handle message
    ...
  finally {
    wakeLock.release();
  }
}

تجاهل onDeletedMessages

في بعض الحالات، قد لا يرسل FCM رسالة. يحدث ذلك عندما يكون هناك عدد كبير جدًا من الرسائل المعلقة (>100) لتطبيقك على جهاز معيّن عند اتصاله بالإنترنت، أو إذا لم يتصل الجهاز بخدمة FCM لأكثر من شهر واحد. في هذه الحالات، قد تتلقّى رد اتصال إلى FirebaseMessagingService.onDeletedMessages() عندما يتلقّى مثيل التطبيق رد الاتصال هذا، يجب إجراء مزامنة كاملة مع خادم تطبيقك. إذا لم ترسل رسالة إلى التطبيق على هذا الجهاز خلال الأسابيع الأربعة الماضية، لن يتصل FCM بـ onDeletedMessages().

التعامل مع رسائل الإشعارات في تطبيق يعمل في الخلفية

عندما يكون تطبيقك يعمل في الخلفية، يوجّه نظام التشغيل Android رسائل الإشعارات إلى لوحة النظام. عندما ينقر المستخدم على الإشعار، يتم فتح لوحة تشغيل التطبيقات تلقائيًا.

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

للحصول على إحصاءات حول وصول الرسائل إلى تطبيقك، اطّلِع على FCMلوحة بيانات التقارير التي تسجّل عدد الرسائل المرسَلة والمفتوحة على أجهزة Apple وAndroid، بالإضافة إلى بيانات "مرات الظهور" (الإشعارات التي يراها المستخدمون) لتطبيقات Android.

تلقّي رسائل FCM في وضع "التشغيل المباشر"

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

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

المتطلبات الأساسية

  • يجب إعداد الجهاز لوضع التشغيل المباشر.
  • يجب أن يكون على الجهاز إصدار حديث من "خدمات Google Play" (الإصدار 19.0.54 أو الإصدارات الأحدث).
  • يجب أن يستخدم التطبيق حزمة تطوير البرامج (SDK) لخدمة "المراسلة عبر السحابة الإلكترونية من Firebase" (com.google.firebase:firebase-messaging) لتلقّي رسائل هذه الخدمة.

تفعيل معالجة الرسائل في وضع "التشغيل المباشر" في تطبيقك

  1. في ملف Gradle على مستوى التطبيق، أضِف اعتمادًا على مكتبة دعم التشغيل المباشر في FCM:

    implementation 'com.google.firebase:firebase-messaging-directboot:20.2.0'
    
  2. اجعل تطبيقك FirebaseMessagingService متوافقًا مع وضع التشغيل المباشر من خلال إضافة السمة android:directBootAware="true" في بيان التطبيق:

    <service
        android:name=".java.MyFirebaseMessagingService"
        android:exported="false"
        android:directBootAware="true">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
    

من المهم التأكّد من إمكانية تشغيل هذا FirebaseMessagingService في وضع "التشغيل المباشر". يجب استيفاء المتطلبات التالية:

  • يجب ألا تصل الخدمة إلى وحدة التخزين المحمية ببيانات الاعتماد أثناء التشغيل في وضع "التشغيل المباشر".
  • يجب ألا تحاول الخدمة استخدام مكوّنات، مثل Activities أو BroadcastReceivers أو غيرها من Services التي لم يتم وضع علامة عليها بأنّها متوافقة مع وضع "التشغيل المباشر" أثناء التشغيل في وضع "التشغيل المباشر".
  • يجب أيضًا ألا تصل أي مكتبات تستخدمها الخدمة إلى مساحة التخزين المحمية ببيانات الاعتماد، كما يجب ألا تستدعي أي مكونات غير متوافقة مع وضع "التمهيد المباشر" أثناء التشغيل في هذا الوضع. وهذا يعني أنّ أي مكتبات يستخدمها التطبيق ويتم استدعاؤها من الخدمة يجب أن تكون متوافقة مع وضع "التشغيل المباشر"، أو يجب أن يتحقّق التطبيق مما إذا كان يعمل في وضع "التشغيل المباشر" وأن لا يستدعيها في هذا الوضع. على سبيل المثال، تعمل حِزم تطوير البرامج (SDK) من Firebase مع ميزة "التشغيل المباشر" (يمكن تضمينها في تطبيق بدون أن يؤدي ذلك إلى تعطُّله في وضع "التشغيل المباشر")، ولكن لا تتوافق العديد من واجهات برمجة التطبيقات في Firebase مع إمكانية استدعائها في وضع "التشغيل المباشر".
  • إذا كان التطبيق يستخدم Application مخصّصًا، يجب أن يكون Application متوافقًا أيضًا مع ميزة "التشغيل المباشر" (أي لا يمكن الوصول إلى مساحة التخزين المحمية ببيانات الاعتماد في وضع "التشغيل المباشر").

للحصول على إرشادات حول إرسال الرسائل إلى الأجهزة في وضع التشغيل المباشر، راجِع إرسال الرسائل المتوافقة مع وضع التشغيل المباشر.