【问题标题】:Android FCM - how to show only one notificationAndroid FCM - 如何只显示一个通知
【发布时间】:2017-09-22 11:38:44
【问题描述】:

我正在从 FCM 向 Android 设备发送推送通知,这是通过向 FCM 发送包含 JSON 正文的 POST 消息来完成的。

如果我两次发送相同的 JSON 正文,Android 设备将显示两个通知(或三个,或四个,...)。但我希望它只显示一个。

“collapse_key”应该可以解决这个问题,对吧? (FCM Documentation)

但是应该在哪里或如何插入呢?

这个 SO 问题回答了这个问题,但没有给出示例:Can FCM notification on Android overwrite previous one?

当前 JSON 正文:

{
    "notification": {
        "title": "MyAPP",
        "body": "Open MyAPP to access your data",
        "click_action" : "OPEN_MAINACTIVITY",
        "icon": "ic_launcher_red",
        "color": "#ff0000"
    },
    "data": {
        "extra1":"sample1",
        "extra2":"sample2"
    },
    "registration_ids":[
        "--my_id--"
    ]
}

我已经尝试过多种方式来包含“collapse_key”,但到目前为止还没有成功。仍然是多个通知。欢迎任何帮助。

【问题讨论】:

    标签: android json firebase push firebase-cloud-messaging


    【解决方案1】:

    好吧,我一直在挖掘并找到答案:它不是“collapse_key”,我应该在通知中使用“tag”选项。

    因此,使用此 JSON 只会显示一个通知:

    {
        "notification": {
            "title": "MyAPP",
            "body": "Open MyAPP to access your data",
            "click_action" : "OPEN_MAINACTIVITY",
            "icon": "ic_launcher_red",
            "color": "#ff0000"
            "tag": "unique_tag"
        },
        "data": {
            "extra1":"sample1",
            "extra2":"sample2"
        },
        "registration_ids":[
            "--my_id--"
        ]
    }
    

    希望这对其他人有所帮助!

    如果有人想进一步解释“collapse_key”,我会很高兴,显然我误解了。

    【讨论】:

    • 如果发送不同的消息具有相同的collapse_key,最后一条消息将替换上一条消息。 "collapse_key" : "用于消息的相同字符串被替换为新的一个"
    • 是的,我希望这是行为,但它不断创建新消息。这就是我打开这个问题的方式,也许有人可以解释“collapse_key”应该去哪里。然后我发现“标签”元素成功了,并发布了答案。你能使用“collapse_key”吗?能否提供 JSON 示例?
    • 它与“To”键处于同一级别。对于我的一个项目,我让它工作,然后由于更改请求而将其删除,但是它工作正常。
    • 我已经在我的案例中包含了标签,但它似乎仍然不起作用
    • @GILO 您需要将“标签”作为 android 特定选项发送,请在此处查看我的答案:stackoverflow.com/a/63898806/9960700
    【解决方案2】:

    "tag" 选项是您正在寻找的。如果新通知与通知托盘中已显示的通知具有相同的标签,则新通知替换旧通知。

    更新: 更新的FCM docs 展示了如何将通用字段(所有平台通用)与平台特定参数分开。由于 "tag" 是 android 特定的选项,这是让它现在工作的方法:

    {
       notification: {
           title: "Title Here",
           body: "Body Here",
       },
       //These are android-specific options to override
       android: {
           notification: {
               tag: "My-Tag"
           }
       },
       token: tokenHere
    };
    

    然而,这似乎引发了 Invalid JSON 错误并且无法识别“tag”字段。 这不起作用

    {
       notification: {
           title: "Title Here",
           body: "Body Here",
           tag: "My-Tag"
       },
       token: tokenHere
    }
    

    【讨论】:

    • 如何对通知进行分组?我的意思是如果通知来自同一个应用程序,它们应该堆叠。你知道怎么做吗?
    • 所以我正在寻找反向配置。我想显示多个通知。我应该在其中使用不同的标签吗?
    【解决方案3】:

    用于 FCM 的 C# Rest API:

     WebRequest tRequest = WebRequest.Create("https://fcm.googleapis.com/fcm/send");
        tRequest.Method = "post";
        //serverKey - Key from Firebase cloud messaging server  
        tRequest.Headers.Add(string.Format("Authorization: key={0}", "AIXXXXXX...."));
        //Sender Id - From firebase project setting  
        tRequest.Headers.Add(string.Format("Sender: id={0}", "XXXXX.."));
        tRequest.ContentType = "application/json";
        var payload = new
        {
            to = "e8EHtMwqsZY:APA91bFUktufXdsDLdXXXXXX..........XXXXXXXXXXXXXX",
            priority = "high",
            content_available = true,
            notification = new
            {
                body = "Test",
                title = "Test",
                badge = 1
            },
        };
    
        string postbody = JsonConvert.SerializeObject(payload).ToString();
        Byte[] byteArray = Encoding.UTF8.GetBytes(postbody);
        tRequest.ContentLength = byteArray.Length;
        using (Stream dataStream = tRequest.GetRequestStream())
        {
            dataStream.Write(byteArray, 0, byteArray.Length);
            using (WebResponse tResponse = tRequest.GetResponse())
            {
                using (Stream dataStreamResponse = tResponse.GetResponseStream())
                {
                    if (dataStreamResponse != null) using (StreamReader tReader = new StreamReader(dataStreamResponse))
                        {
                            String sResponseFromServer = tReader.ReadToEnd();
                            //result.Response = sResponseFromServer;
                        }
                }
            }
        }
    

    android FCM 通知接收代码

    MyFirebaseInstanceIDService 类

    public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
    
    private static final String TAG = "MyFirebaseIIDService";
    
    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the InstanceID token
     * is initially generated so this is where you would retrieve the token.
     */
    // [START refresh_token]
    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
    
        Log.d(TAG, "Refreshed token: " + refreshedToken);
    
        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        sendRegistrationToServer(refreshedToken);
    }
    // [END refresh_token]
    
    /**
     * Persist token to third-party servers.
     *
     * Modify this method to associate the user's FCM InstanceID token with any server-side account
     * maintained by your application.
     *
     * @param token The new token.
     */
    private void sendRegistrationToServer(String token) {
        // TODO: Implement this method to send token to your app server.
    }}
    

    MyFirebaseMessagingService 类

    public class MyFirebaseMessagingService extends FirebaseMessagingService {
    
    private static final String TAG = "MyFirebaseMsgService";
    
    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // [START_EXCLUDE]
        // There are two types of messages data messages and notification messages. Data messages are handled
        // here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
        // traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
        // is in the foreground. When the app is in the background an automatically generated notification is displayed.
        // When the user taps on the notification they are returned to the app. Messages containing both notification
        // and data payloads are treated as notification messages. The Firebase console always sends notification
        // messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
        // [END_EXCLUDE]
    
        // TODO(developer): Handle FCM messages here.
    
        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 Firebase Job Dispatcher.
                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.
    }
    // [END receive_message]
    
    
    // [START on_new_token]
    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the InstanceID token
     * is initially generated so this is where you would retrieve the token.
     */
    @Override
    public void onNewToken(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
        // Instance ID token to your app server.
        sendRegistrationToServer(token);
    }
    // [END on_new_token]
    
    /**
     * Schedule a job using FirebaseJobDispatcher.
     */
    private void scheduleJob() {
        // [START dispatch_job]
        FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));
        Job myJob = dispatcher.newJobBuilder()
                .setService(MyJobService.class)
                .setTag("my-job-tag")
                .build();
        dispatcher.schedule(myJob);
        // [END dispatch_job]
    }
    
    /**
     * Handle time allotted to BroadcastReceivers.
     */
    private void handleNow() {
        Log.d(TAG, "Short lived task is done.");
    }
    
    /**
     * Persist token to third-party servers.
     *
     * Modify this method to associate the user's FCM InstanceID token with any server-side account
     * maintained by your application.
     *
     * @param token The new token.
     */
    private void sendRegistrationToServer(String token) {
        // TODO: Implement this method to send token to your app server.
    }
    
    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param messageBody FCM message body received.
     */
    private void sendNotification(String messageBody) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);
    
        String channelId = getString(R.string.default_notification_channel_id);
        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.ic_stat_ic_notification)
                .setContentTitle("FCM Message")
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);
    
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    
        // Since android Oreo notification channel is needed.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channelId,
                    "Channel human readable title",
                    NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }
    
        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }}
    

    【讨论】:

      猜你喜欢
      • 2021-08-07
      • 1970-01-01
      • 1970-01-01
      • 2023-01-02
      • 2022-01-06
      • 1970-01-01
      • 2022-08-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多