איך מקבלים הודעות באפליקציה ל-Android

ההתנהגות של התראות Firebase שונה בהתאם למצב החזית/הרקע של האפליקציה המקבלת. אם רוצים שאפליקציות בחזית יקבלו הודעות התראה או הודעות נתונים, צריך לכתוב קוד לטיפול בקריאה החוזרת onMessageReceived. הסבר על ההבדל בין הודעות התראה להודעות נתונים מופיע במאמר בנושא סוגי הודעות.

טיפול בהודעות

כדי לקבל הודעות, צריך להשתמש בשירות שמרחיב את FirebaseMessagingService. השירות שלכם צריך לבטל את ההחזרות (callbacks) של onMessageReceived ו-onDeletedMessages.

חלון הזמן לטיפול בהודעה עשוי להיות קצר מ-20 שניות, בהתאם לעיכובים שקורים לפני הקריאה ל-onMessageReceived, כולל עיכובים במערכת ההפעלה, זמן ההפעלה של האפליקציה, חסימת ה-thread הראשי על ידי פעולות אחרות או קריאות קודמות ל-onMessageReceived שנמשכות יותר מדי זמן. אחרי פרק הזמן הזה, התנהגויות שונות של מערכת ההפעלה, כמו הפסקת התהליך ב-Android או הגבלות על הפעלת אפליקציות ברקע ב-Android O, עלולות להפריע לכם להשלים את העבודה.

הסמל onMessageReceived מוצג ברוב סוגי ההודעות, למעט במקרים הבאים:

  • הודעות התראה שנמסרות כשהאפליקציה פועלת ברקע. במקרה כזה, ההתראה מועברת למגש המערכת של המכשיר. הקשה של משתמש על התראה פותחת את מרכז האפליקציות כברירת מחדל.

  • הודעות עם מטען ייעודי (payload) של התראה ונתונים, כשמתקבלות ברקע. במקרה כזה, ההתראה מועברת למגש המערכת של המכשיר, ומטען הנתונים מועבר בתוספות של ה-intent של פעילות מרכז האפליקציות.

בקצרה:

מצב האפליקציה התראה נתונים שניהם
חזית onMessageReceived onMessageReceived onMessageReceived
רקע מגש המערכת onMessageReceived התראה: מגש המערכת
נתונים: בתוספות של הכוונה.
מידע נוסף על סוגי הודעות זמין במאמר התראות והודעות נתונים.

עריכת מניפסט האפליקציה

כדי להשתמש ב-FirebaseMessagingService, צריך להוסיף את השורות הבאות למניפסט של האפליקציה:

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

מומלץ גם להגדיר ערכי ברירת מחדל כדי להתאים אישית את המראה של ההתראות. אתם יכולים לציין סמל ברירת מחדל מותאם אישית וצבע ברירת מחדל מותאם אישית שיוחלו בכל פעם שלא מוגדרים ערכים מקבילים במטען הייעודי (payload) של ההתראה.

מוסיפים את השורות האלה בתוך התג 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 מוצג סמל ברירת המחדל המותאם אישית

  • כל ההודעות של ההתראות שנשלחות מ כלי ההתראות.
  • כל הודעת התראה שלא מוגדר בה במפורש הסמל במטען הייעודי (Payload) של ההתראה.

מערכת Android משתמשת בצבע ברירת המחדל המותאם אישית עבור

  • כל ההודעות של ההתראות שנשלחות מ כלי ההתראות.
  • כל הודעת התראה שלא מוגדר בה צבע באופן מפורש במטען הייעודי (Payload) של ההתראה.

אם לא מוגדר סמל ברירת מחדל מותאם אישית ולא מוגדר סמל במטען הייעודי (payload) של ההתראה, מערכת Android מציגה את סמל האפליקציה בצבע לבן.

השבתה של onMessageReceived

אפשר לבצע פעולות על סמך האובייקט RemoteMessage שהתקבל ולקבל את נתוני ההודעה באמצעות שינוי של השיטה FirebaseMessagingService.onMessageReceived:

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.
}

השבתה של onDeletedMessages

במקרים מסוימים, יכול להיות שההודעה לא תועבר דרך FCM. המצב הזה קורה אם יש יותר מדי הודעות (>100) שממתינות לאפליקציה במכשיר מסוים בזמן שהוא מתחבר, או אם המכשיר לא התחבר אל FCM במשך יותר מחודש. במקרים כאלה, יכול להיות שתקבלו קריאה חוזרת אל FirebaseMessagingService.onDeletedMessages() כשמופע האפליקציה מקבל את הקריאה החוזרת הזו, הוא צריך לבצע סנכרון מלא עם שרת האפליקציה. אם לא שלחתם הודעה לאפליקציה במכשיר הזה ב-4 השבועות האחרונים, FCM לא יתקשר אל onDeletedMessages().

טיפול בהודעות התראה באפליקציה שפועלת ברקע

כשהאפליקציה פועלת ברקע, מערכת Android מפנה את הודעות ההתראה למגש המערכת. הקשה של משתמש על ההתראה פותחת את מרכז האפליקציות כברירת מחדל.

זה כולל הודעות שמכילות גם התראה וגם מטען נתונים (וכל ההודעות שנשלחות ממסוף ההתראות). במקרים כאלה, ההתראה מועברת למגש המערכת של המכשיר, ומטען הנתונים מועבר בתוספות של ה-Intent של פעילות ההפעלה.

כדי לקבל תובנות לגבי מסירת הודעות לאפליקציה, אפשר לעיין ב FCMלוח הבקרה של הדוחות, שבו מתועד מספר ההודעות שנשלחו ונפתחו במכשירי Apple ובמכשירי Android, וגם נתונים לגבי 'חשיפות' (התראות שהמשתמשים ראו) באפליקציות ל-Android.

קבלת הודעות FCM במצב אתחול ישיר

מפתחים שרוצים לשלוח הודעות לאפליקציות גם לפני שהמכשיר נפתח יכולים להפעיל אפליקציית Android כדי לקבל הודעות כשהמכשיר נמצא במצב אתחול ישיר.FCM לדוגמה, יכול להיות שתרצו שמשתמשים באפליקציה שלכם יקבלו התראות על אזעקות גם במכשיר נעול.

כשמפתחים את תרחיש השימוש הזה, חשוב לפעול לפי השיטות המומלצות וההגבלות הכלליות לגבי מצב אתחול ישיר. חשוב במיוחד לשים לב לחשיפה של הודעות שמופעלת בהן הפעלה ישירה. כל משתמש שיש לו גישה למכשיר יכול לראות את ההודעות האלה בלי להזין את פרטי הכניסה שלו.

דרישות מוקדמות

  • המכשיר צריך להיות מוגדר למצב אתחול ישיר.
  • במכשיר צריכה להיות מותקנת גרסה עדכנית של שירותי Google Play (19.0.54 ואילך).
  • האפליקציה צריכה להשתמש ב-FCM SDK‏ (com.google.firebase:firebase-messaging) כדי לקבל הודעות FCM.

הפעלת טיפול בהודעות במצב אתחול ישיר באפליקציה

  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 אחרים שלא מסומנים כרכיבים שיכולים לפעול במצב אתחול ישיר, בזמן שהוא פועל במצב אתחול ישיר.
  • בנוסף, אף אחת מהספריות שבהן השירות משתמש לא יכולה לגשת לאחסון שמוגן באמצעות אישורים או לקרוא לרכיבים שלא תומכים בהפעלה ישירה בזמן שהשירות פועל במצב הפעלה ישירה. המשמעות היא שכל הספריות שבהן האפליקציה משתמשת ושנקראות מהשירות צריכות להיות מודעות להפעלה ישירה, או שהאפליקציה צריכה לבדוק אם היא פועלת במצב של הפעלה ישירה ולא לקרוא להן במצב הזה. לדוגמה, ערכות Firebase SDK פועלות עם אתחול ישיר (אפשר לכלול אותן באפליקציה בלי שהיא תקרוס במצב אתחול ישיר), אבל הרבה ממשקי Firebase API לא תומכים בקריאה במצב אתחול ישיר.
  • אם האפליקציה משתמשת ב-Application מותאם אישית, גם Application צריך להיות מודע להפעלה ישירה (אין גישה לאחסון מוגן באמצעות פרטי כניסה במצב הפעלה ישירה).

הוראות לשליחת הודעות למכשירים במצב אתחול ישיר מופיעות במאמר בנושא שליחת הודעות שמופעל בהן אתחול ישיר.