46
votes

I have a service that uses Firebase Cloud Messaging to communicate with its Android clients using FCM Data messages with the collapse_key parameter set. From the documentation about collapsable keys:

When there is a newer message that renders an older thread, related message becomes irrelevant to the client app and FCM replaces the older message. For example send-to-sync, or outdated notification messages.

This is what I'm looking for. I don't need all updates, only the last one is needed. But, I need it ASAP if the user is online.


However, I get a weird rate limiting that doesn't result in any HTTP error code. It is pretty easily reproducible just do 20 consecutive data messages and monitor the android FirebaseMessagingService.onMessageReceived:

for i in {1..20}; do 
  curl -v -X POST --header "Authorization: key=$SERVER_KEY" \
       --Header "Content-Type: application/json" \
       https://fcm.googleapis.com/fcm/send \
       -d "{\"to\":\"$CLIENT_TOKEN\", \
            \"data\":{\"counter\":\"$i\"}, \
            \"priority\":\"high\", \
            \"collapse_key\": \"test\" \
           }"
done

The bash script above is a bit hard to read, but I have a counter variable that I'm interested in.

After a few received messages (counter=~10) it stops and you need to toggle network status to get the last message with counter=20. The last message also appears after a few minutes (normally ~10 minutes) when a firebase check-in is requested (?).

Removing collapse_key from the curl command above results in that all 20 messages are received (where counter={1..20}).


So, the question: Is this a bug? Or am I shutting down (/rate limited) because I "abuse" the interface (since all requests sends back a 200 response I thought I was ok).

1
Note that I'm using "Data messages" and not "Notification messages" if that makes any difference. - dacwe
Both priority and time_to_live are specified outside the notification or data parameter, so there isn't really any difference whether which type of payload you're using (although each has default values). AFAIK, latency wise, it is best to simply set the ttl to 0, but as you already know, the message will become a now or never type of message. But as per the behavior of FCM (even before for GCM), it will attempt to send the message asap, depending on the settings. - AL.
@AL. Seems like collapse_key gets rate limited see my edited question. - dacwe
If I understand that scenario you added in properly, adding the collapse_key to your payload treats your message as collapsible, wherein if the previous message with the same collapse_key is not yet sent to the device, it will be deleted and replaced with the most recent one with the same collapse_key. So the behavior you saw where not all the messages with collapse_key are received is just as expected. - AL.
@AL. I think this is a bug. I rewrote my question one last time. - dacwe

1 Answers

1
votes
<?php
#API access key from Google API's Console
    define( 'API_ACCESS_KEY', 'YOUR-SERVER-API-ACCESS-KEY-GOES-HERE' );
    $registrationIds = $_GET['id'];
#prep the bundle
     $msg = array
          (
        'body'  => 'Body  Of Notification',
        'title' => 'Title Of Notification',
                'icon'  => 'myicon',/*Default Icon*/
                'sound' => 'mySound'/*Default sound*/
          );
    $fields = array
            (
                'to'        => $registrationIds,
                'notification'  => $msg
            );


    $headers = array
            (
                'Authorization: key=' . API_ACCESS_KEY,
                'Content-Type: application/json'
            );
#Send Reponse To FireBase Server    
        $ch = curl_init();
        curl_setopt( $ch,CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send' );
        curl_setopt( $ch,CURLOPT_POST, true );
        curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );
        curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );
        curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false );
        curl_setopt( $ch,CURLOPT_POSTFIELDS, json_encode( $fields ) );
        $result = curl_exec($ch );
        curl_close( $ch );
#Echo Result Of FireBase Server
echo $result;

Put your data in body section.