Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I collapse my push notifications when I use Firebase FCM?

const options = {
    priority: 'high',
    collapseKey: user_id
};
const deviceTokensPromise = db.ref('/users-fcm-tokens/' + user_id).once('value');
deviceTokensPromise.then(tokensSnapshot => {
    if (!tokensSnapshot.hasChildren()) {
        return console.log('There are no device tokens to send to.');
    }
    const tokens = Object.keys(tokensSnapshot.val());
    console.log(tokens);
    console.log(payload);
     return admin.messaging().sendToDevice(tokens, payload, options).then(response => {
         console.log(response);
         return removeInvalidFCMTokens(tokensSnapshot, response);
     });
});

I have a collapse-Key field in my options.

When this code is ran, the iPhone receives multiple notifications, all on top of each other. I'd like to have most recent notification replace the previous ones.

like image 362
TIMEX Avatar asked Jan 02 '18 01:01

TIMEX


People also ask

What is collapse key in FCM?

FCM allows a maximum of four different collapse keys per device to be used by the app server at any given time. In other words, the FCM connection server can simultaneously store four different collapsible send-to-sync messages per device, each with a different collapse key.

Is there a limit for Firebase push notification?

Notification messages can contain an optional data payload. Maximum payload for both message types is 4000 bytes, except when sending messages from the Firebase console, which enforces a 1024 character limit.

How do you handle Firebase push notifications?

Firebase notifications behave differently depending on the foreground/background state of the receiving app. If you want foregrounded apps to receive notification messages or data messages, you'll need to write code to handle the onMessageReceived callback.

Why you use FCM notification instead of APNs?

APNs needs to be used for push messaging when an application is in the background. Hence, FCM uses APNs to deliver messages when the message contains user visible payload, e.g., body, sound etc.


3 Answers

@Timex you can pass same notification id for all notifications with the same collapse_id. For this you need to implement your own SendNotification method.

like image 168
cauchy Avatar answered Oct 14 '22 12:10

cauchy


Check out the "Delivery Options" section in Firebase's FCM Messages documentation.

"collapsible" message behavior is supported on Android via FCM's collapse_key, on iOS via apns-collapse-id, and on JavaScript/Web via Topic.

Intuitively you might expect that the apns-collapse-id setting might go into the options parameter passed into the sendToMessage method you are using. However, this is not the case. Instead try patching it into the payload object, like this:

const patchedPayload = Object.assign({}, payload, {
    apns: {
        headers: {
            'apns-collapse-id': user_id
        }
    }
});

This follows the payload format presented in the documentation linked above.

Once you've constructed this patched payload don't forget to update sendToDevice(tokens, payload, options) to sendToDevice(tokens, patchedPayload, options).

Hope this works out for you!

like image 40
casieber Avatar answered Oct 14 '22 10:10

casieber


For iOS:

Use apns-collapse-id see the docs.

if you use collapsible messages, remember that FCM only allows a maximum of four different collapse keys to be used by the FCM connection server per registration token at any given time. You must not exceed this number, or it could cause unpredictable consequences.

Collapsible:

Use scenario

When there is a newer message that renders an older, related message irrelevant to the client app, FCM replaces the older message. For example: messages used to initiate a data sync from the server, or outdated notification messages.

How to send

Set the appropriate parameter in your message request:

  • collapseKey on Android
  • apns-collapse-id on iOS
  • Topic on Web
  • collapse_key in legacy protocols (all platforms)

See the implementation of apns-collapse-id in the article:

# Script to send push notifications for each song in a Phish Setlist via an updateable Push Notification.
# Place a config.yml in the same directory as the script and your push notification PEM file.  
#
# Config Format:

# push_token: XXXXXXXXXXXXXX
# phish_api_key: XXXXXXXXXXXXXX
# push_mode: XXXXXXXXXXXXXX # development or production

require 'apnotic'
require 'phish_dot_net_client'
require 'awesome_print'
require 'yaml'

show_date = ARGV[0]

if show_date 

    script_config = YAML.load(File.read(File.expand_path('../config.yml', __FILE__)))

    PhishDotNetClient.apikey = script_config["phish_api_key"]

    the_show = PhishDotNetClient.shows_setlists_get :showdate => show_date

    push_body = ""

    if script_config["push_mode"] == "development"
        connection = Apnotic::Connection.new(cert_path: "pushcert.pem", url: "https://api.development.push.apple.com:443")
    else
        connection = Apnotic::Connection.new(cert_path: "pushcert.pem")
    end

    token = script_config["push_token"] 

    notification       = Apnotic::Notification.new(token)

    notification.apns_id = SecureRandom.uuid

    notification.apns_collapse_id = "Phish " + the_show[0]["showdate"] + ": "

    notification.mutable_content = true

    the_show[0]["setlistdata"].sets.each do |set_data|
        set_name = set_data.name + ": "
        set_data.songs.each do |song|
            song_str = set_name + song.title
            push_body = push_body + set_name + song.title + "\n"
            set_name = ""
            push_content = {'title' => song_str, 'body' => push_body} 
            puts push_content

            notification.alert = push_content

            response = connection.push(notification)

            # read the response
            puts ""
            puts response.ok?      # => true
            puts response.status   # => '200'
            puts response.headers  # => {":status"=>"200", "apns-id"=>"XXXX"}
            puts response.body     # => ""
            puts ""

            sleep(5)

        end

    end

    connection.close
else
    puts "Usage ruby send_push.rb SHOWDATE(Format:YYYY-MM-DD)"
end

For Android:

Use a tag variable in your notification payload.

"notification":{
  "title":"Huawei",
  "body":"21 Notification received", 
  "sound":"default",
  "badge":4,
  "tag":"1",
  "click_action":"Your_Activity"
   "icon":"Push_Icon" 
}
like image 38
youpilat13 Avatar answered Oct 14 '22 12:10

youpilat13