הגדרה של אפליקציית לקוח להעברת הודעות בענן ב-Firebase ב-Android

לקוחות FCM דורשים מכשירים עם Android מגרסה 5.0 ואילך, שבהם מותקנת גם אפליקציית חנות Play, או אמולטור עם Android מגרסה 5.0 עם ממשקי Google API. חשוב לזכור שאתם לא מוגבלים לפריסה של אפליקציות ל-Android דרך חנות Google Play.

הגדרת ה-SDK

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

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

מוסיפים את הקוד הבא למניפסט של האפליקציה:

  • שירות שמרחיב את FirebaseMessagingService. צריך לעשות זאת אם רוצים לבצע טיפול בהודעות מעבר לקבלת התראות באפליקציות שפועלות ברקע. כדי לקבל התראות באפליקציות שבחזית, לקבל עומס נתונים, לשלוח הודעות למקור (upstream) וכו', צריך להרחיב את השירות הזה.
  • <service
        android:name=".java.MyFirebaseMessagingService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
  • (אופציונלי) ברכיב האפליקציה, רכיבי מטא-נתונים להגדרת סמל וצבע ברירת מחדל להתראות. מערכת Android משתמשת בערכים האלה כשלא מוגדר באופן מפורש סמל או צבע להודעות נכנסות.
  • <!-- 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 8.0 (רמת API‏ 26) ואילך, מומלץ להשתמש ב ערוצי התראות. FCM מספק ערוץ התראות ברירת מחדל עם הגדרות בסיסיות. אם אתם מעדיפים ליצור ערוץ ברירת מחדל משלכם ולהשתמש בו, צריך להגדיר את default_notification_channel_id למזהה של אובייקט ערוץ ההתראות, כפי שמוצג. הערך הזה ישמש את FCM בכל פעם שמסרים נכנסים לא מגדירים באופן מפורש ערוץ התראות. למידע נוסף, קראו את המאמר ניהול ערוצי התראות.
  • <meta-data
        android:name="com.google.firebase.messaging.default_notification_channel_id"
        android:value="@string/default_notification_channel_id" />

שליחת בקשה להרשאה לקבלת התראות בזמן ריצה ב-Android מגרסה 13 ואילך

ב-Android 13 נוספה הרשאה חדשה בסביבת זמן הריצה להצגת התראות. השינוי הזה משפיע על כל האפליקציות שפועלות ב-Android מגרסה 13 ואילך ומשתמשות בהתראות FCM.

כברירת מחדל, ה-SDK של FCM (גרסה 23.0.6 ואילך) כולל את ההרשאה POST_NOTIFICATIONS שמוגדרת במניפסט. עם זאת, האפליקציה תצטרך לבקש גם את גרסת זמן הריצה של ההרשאה הזו באמצעות הקבוע android.permission.POST_NOTIFICATIONS. האפליקציה לא תהיה רשאית להציג התראות עד שהמשתמש יעניק לה את ההרשאה הזו.

כדי לבקש את ההרשאה החדשה בסביבת זמן הריצה:

Kotlin+KTX

// Declare the launcher at the top of your Activity/Fragment:
private val requestPermissionLauncher = registerForActivityResult(
    ActivityResultContracts.RequestPermission(),
) { isGranted: Boolean ->
    if (isGranted) {
        // FCM SDK (and your app) can post notifications.
    } else {
        // TODO: Inform user that that your app will not show notifications.
    }
}

private fun askNotificationPermission() {
    // This is only necessary for API level >= 33 (TIRAMISU)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
            PackageManager.PERMISSION_GRANTED
        ) {
            // FCM SDK (and your app) can post notifications.
        } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
            // TODO: display an educational UI explaining to the user the features that will be enabled
            //       by them granting the POST_NOTIFICATION permission. This UI should provide the user
            //       "OK" and "No thanks" buttons. If the user selects "OK," directly request the permission.
            //       If the user selects "No thanks," allow the user to continue without notifications.
        } else {
            // Directly ask for the permission
            requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
        }
    }
}

Java

// Declare the launcher at the top of your Activity/Fragment:
private final ActivityResultLauncher<String> requestPermissionLauncher =
        registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
            if (isGranted) {
                // FCM SDK (and your app) can post notifications.
            } else {
                // TODO: Inform user that that your app will not show notifications.
            }
        });

private void askNotificationPermission() {
    // This is only necessary for API level >= 33 (TIRAMISU)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
                PackageManager.PERMISSION_GRANTED) {
            // FCM SDK (and your app) can post notifications.
        } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
            // TODO: display an educational UI explaining to the user the features that will be enabled
            //       by them granting the POST_NOTIFICATION permission. This UI should provide the user
            //       "OK" and "No thanks" buttons. If the user selects "OK," directly request the permission.
            //       If the user selects "No thanks," allow the user to continue without notifications.
        } else {
            // Directly ask for the permission
            requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
        }
    }
}

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

במאמר הרשאה בזמן ריצה להצגת התראות מפורטות שיטות מומלצות נוספות לגבי הזמנים שבהם האפליקציה צריכה לבקש מהמשתמש את ההרשאה POST_NOTIFICATIONS.

הרשאות התראות לאפליקציות שמטרגטות ל-Android 12L‏ (רמת API 32) ומטה

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

  • אם האפליקציה יוצרת את ערוץ ההתראות הראשון שלה כשהיא פועלת ברקע (כפי ש-SDK של FCM עושה כשמתקבלת התראה של FCM), מערכת Android לא תאפשר להצגת ההתראה ולא תציג למשתמש בקשה להענקת הרשאת התראות עד הפעם הבאה שהאפליקציה תיפתח. המשמעות היא שכל ההתראות שהתקבלו לפני פתיחת האפליקציה והמשתמש אישר את ההרשאה ייאבדו.
  • מומלץ מאוד לעדכן את האפליקציה כך שתתמקד ב-Android מגרסה 13 ואילך, כדי ליהנות מממשקי ה-API של הפלטפורמה ולבקש הרשאה. אם אי אפשר לעשות זאת, האפליקציה צריכה ליצור ערוצי התראות לפני שליחת ההתראות לאפליקציה כדי להפעיל את תיבת הדו-שיח של בקשת ההרשאה להצגת התראות ולוודא שלא ייאבדו התראות. מידע נוסף זמין במאמר שיטות מומלצות לקבלת הרשאות לקבלת התראות.

אופציונלי: הסרת ההרשאה POST_NOTIFICATIONS

כברירת מחדל, ה-SDK של FCM כולל את ההרשאה POST_NOTIFICATIONS. אם האפליקציה לא משתמשת בהתראות (דרך התראות FCM, דרך ערכת SDK אחרת או דרך הודעות שפרסמה האפליקציה ישירות) ואתם לא רוצים שהאפליקציה תכלול את ההרשאה, תוכלו להסיר אותה באמצעות הסמן remove של מיזוג המניפסטים. חשוב לזכור שהסרת ההרשאה הזו תמנע את הצגת כל ההתראות, ולא רק את ההתראות של FCM. מוסיפים את הטקסט הבא לקובץ המניפסט של האפליקציה:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" tools:node="remove"/>

גישה לטוקן הרישום של המכשיר

בהפעלה הראשונית של האפליקציה, ה-SDK של FCM יוצר אסימון רישום למכונה של אפליקציית הלקוח. כדי לטרגט מכשירים ספציפיים או ליצור קבוצות של מכשירים, צריך לגשת לאסימון הזה על ידי הרחבה של FirebaseMessagingService ועקיפת onNewToken.

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

אסימון הרישום עשוי להשתנות במקרים הבאים:

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

אחזור של טוקן הרישום הנוכחי

כשצריך לאחזר את האסימון הנוכחי, צריך להפעיל את הפונקציה FirebaseMessaging.getInstance().getToken():

Kotlin+KTX

FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
    if (!task.isSuccessful) {
        Log.w(TAG, "Fetching FCM registration token failed", task.exception)
        return@OnCompleteListener
    }

    // Get new FCM registration token
    val token = task.result

    // Log and toast
    val msg = getString(R.string.msg_token_fmt, token)
    Log.d(TAG, msg)
    Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
})

Java

FirebaseMessaging.getInstance().getToken()
    .addOnCompleteListener(new OnCompleteListener<String>() {
        @Override
        public void onComplete(@NonNull Task<String> task) {
          if (!task.isSuccessful()) {
            Log.w(TAG, "Fetching FCM registration token failed", task.getException());
            return;
          }

          // Get new FCM registration token
          String token = task.getResult();

          // Log and toast
          String msg = getString(R.string.msg_token_fmt, token);
          Log.d(TAG, msg);
          Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
        }
    });

מעקב אחר יצירת הטוקנים

קריאת החזרה (callback) של onNewToken מופעלת בכל פעם שנוצר טוקן חדש.

Kotlin+KTX

/**
 * Called if the FCM registration token is updated. This may occur if the security of
 * the previous token had been compromised. Note that this is called when the
 * FCM registration token is initially generated so this is where you would retrieve the token.
 */
override fun onNewToken(token: String) {
    Log.d(TAG, "Refreshed token: $token")

    // If you want to send messages to this application instance or
    // manage this apps subscriptions on the server side, send the
    // FCM registration token to your app server.
    sendRegistrationToServer(token)
}

Java

/**
 * There are two scenarios when onNewToken is called:
 * 1) When a new token is generated on initial app startup
 * 2) Whenever an existing token is changed
 * Under #2, there are three scenarios when the existing token is changed:
 * A) App is restored to a new device
 * B) User uninstalls/reinstalls the app
 * C) User clears app data
 */
@Override
public void onNewToken(@NonNull String token) {
    Log.d(TAG, "Refreshed token: " + token);

    // If you want to send messages to this application instance or
    // manage this apps subscriptions on the server side, send the
    // FCM registration token to your app server.
    sendRegistrationToServer(token);
}

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

בדיקה אם שירות Google Play Services מותקן

אפליקציות שמסתמכות על Play Services SDK צריכות תמיד לבדוק במכשיר אם יש קובץ APK תואם של Google Play Services לפני שהן ניגשות לתכונות של Google Play Services. מומלץ לעשות זאת בשני מקומות: ב-method‏ onCreate() של הפעילות הראשית וב-method‏ onResume() שלה. הבדיקה ב-onCreate() מבטיחה שלא ניתן להשתמש באפליקציה בלי בדיקה מוצלחת. הבדיקה ב-onResume() מבטיחה שאם המשתמש יחזור לאפליקציה שפועלת באמצעים אחרים, למשל באמצעות לחצן החזרה אחורה, הבדיקה עדיין תתבצע.

אם במכשיר לא מותקנת גרסה תואמת של Google Play Services, האפליקציה יכולה להפעיל את GoogleApiAvailability.makeGooglePlayServicesAvailable() כדי לאפשר למשתמשים להוריד את Google Play Services מחנות Play.

מניעת אתחול אוטומטי

כשיוצרים אסימון רישום מסוג FCM, הספרייה מעלה את המזהה ונתוני ההגדרה ל-Firebase. אם אתם מעדיפים למנוע יצירת אסימונים באופן אוטומטי, צריך להשבית את האיסוף ב-Analytics ואת האיפוס האוטומטי של FCM (צריך להשבית את שניהם) על ידי הוספת ערכי המטא-נתונים הבאים ל-AndroidManifest.xml:

<meta-data
    android:name="firebase_messaging_auto_init_enabled"
    android:value="false" />
<meta-data
    android:name="firebase_analytics_collection_enabled"
    android:value="false" />

כדי להפעיל מחדש את ההפעלה האוטומטית של FCM, צריך לבצע קריאה בסביבת זמן הריצה:

Kotlin+KTX

Firebase.messaging.isAutoInitEnabled = true

Java

FirebaseMessaging.getInstance().setAutoInitEnabled(true);

כדי להפעיל מחדש את האיסוף ב-Analytics, צריך להפעיל את השיטה setAnalyticsCollectionEnabled() של הכיתה FirebaseAnalytics. לדוגמה:

setAnalyticsCollectionEnabled(true);

הערכים האלה נשארים לאחר הפעלה מחדש של האפליקציה.

השלבים הבאים

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

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

חשוב לזכור: כדי ליהנות מהתכונות האלה, תצטרכו הטמעה בשרת ואת הפרוטוקולים של השרת (HTTP או XMPP), או הטמעה של Admin SDK.