Bermigrasi dari FCM HTTP v1 API ke AndroidConfigV2

Dengan FCM AndroidConfigV2, Anda dapat mengirim pesan berbasis intent ke perangkat Android dengan pengiriman notifikasi yang tepat waktu dan API yang disederhanakan.

Panduan ini membahas cara memigrasikan permintaan pengiriman backend Anda dari AndroidConfig ke AndroidConfigV2 dan cara mengupdate klien aplikasi Android Anda dari penanganan onMessageReceived lama ke callback klien v2 baru, onNotificationReceived dan onBackgroundSyncReceived.

Yang baru di AndroidConfigV2

FCM AndroidConfigV2 API menyederhanakan pengalaman developer dengan memperkenalkan dua jenis pesan:

  • RemoteNotification: Direkomendasikan untuk semua pesan FCM yang menampilkan notifikasi mendesak dan sensitif terhadap waktu yang dapat dilihat pengguna. Pesan ini mengabaikan langkah-langkah penghematan baterai dan dikirim tanpa penundaan. Di perangkat, FCM SDK dan layanan Google Play bertanggung jawab untuk memposting notifikasi ke NotificationManager Android.
  • BackgroundSync: Pesan data yang tidak mendesak yang ditujukan untuk sinkronisasi latar belakang dan update status aplikasi. Pengiriman dapat dikelompokkan atau ditunda untuk mengoptimalkan masa pakai baterai.
Fitur Lama (AndroidConfig v1) Baru (AndroidConfigV2)
Kolom konfigurasi message.android message.android_v2
Definisi prioritas priority: "high" atau priority: "normal" eksplisit Tersirat oleh jenis union (remote_notification untuk pemberitahuan mendesak versus background_sync untuk sinkronisasi yang tidak mendesak)
Posting notifikasi Aplikasi memanggil NotificationManager.notify() secara manual FCM SDK dan GMS Core memposting secara langsung atau menggunakan NotificationResponse
Callback klien • onMessageReceived(RemoteMessage)
• onDeletedMessages()
• onNotificationReceived(RemoteMessage)
• onBackgroundSyncReceived(RemoteMessage)
• onDeletedMessages()
Dapat diciutkan Bervariasi; memerlukan setelan eksplisit Kedua jenis pesan dapat diciutkan atau tidak dapat diciutkan (tidak dapat diciutkan secara default)

Mengizinkan permintaan kirim AndroidConfigV2

Anda dapat terus menggunakan token akses OAuth 2.0 yang berasal dari akun layanan Firebase menggunakan Kredensial Default Aplikasi Google atau Admin SDK, dan mengirim permintaan POST ke endpoint messages:send HTTP v1.

Jika Anda tidak menggunakan akun layanan Firebase, pastikan untuk menetapkan akun khusus Anda ke peran Admin Firebase Cloud Messaging API (roles/firebase.messagingAdmin) dan meminta cakupan OAuth 2.0 https://www.googleapis.com/auth/firebase.messaging saat membuat token akses:

POST https://fcm.googleapis.com/v1/projects/YOUR_PROJECT_ID/messages:send HTTP/1.1
Authorization: Bearer YOUR_OAUTH_ACCESS_TOKEN
Content-Type: application/json

Memperbarui permintaan kirim server (REST)

Untuk mengirim permintaan AndroidConfigV2 menggunakan REST API, ganti objek android dalam isi permintaan Anda dengan android_v2. Dalam android_v2, tentukan parameter umum (seperti ttl, collapse_key, data, dan restricted_package_name), serta berikan salah satu kolom gabungan berikut: remote_notification atau background_sync.

Mengirim pesan RemoteNotification

Untuk mengirim notifikasi mendesak yang ditampilkan kepada pengguna, sertakan objek remote_notification dan payload notification yang direkomendasikan. Secara default, mutable_content ditetapkan ke false. GMS Core akan langsung merender dan memposting notifikasi ke area notifikasi tanpa mengeksekusi kode aplikasi latar belakang.

Contoh JSON permintaan HTTP lengkap (Notifikasi yang dirender otomatis)

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1
Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA

{
  "message": {
    "token": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "notification": {
      "title": "FCM Message",
      "body": "This is an FCM notification message!"
    },
    "android_v2": {
      "ttl": "3600s",
      "remote_notification": {
        "mutable_content": false,
        "notification": {
          "title": "Order update",
          "body": "Your order has been shipped!",
          "icon": "ic_notification_custom",
          "sound": "default",
          "tag": "alert_tag_1",
          "id": 100
        }
      }
    }
  }
}

Mengirim RemoteNotification dengan konten yang dapat diubah

Jika aplikasi Anda perlu mengubah notifikasi di perangkat sebelum ditampilkan, tetapkan mutable_content: true di dalam remote_notification. Tindakan ini memerintahkan GMS Core untuk mengikat ke aplikasi klien Anda dan memanggil onNotificationReceived(). Hal ini berguna saat Anda ingin mendekripsi payload terenkripsi end-to-end, melampirkan avatar pengguna, atau melokalkan string.

Pastikan untuk menyertakan objek notification di dalam remote_notification meskipun mutable_content adalah true. GMS Core menggunakan objek notification ini sebagai notifikasi penggantian jika waktu tunggu callback klien habis atau melebihi batas penekanan.

Jika Anda bermigrasi dari pesan data v1 lama dan ingin FCM mengirimkan payload ke penginstalan klien v1 lama sebagai pesan data murni, tetapkan use_as_v1_data_message: true di dalam remote_notification.

Contoh JSON permintaan HTTP lengkap

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1
Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA

{
  "message": {
    "token": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "data": {
      "encrypted_content": "U2FsdGVkX19vN2m+",
      "sender_id": "user_98124"
    },
    "android_v2": {
      "ttl": "3600s",
      "remote_notification": {
        "mutable_content": true,
        "use_as_v1_data_message": true,
        "notification": {
          "title": "New message",
          "body": "You have a new message",
          "tag": "chat_alert",
          "id": 1001
        }
      }
    }
  }
}

Mengirim pesan BackgroundSync

Untuk mengirim pesan yang tidak mendesak untuk sinkronisasi data latar belakang, update status senyap, atau mengupdate badge atau widget aplikasi, gunakan objek background_sync. Jangan gunakan pesan ini untuk memposting notifikasi yang terlihat oleh pengguna, karena pesan ini dapat dikelompokkan atau ditunda untuk mengoptimalkan masa pakai baterai perangkat.

Contoh JSON permintaan HTTP lengkap

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1
Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA

{
  "message": {
    "token": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "data": {
      "score": "FETCH_UPDATES",
      "sync_action": "FETCH_UPDATES"
    },
    "android_v2": {
      "ttl": "86400s",
      "collapse_key": "app_state_sync",
      "background_sync": {}
    }
  }
}

Mengupdate callback klien Android

Untuk menerima pesan AndroidConfigV2 di Android, upgrade aplikasi Anda agar menggunakan firebase-messaging SDK terbaru. Perbarui layanan Anda yang memperluas FirebaseMessagingService dengan mengimplementasikan onNotificationReceived() dan onBackgroundSyncReceived().

Menginstal SDK EAP

Selama EAP, SDK firebase-messaging v2 didistribusikan sebagai arsip repositori Maven lokal, bukan melalui repositori Maven publik Google.

  1. Tambahkan direktori m2repository yang berisi firebase-messaging:26.1.0-eap01 ke direktori utama project Android Anda (<project-root>/m2repository) menggunakan salah satu opsi berikut:

    1. Opsi A: Download arsip bawaan: Download FirebaseMessaging_26.1.0-eap01.zip dan ekstrak direktori m2repository ke direktori root project Android Anda (<project-root>/m2repository).
    2. Opsi B: Build dari GitHub dengan Gradle: Clone cabang feature/fcm-android-config-v2-eap dari firebase/firebase-android-sdk, build repositori Maven lokal, dan salin direktori build/m2repository yang dihasilkan ke root project Android Anda:

      git clone --branch feature/fcm-android-config-v2-eap --single-branch \
        https://github.com/firebase/firebase-android-sdk.git
      cd firebase-android-sdk
      ./gradlew -PprojectsToPublish="firebase-messaging" firebasePublish
      cp -R build/m2repository /path/to/your/android-project/m2repository
      
  2. Dalam settings.gradle.kts (atau settings.gradle) level project, tambahkan direktori m2repository lokal ke bagian atas blok repositories, di atas google():

    Kotlin

    dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            maven { url = uri("${rootDir}/m2repository") }
            google()
            mavenCentral()
        }
    }
    

    Groovy

    dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            maven { url "${rootDir}/m2repository" }
            google()
            mavenCentral()
        }
    }
    
  3. Di app/build.gradle.kts (atau app/build.gradle) level modul, update dependensi firebase-messaging ke 26.1.0-eap01:

    Kotlin

    dependencies {
        implementation("com.google.firebase:firebase-messaging:26.1.0-eap01")
    }
    

    Groovy

    dependencies {
        implementation 'com.google.firebase:firebase-messaging:26.1.0-eap01'
    }
    
  4. Sinkronkan project Anda dengan file Gradle.

Menangani RemoteNotifications dengan onNotificationReceived

Dengan AndroidConfigV2, pesan RemoteNotification akan ditampilkan kecuali jika mutable_content ditetapkan ke benar (true) atau pesan tersebut secara eksplisit disenyapkan di onNotificationReceived().

Saat RemoteNotification tiba dengan mutable_content: true, GMS Core akan mengikat ke aplikasi Anda dan memanggil onNotificationReceived(). Metode Anda harus menampilkan NotificationResponse dalam waktu 20 detik.

Menampilkan notifikasi yang diubah

Objek Notification yang Anda teruskan ke NotificationResponse.create menggantikan properti payload penggantian remote_notification.notification server yang ditentukan dalam permintaan kirim. Untuk mempertahankan nilai dari permintaan kirim, baca nilai tersebut dari message.notification (message.getNotification() di Java) saat menerapkan modifikasi di perangkat:

Kotlin

import androidx.core.app.NotificationCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.NotificationResponse
import com.google.firebase.messaging.RemoteMessage

class MyFirebaseMessagingService : FirebaseMessagingService() {

    override fun onNotificationReceived(message: RemoteMessage): NotificationResponse {
        val serverNotif = message.notification
        val channelId = serverNotif?.channelId ?: "default_channel"
        // Keep the server-defined title unchanged, or fall back to default
        val title = serverNotif?.title ?: "New message"
        // Modify the notification body on-device (for example, decrypting data)
        val decryptedBody = decryptPayload(message.data["encrypted_content"])

        val builder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_stat_notification)
            .setContentTitle(title)
            .setContentText(decryptedBody)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setAutoCancel(true)

        // Return the response for the open-source FCM SDK to post to the Android platform
        return NotificationResponse.create("optional_tag", 100, builder.build())
    }
}

Java

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import com.google.firebase.messaging.NotificationResponse;
import androidx.core.app.NotificationCompat;

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public NotificationResponse onNotificationReceived(RemoteMessage message) {
        RemoteMessage.Notification serverNotif = message.getNotification();
        String channelId = (serverNotif != null && serverNotif.getChannelId() != null)
                ? serverNotif.getChannelId()
                : "default_channel";
        // Keep the server-defined title unchanged, or fall back to default
        String title = (serverNotif != null && serverNotif.getTitle() != null)
                ? serverNotif.getTitle()
                : "New message";
        // Modify the notification body on-device (for example, decrypting data)
        String decryptedBody = decryptPayload(message.getData().get("encrypted_content"));

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.ic_stat_notification)
                .setContentTitle(title)
                .setContentText(decryptedBody)
                .setPriority(NotificationCompat.PRIORITY_HIGH)
                .setAutoCancel(true);

        // Return the response for the open-source FCM SDK to post to the Android platform
        return NotificationResponse.create("optional_tag", 100, builder.build());
    }
}

Menyembunyikan notifikasi

Jika pengguna sedang membuka layar atau chat yang relevan, Anda dapat menyembunyikan notifikasi dengan menampilkan NotificationResponse.suppress():

Kotlin

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner

override fun onNotificationReceived(message: RemoteMessage): NotificationResponse {
    val chatId = message.data["chat_id"]
    val isAppForeground = ProcessLifecycleOwner.get()
        .lifecycle
        .currentState
        .isAtLeast(Lifecycle.State.STARTED)

    if (isAppForeground && chatRepository.isConversationActive(chatId)) {
        // Suppress notification display because the user is actively viewing this chat
        return NotificationResponse.suppress()
    }

    val builder = buildNotificationForChat(message)
    return NotificationResponse.create("chat_tag", 101, builder.build())
}

Java

import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.ProcessLifecycleOwner;

@Override
public NotificationResponse onNotificationReceived(RemoteMessage message) {
    String chatId = message.getData().get("chat_id");
    boolean isAppForeground = ProcessLifecycleOwner.get()
            .getLifecycle()
            .getCurrentState()
            .isAtLeast(Lifecycle.State.STARTED);

    if (isAppForeground && chatRepository.isConversationActive(chatId)) {
        // Suppress notification display because the user is actively viewing this chat
        return NotificationResponse.suppress();
    }

    NotificationCompat.Builder builder = buildNotificationForChat(message);
    return NotificationResponse.create("chat_tag", 101, builder.build());
}

Notifikasi streaming atau batalkan pemberitahuan lama (FcmNotificationManager)

Jika Anda perlu memposting beberapa notifikasi untuk satu push masuk, atau membatalkan notifikasi yang sudah tidak berlaku sebelum menampilkan notifikasi baru, gunakan FcmNotificationManager:

Kotlin

override fun onNotificationReceived(message: RemoteMessage): NotificationResponse {
    // Retrieve the scoped manager for this message execution
    val manager = getFcmNotificationManager(message)

    // 1. Cancel an outdated notification right away
    manager.cancelNow("message_tag", 50)

    // 2. Post the item notification immediately
    val itemNotif = NotificationCompat.Builder(this, "chat_channel")
        .setSmallIcon(R.drawable.ic_message)
        .setContentTitle("Alex")
        .setContentText(message.data["text"])
    manager.postNow("item_tag", 51, itemNotif.build())

    // 3. Post a group summary notification
    val summaryNotif = NotificationCompat.Builder(this, "chat_channel")
        .setSmallIcon(R.drawable.ic_message)
        .setContentTitle("New Conversations")
        .setGroupSummary(true)
    manager.postNow("summary_tag", 52, summaryNotif.build())

    // 4. Return finished() to complete the streaming workflow
    return manager.finished()
}

Java

@Override
public NotificationResponse onNotificationReceived(RemoteMessage message) {
    // Retrieve the scoped manager for this message execution
    FcmNotificationManager manager = getFcmNotificationManager(message);

    // 1. Cancel an outdated notification right away
    manager.cancelNow("message_tag", 50);

    // 2. Post the item notification immediately
    NotificationCompat.Builder itemNotif = new NotificationCompat.Builder(this, "chat_channel")
            .setSmallIcon(R.drawable.ic_message)
            .setContentTitle("Alex")
            .setContentText(message.getData().get("text"));
    manager.postNow("item_tag", 51, itemNotif.build());

    // 3. Post a group summary notification
    NotificationCompat.Builder summaryNotif = new NotificationCompat.Builder(this, "chat_channel")
            .setSmallIcon(R.drawable.ic_message)
            .setContentTitle("New Conversations")
            .setGroupSummary(true);
    manager.postNow("summary_tag", 52, summaryNotif.build());

    // 4. Return finished() to complete the streaming workflow
    return manager.finished();
}

Menangani pesan BackgroundSync menggunakan onBackgroundSyncReceived

Untuk memproses pesan BackgroundSync di Android, gunakan onBackgroundSyncReceived():

Kotlin

override fun onBackgroundSyncReceived(message: RemoteMessage) {
    val syncCommand = message.data["sync_action"]

    try {
        // Perform local database synchronization or cache refresh
        AppDataRepository.getInstance(applicationContext).syncWithServer(syncCommand)
    } catch (e: Exception) {
        Log.e("FCM", "Background sync operation failed", e)
    }
    // Execution completes -> GMS Core marks the message as handled and unbinds.
}

Java

@Override
public void onBackgroundSyncReceived(RemoteMessage message) {
    String syncCommand = message.getData().get("sync_action");

    try {
        // Perform local database synchronization or cache refresh
        AppDataRepository.getInstance(getApplicationContext()).syncWithServer(syncCommand);
    } catch (Exception e) {
        Log.e("FCM", "Background sync operation failed", e);
    }
    // Execution completes -> GMS Core marks the message as handled and unbinds.
}

Menangani penghapusan pesan yang tertunda menggunakan onDeletedMessages

Dalam beberapa situasi, seperti saat perangkat tidak terhubung ke FCM dalam jangka waktu yang lama atau saat antrean server penuh, FCM dapat menghapus pesan yang tertunda sebelum pengiriman. Dalam kasus ini, ganti onDeletedMessages():

Kotlin

override fun onDeletedMessages() {
    // Perform a full state synchronization with your app server
    AppDataRepository.getInstance(applicationContext).scheduleFullSync()
}

Java

@Override
public void onDeletedMessages() {
    // Perform a full state synchronization with your app server
    AppDataRepository.getInstance(getApplicationContext()).scheduleFullSync();
}

Memigrasikan aplikasi tertentu

Mengirimkan notifikasi terenkripsi end-to-end (E2EE)

Saat mengirimkan notifikasi terenkripsi end-to-end menggunakan RemoteNotification, konten notifikasi yang didekripsi tetap berada dalam aplikasi Anda dan platform Android:

  1. Mengirimkan notifikasi yang dapat diubah: Server Anda mengirimkan RemoteNotification dengan mutable_content: true, payload terenkripsi di data, dan cadangan generik yang tidak dienkripsi notification. GMS Core mengirimkan pesan terenkripsi ke FCM SDK open source di dalam aplikasi Anda.
  2. Mendekripsi dan menampilkan notifikasi: FCM SDK memanggil onNotificationReceived(). Aplikasi Anda mendekripsi payload secara lokal, mem-build Notification Android yang didekripsi akhir, dan meneruskannya kembali ke FCM SDK open source menggunakan NotificationResponse atau FcmNotificationManager.
  3. Memposting ke platform dan melaporkan metadata: SDK FCM open source memposting notifikasi yang didekripsi langsung ke API NotificationManager platform Android dan hanya mengirim metadata notifikasi, seperti ID notifikasi dan stempel waktu, kembali ke GMS Core untuk visibilitas pengiriman. Konten yang didekripsi tidak pernah dikirim ke GMS Core.
  4. Memposting notifikasi cadangan jika perlu: Hanya jika aplikasi Anda gagal merespons dalam waktu tunggu 20 detik atau melebihi batas penekanan latar belakang, GMS Core akan memposting notification cadangan umum langsung ke platform Android.

Diagram arsitektur yang menunjukkan alur pengiriman notifikasi terenkripsi end-to-end dalam 4 langkah antara GMS Core, FCM SDK open source, aplikasi Anda, dan NotificationManager API platform Android.

Memahami penonaktifan dan waktu tunggu notifikasi

Untuk mempertahankan pengiriman yang andal di seluruh ekosistem Android, GMS Core menerapkan waktu tunggu pemrosesan dan batas penekanan notifikasi saat menangani pesan RemoteNotification:

Waktu tunggu pemrosesan

Jika mutable_content ditetapkan ke true, metode onNotificationReceived() Anda harus menampilkan NotificationResponse dalam waktu 20 detik. Jika eksekusi melebihi batas ini, callback akan dibatalkan dan GMS Core akan otomatis memposting notifikasi penggantian yang dirender dari payload remote_notification.notification.

Rasio penekanan notifikasi

Karena pesan RemoteNotification mengabaikan batasan Istirahatkan untuk segera memberi tahu pengguna dan dikirim tanpa penundaan, aplikasi diharapkan menampilkan notifikasi untuk pesan RemoteNotification yang diterima.

Setiap aplikasi diizinkan untuk menyembunyikan hingga 25% traffic RemoteNotification-nya saat berjalan di latar belakang. Jika tingkat penghentian aplikasi melebihi 25%, GMS Core akan otomatis merender dan memposting notifikasi pengganti yang dirender dari payload remote_notification.notification.

Penekanan yang dilakukan saat aplikasi aktif di latar depan tidak dihitung dalam batas ini. Aplikasi yang diberi izin penggunaan latar belakang tanpa batas juga dikecualikan dari batas penekanan latar belakang.