簡體   English   中英

當應用程序處於前台或后台時如何使用 FCM 處理通知

[英]How to handle notifications with FCM when app is in either foreground or background

我用 firebase 來構建我的項目。
它還將使用 FCM(firebase 雲消息)。
但有一個問題。
當應用程序處於后台時,我無法處理 FCM(創建我的自定義通知)。

官網教程是這么說的
情況 1:應用程序前台 -> 覆蓋“onMessageReceived()”以創建您的自定義通知。
案例二:App后台->系統會直接創建通知。 我們不需要也不能做任何事情。 因為在這種情況下它不會觸發“onMessageReceived()”。

但是,如果當應用程序處於后台時我無能為力,我將無法創建自定義通知。 (例如用戶點擊通知后會彈出一個window顯示詳細信息。)

那么,當應用程序處於后台時,我如何使用 FCM 處理通知?

有一個壞消息。
Google 更改了“com.google.firebase:firebase-messaging:11.6.0”版本中的 Firebase 源代碼。
handelIntent 現在是“public final void 方法”。 這意味着我們不能覆蓋它。
如果要使用該解決方案,請將版本更改為“com.google.firebase:firebase-messaging:11.4.2”



試試我的方法。 它可以完美地在項目構建版本為Android 6.0以上(api級別23)上運行,我已經嘗試過了。

有比官方網站教程更好的方法

官網說,當應用程序在后台時,系統會創建通知。 所以你不能通過覆蓋“onMessageReceived()”來處理它。 因為“onMessageReceived()”僅在應用程序處於前台時觸發。

但事實並非如此。 實際上通知(當應用程序在后台時)是由 Firebase 庫創建的。

在我跟蹤了 firebase 庫代碼之后。 我找到了更好的方法。

步驟 1. 覆蓋 FirebaseMessagingService 中的“handleIntent()”而不是“onMessageReceived()”
為什么:
因為該方法將觸發應用程序在前台或后台。 因此,我們可以在兩種情況下處理 FCM 消息並創建自定義通知。

@Override
public void handleIntent(Intent intent) {
    Log.d( "FCM", "handleIntent ");
}


步驟 2. 解析來自 FCM 的消息
如何:
如果您不知道您設置的消息格式。 打印它並嘗試解析它。
這是基本插圖

Bundle bundle = intent.getExtras();
if (bundle != null) {
    for (String key : bundle.keySet()) {
        Object value = bundle.get(key);
        Log.d("FCM", "Key: " + key + " Value: " + value);
    }
}


步驟 2. 刪除應用在后台時 Firebase 庫創建的通知
為什么:
我們可以創建自定義通知。 但是 Firebase 庫創建的通知仍然存在(實際上它是由 ""super.handleIntent(intent)"" 創建的。下面有詳細說明。)。 然后我們會有兩個通知。 這就比較奇怪了。 所以我們必須刪除 Firebase 庫創建的通知

如何(項目構建級別為 Android 6.0 以上):
識別我們要刪除的通知並獲取信息。 並使用“notificationManager.cancel()”來刪除它們。

private void removeFirebaseOrigianlNotificaitons() {

    //check notificationManager is available
    NotificationManager notificationManager = 
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    if (notificationManager == null )
        return;

    //check api level for getActiveNotifications()
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        //if your Build version is less than android 6.0
        //we can remove all notifications instead. 
        //notificationManager.cancelAll();
        return;
    }


    //check there are notifications
    StatusBarNotification[] activeNotifications = 
        notificationManager.getActiveNotifications();
    if (activeNotifications == null)
        return;

    //remove all notification created by library(super.handleIntent(intent))
    for (StatusBarNotification tmp : activeNotifications) {
        Log.d("FCM StatusBarNotification", 
            "StatusBarNotification tag/id: " + tmp.getTag() + " / " + tmp.getId());
        String tag = tmp.getTag();
        int id = tmp.getId();

        //trace the library source code, follow the rule to remove it.
        if (tag != null && tag.contains("FCM-Notification"))
            notificationManager.cancel(tag, id);
    }
}

我的整個示例代碼:

public class MyFirebaseMessagingService extends FirebaseMessagingService {

private static int notificationCount=0;

@Override
public void handleIntent(Intent intent) {
    //add a log, and you'll see the method will be triggered all the time (both foreground and background).
    Log.d( "FCM", "handleIntent");

    //if you don't know the format of your FCM message,
    //just print it out, and you'll know how to parse it
    Bundle bundle = intent.getExtras();
    if (bundle != null) {
        for (String key : bundle.keySet()) {
            Object value = bundle.get(key);
            Log.d("FCM", "Key: " + key + " Value: " + value);
        }
    }

    //the background notification is created by super method
    //but you can't remove the super method. 
    //the super method do other things, not just creating the notification
    super.handleIntent(intent);

    //remove the Notificaitons
    removeFirebaseOrigianlNotificaitons();

    if (bundle ==null)
        return;

    //pares the message
    CloudMsg cloudMsg = parseCloudMsg(bundle);

    //if you want take the data to Activity, set it
    Bundle myBundle = new Bundle();
    myBundle.putSerializable(TYPE_FCM_PLATFORM, cloudMsg);
    Intent myIntent = new Intent(this, NotificationActivity.class);
    myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    myIntent.putExtras(myBundle);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, notificationCount, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    //set the Notification
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
            .setSmallIcon(R.mipmap.icon)
            .setContentTitle(cloudMsg.getTitle())
            .setContentText(cloudMsg.getMessage())
            .setAutoCancel(true)
            .setContentIntent(pendingIntent);

    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(notificationCount++, notificationBuilder.build());
}



/**
 * parse the message which is from FCM
 * @param bundle
 */
private CloudMsg parseCloudMsg(Bundle bundle) {
    String title = null, msg=null;

    //if the message is sent from Firebase platform, the key will be that
    msg = (String) bundle.get("gcm.notification.body");

    if(bundle.containsKey("gcm.notification.title"))
    title = (String) bundle.get("gcm.notification.title");

    //parse your custom message
    String testValue=null;
    testValue =  (String) bundle.get("testKey");

    //package them into a object(CloudMsg is your own structure), it is easy to send to Activity.
    CloudMsg cloudMsg = new CloudMsg(title, msg, testValue);
    return cloudMsg;
}


/**
 * remove the notification created by "super.handleIntent(intent)"
 */
    private void removeFirebaseOrigianlNotificaitons() {

    //check notificationManager is available
    NotificationManager notificationManager = 
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    if (notificationManager == null )
        return;

    //check api level for getActiveNotifications()
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        //if your Build version is less than android 6.0
        //we can remove all notifications instead. 
        //notificationManager.cancelAll();
        return;
     }

    //check there are notifications
    StatusBarNotification[] activeNotifications = 
        notificationManager.getActiveNotifications();
    if (activeNotifications == null)
        return;

    //remove all notification created by library(super.handleIntent(intent))
    for (StatusBarNotification tmp : activeNotifications) {
        Log.d("FCM StatusBarNotification", 
            "tag/id: " + tmp.getTag() + " / " + tmp.getId());
        String tag = tmp.getTag();
        int id = tmp.getId();

        //trace the library source code, follow the rule to remove it.
        if (tag != null && tag.contains("FCM-Notification"))
            notificationManager.cancel(tag, id);
    }
}
}

但是,如果當應用程序處於后台時我什么都不做,我就無法創建我的自定義通知。 (例如,當用戶點擊通知后,它會彈出一個窗口顯示詳細信息。)

那么當應用程序在后台時如何使用 FCM 處理通知?

首先,您需要創建發送到 fcm 服務器的正確消息負載。 示例:

{
  "to": "topic_name",
  "priority": "high",
  "data": {
    "field1": "field1 value" 
    "field2": "field2 value" 
  }

  "notification" : {
      "body" : "Lorem ipsum",
      "title" : "sampke title" 
      "click_action": "SHOW_DETAILS" 
    }
}

data負載是您希望在用戶單擊通知后顯示為消息詳細信息的實際數據, notification負載表示生成的通知的外觀(可以設置更多屬性),您不需要自己構建通知,您只需需要在這里設置它的屬性。

要在用戶點擊通知后顯示您的活動,您需要設置與click_action對應的意圖過濾器:

<intent-filter>
     <action android:name="SHOW_DETAILS"/>
     <category android:name="android.intent.category.DEFAULT"/>
 </intent-filter>

因此,當用戶點擊通知時,將自動啟動具有上述意圖過濾器的活動。 最后一步是在點擊通知后啟動活動時檢索數據。 這很容易。 自定義數據通過包傳遞給活動。 在您的活動的onCreate方法中執行以下操作:

Bundle bundle = getIntent().getExtras();
if(bundle.getString("action").equals("SHOW_DETAILS")) /*This indicates activity is launched from notification, not directly*/
{
 //Data retrieved from notification payload send 
 String filed1 = bundle.getString("field1");
 String filed2 = bundle.getString("field2");
}

如果應用程序未運行或在后台,則上述所有內容均有效。 如果您的應用程序處於前台,則不會創建通知。 相反,您將收到onMessageReceived()事件,以便您可以在那里處理相同的數據(我想您知道如何)。

參考:

https://firebase.google.com/docs/cloud-messaging/http-server-ref https://github.com/firebase/quickstart-android/tree/master/messaging

您需要使用 FCM 數據消息才能在 android 應用程序中創建自定義通知。即使您的應用程序在后台,也會調用onMessageReceived ,因此您可以處理數據並顯示自定義通知。

https://firebase.google.com/docs/cloud-messaging/android/receive

必須從服務器發送的數據消息格式:

{"message":{
"token":"Your Device Token",
"data":{
  "Nick" : "Mario",
  "body" : "great match!",
  "Room" : "PortugalVSDenmark"
}
}
}

如果您的應用程序被handleIntent()FCM將不會發送后台通知,正如您在關於handleIntent()解決方案的回答中所述,它可能適用於某些設備和某些舊版本的FCM ,如果您使用@override方法firebase 的官方文檔中沒有描述,您可能會在這里遇到一些問題,使用它的風險自負

解決辦法是什么?

您需要在FCM旁邊使用自己的推送通知服務,例如Telegram

或者在GCM旁邊使用SyncAdapter ,比如Gmail

因此,如果您需要它像那些應用程序一樣成功運行,則必須使用自己的 hack

當您的應用終止運行或后台運行時, 永遠不會觸發onMessageReceive

你該怎么辦

推送時,僅在以下示例中添加數據項; 你可以用郵遞員

首先需要以下網址: https : //fcm.googleapis.com/fcm/send發送時,您可以選擇POST

在添加標題后,應這樣:

內容類型:application / json

授權:key =“您的服務器密鑰”

  {
        "to": "/topics/yourTopics",


        "data": {
            "title": "BlaBla",
            "body":"BlaBla"
         }
    }

處理;

class PushService : FirebaseMessagingService() {

     override fun onMessageReceived(remoteMessage: RemoteMessage?) {
    for (i in remoteMessage!!.data.keys) {
    //Your maps here you can do something..
    }


        val contentIntent = PendingIntent.getActivity(this,
                0, intent, PendingIntent.FLAG_UPDATE_CURRENT)

        val uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
// Your notification set here!! 
        val b = NotificationCompat.Builder(this, "1")
        val n = b.setTicker(remoteMessage!!.data["title"])
                .setWhen(0)
                .setAutoCancel(true)
                .setContentTitle(remoteMessage.data["title"])
                .setContentText(remoteMessage.data["body"])
                .setShowWhen(true)
                .setContentIntent(contentIntent)
                .setSound(uri)
                .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
                .setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
                .setStyle(NotificationCompat.BigTextStyle().bigText(remoteMessage.data["body"]))


        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            b.setSmallIcon(R.drawable.ic_push_notification_transparent)
            b.color = ContextCompat.getColor(this, R.color.colorAccent)
        } else {
            b.setSmallIcon(R.mipmap.ic_launcher)
        }

        val notificationManager = this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel("1",
                    "ic_notification",
                    NotificationManager.IMPORTANCE_DEFAULT)
            notificationManager.createNotificationChannel(channel)
        }

        if (notificationManager != null) {
            notificationManager.cancel(1)
            notificationManager.notify(1, n.build())
        }
    }


}

公共 class FirebaseMessageReceiver 擴展 FirebaseMessagingService {

private static final String TAG = "main";
String s12;
String channel_id = "general";
Intent intent;

@Override
public void onNewToken(@NonNull String token)
{
    Log.d(TAG, "Refreshed token: " + token);
}
@Override
public void
onMessageReceived(RemoteMessage remoteMessage) {
    s12=remoteMessage.getNotification().getClickAction();
    Log.d("tttt",(remoteMessage.getData().toString()));
    Log.d("ttttttt",(remoteMessage.getNotification().toString()));
    if (remoteMessage.getNotification() != null) {
        showNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
    }
    //
}

public void handleIntent(Intent intent)
{
    try
    {
        if (intent.getExtras() != null)
        {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("FirebaseMessageReceiver");

            for (String key : intent.getExtras().keySet())
            {
                builder.addData(key, intent.getExtras().get(key).toString());
            }

            onMessageReceived(builder.build());
        }
        else
        {
            super.handleIntent(intent);
        }
    }
    catch (Exception e)
    {
        super.handleIntent(intent);
    }
}

private RemoteViews getCustomDesign(String title, String message) {
    RemoteViews remoteViews = new RemoteViews(getApplicationContext().getPackageName(), R.layout.notification);
    remoteViews.setTextViewText(R.id.title111, title);
    remoteViews.setTextViewText(R.id.message111, message);
    remoteViews.setImageViewResource(R.id.icon111, R.drawable.favicon);
    return remoteViews;
}
// Method to display the notifications
public void showNotification(String title, String message) {
    intent  = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(s12));
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent notifyIntent = PendingIntent.getActivity(this, 0, intent,
            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
    Log.d("notifyy",notifyIntent.toString());
    NotificationCompat.Builder builder
            = new NotificationCompat
            .Builder(getApplicationContext(),
            channel_id)
            .setSmallIcon(R.drawable.favicon)
            .setAutoCancel(true)
            .setVibrate(new long[]{1000, 1000, 1000, 1000, 1000})
            .setOnlyAlertOnce(true)
            .setContentIntent(notifyIntent);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        builder = builder.setContent(getCustomDesign(title, message));
    }
    else {
        builder = builder.setContentTitle(title)
                .setContentText(message)
                .setSmallIcon(R.drawable.favicon);
    }
    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    // Check if the Android Version is greater than Oreo
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel notificationChannel = new NotificationChannel(channel_id, "web_app",
                NotificationManager.IMPORTANCE_HIGH);
        notificationManager.createNotificationChannel(
                notificationChannel);
    }
    notificationManager.notify(0, builder.build());
}

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM