how to send silent notification / background notification using Firebase Cloud Messaging? - ios

I need to make silent notification/background notification in my iOS app using Firebase Cloud Messaging, so I can make an update in the app even though the user doesn't tap the push notification.
the documentation from Apple about background notification is in here , it is said that
To send a background notification, create a remote notification with
an aps dictionary that includes only the content-available key in the payload
Sample payload for a background notification from that documentation is like this:
{
"aps" : {
"content-available" : 1
},
"acme1" : "bar",
"acme2" : 42
}
so I create my own payload when sending FCM using cloud function node JS. my code is like this
const userToken = device.token
const payload = {
data: {
notificationID : notificationID,
creatorID : moderatorID,
creatorName: creatorName,
title : title,
body : body,
createdAt : now,
imagePath : imagePath,
type: type
},
apps : {
"content-available" : 1 // to force background data update in iOS
}
}
await admin.messaging().sendToDevice(userToken,payload)
I try to send and I have error:
'Messaging payload contains an invalid "apps" property. Valid
properties are "data" and "notification".
so adding "apps" property is not allowed, but iOS documentation said that I need to add "content-available" in the payload.
I read other answer in here, it is said that the payload should be written like this
{
"to" : "[token]",
"content_available": true,
"priority": "high",
"data" : {
"key1" : "abc",
"key2" : abc
}
but I am confused how to write the payload FCM that can trigger background notification in iOS

Based on the error message that you are receiving, you should remove the apps property since data and notification properties are considered to be valid, as per the documentation.
Now, in regards to the the payload that you found elsewhere, this refers to the HTTP syntax used to pass messages from your app server to client apps via Firebase Cloud Messaging using the FCM legacy HTTP API. You can refer to the the documentation to learn more about the new HTTP v1 API.
To answer your question, when you are using a Cloud Function with Node.js runtime to send notifications using the sendToDevice(token, payload, options) method, you will need to pass the contentAvailable in the function's options parameter.
The contentAvailable option does the following: When a notification or message is sent and this is set to true, an inactive client app is awoken, and the message is sent through APNs as a silent notification and not through the FCM connection server.
Therefore, your Cloud Function might look something like this:
const userToken = [YOUR_TOKEN];
const payload = {
"data": {
"story_id": "story_12345"
},
"notification": {
"title": "Breaking News"
}
};
const options = {
"contentAvailable": true
};
admin.messaging().sendToDevice(userToken, payload, options).then(function(response) {
console.log('Successfully sent message:', response);
}).catch(function(error) {
console.log('Error sending message:', error);
});

Related

Unable to send silent push notifications to iOS using FCM

I'm attempting to send a silent data notification to an iOS device using node.js module firebase-admin 7.0.0 and the following code:
// load lib
var firebase = require('firebase-admin');
// add API keys
firebase.initializeApp({
credential: firebase.credential.cert('./certs/firebase-private-key.json')
});
// device token send back from device
var token = '00397db1aa2f1fa625f71deef0c8e8ef0d4427cf60a13c0fb4bd290dcec41f4b';
// data message to send (contains no notification details so should be silent)
var message = {
data: {
key1: 'hello',
key2: 'world'
}
};
var options = {
priority: 'high',
timeToLive: 60 * 60 * 24,
contentAvailable: true,
mutableContent: true
};
// send the message
firebase.messaging().sendToDevice(token, message, options).then(function (res) {
// it worked!
console.log(res);
})
.catch(function (err) {
// it failed :(
console.log(err);
});
I get a response saying the message was sent, but it never arrives on the device. Whereas if I send the message using NWPusher it works fine (example payload below):
{"aps":{ "content-available": 1,"badge":0, "hello": "there" }}
Any ideas?
FYI: I have also opened a ticket on GitHub
Your code looks correct . You may try multiple combination of true and false in mutable content and content available.
And you may also try not sending mutableContent fields. But as far as I remember both should be true.
Other way to debug is to check what json is going out from nodejs. Youcan try same
payload in NWPusher or PostMan. This will give you some clue.
I have tried out the following payload in postman, for me it's working fine
{"mutable_content":true,"content_available" : true,"priority":"high","registration_ids":["d3-fa7XDQQ4:APA91bEKXbT3HAv6ko9RukcxaB4QBr8zOIT06CBpj9o0Sl6TxsMpTnAMQ86t14foIcuQuDUyzMApbvDORELYyD0WOX3BcfP7ZNtWx9uY0JGm2B7cmdlPoOFs68fe6rz3Q7tq_8Ib7Y4H"]}
For silent notifications you need to make sure couple of things:
1- Your payload doesn't have alert key in your payload
2- Have content-available" : 1 in your payload
3- Background mode for Push Notification is enabled ( select your target > capabilities > Background Modes > Remote Notification)
sample payload:
{
"aps" : {
"content-available" : 1
},
"acme1" : "bar",
"acme2" : 42
}
for more information checkout apple's reference : Pushing Updates to Your App Silently
For anyone still having this issue, as Gokul mentioned the code is just fine
Just make sure you are following the steps in the Apple docs
Specially make sure that you are adding the correct callback to your AppDelegate:
application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
Note that it is not the same as the one used to handle regular notifications application(_:didReceiveRemoteNotification:)
Also make sure that Remote Notifications is turned on under Background modes in the Project Settings as described here:
This is PHP version for sent silent for ios. Please add 'content-available' => 1 for silent notificication
$body = array(
'content-available' => 1,
'sound' => ''
);
{
"aps" : {
"alert" : "Notification with custom payload!",
"badge" : 1,
"content-available" : 1
},
"data" :{
"title" : "Game Request",
"body" : "Bob wants to play poker",
"action-loc-key" : "PLAY"
}
}

Sending Custom Payload using One Signal

THe client had asked to integrate OneSignal with their Android and iOS App. Earlier, they were using OpenBack for push notification. The payload which is being received in iOS and Android app in in the following format:
{ "aps": { "alert": { "loc-key": "WATCH_VIDEO", "loc-args": ["Mo Adham", "Simpson's theme on Two guitars"]}, "guid": "1GSIP6J" } }
When I look up in OneSignal dashboard, they have no option to create custom payload. I want the payload in above format from OneSignal.
Currently from dashboard, the OneSignal sends payload in this format:
{
aps = {
alert = {
body = hello;
subtitle = test;
title = test;
};
sound = default;
};
custom = {
i = "db7e56d9-df72-4ec3-adbe-1cd8e1c5d327";
};
}
The keys don't match in the both payloads.
What I want to ask is does the client needs to integrate OneSignal in their backend so that they can send the payload in the specified format?
Check out their documentation on rich notifications, action buttons and customizing action buttons. Links mentioned below. If it still doesn't help, chat with their customer support.
https://onesignal.com/blog/sending-rich-notifications-in-ios10-with-onesignal/
https://documentation.onesignal.com/docs/action-buttons
https://documentation.onesignal.com/docs/customize-action-buttons
Try using Create notification
I tested in postman
POST - https://onesignal.com/api/v1/notifications
Add this in header
Authorization: Basic FETVGER2dsaftOWQ3MS00NmQ2LTlmYmYtODkz34dasgYzkx
(Authorization: Basic Your REST API Key)
{
"app_id": "d7c310b5-f2b6-4e84-8f91-c3e4b77c2904",
"included_segments": ["Subscribed Users"], //To send all user
"include_player_ids": ["6392d91a-b206-4b7b-a620-cd68e32c3a76","76ece62b-bcfe-468c-8a78-839aeaa8c5fa","8e0f21fa-9a5a-4ae7-a9a6-ca1f24294b86"], //To specific user using player id
"content_available": true
}
REST API Key - find here

Firebase Cloud Messaging push notification not being sent to device

This is what my log looks like when my push notification gets called on
I am currently working on creating push notification set up for a user to user setting for the iPhone. I am currently using Firebase, so naturally I turned to Firebase Cloud Messaging to get this done. This is my setup in the functions that I am deploying to my Firebase. Is there something that I am doing wrong in here that would result in the notification not being sent to the device? I appreciate any help, and if there is any more needed information I would be happy to supply it.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
// Listens for new messages added to messages/:pushId
exports.pushNotification = functions.database.ref('/messages/{pushId}').onWrite( event => {
console.log('Push notification event triggered');
// Grab the current value of what was written to the Realtime Database.
var valueObject = event.data.val();
console.log(valueObject)
if(valueObject.photoUrl != null) {
valueObject.photoUrl= "Sent you a photo!";
}
// Create a notification
const payload = {
notification: {
title:valueObject.toId,
body: valueObject.text || valueObject.photoUrl,
sound: "default"
},
};
//Create an options object that contains the time to live for the notification and the priority
const options = {
priority: "high",
timeToLive: 60 * 60 * 24
};
return admin.messaging().sendToTopic("pushNotifications", payload, options);
if(!data.changed()){
});
exports.pushNotification = functions.database.ref('/messages/{pushId}').onWrite( event => {
const data = event.data;
console.log('Push notification event triggered');
return;
}
});
I noticed that you are exposing the same function twice. That is also an issue. Also I suggest you to promisify the admin.messaging, so that you can handle and check for errors.
let topic = "pushNotifications";
admin.messaging().sendToTopic(topic, payload, options)
.then(function(response) {
console.log("Successfully sent message:", response);
console.log("Topic: " + topic);
res.status(200).send("success");
})
.catch(function(error) {
console.log("Error sending message:", error);
res.status(500).send("failure");
});
Send this jsone on your post parameter in registration_ids field you have to post array of your All device token that you want to send push notification
This is post request method body
{ "registration_ids" : [Send Array of Device Token],
"data" :
{
"image_url" : "send your image here"
"message" : "Send your message here" },
"notification" :
{
"title" : "APP Name",
"sound" : "default",
"priority" : "high"
}
}
Here is post URL
https://fcm.googleapis.com/fcm/send
and send key="Your Authorization key" in request HttpHeader field
Take reference for basic setup form here for cloud messaging
https://firebase.google.com/docs/cloud-messaging/ios/client

Firebase Cloud Messaging not sending aps payload in correct format for iOS Notification Content & Service Extensions

I'm trying to implement notifications using Firebase. The notification is received correctly when the app is in the background or foreground. So, the basic mechanics are working.
Now I've added Content Extensions and Service Extensions to the app. The Content Extension works when I use a local notification, but the Firebase message payload seems incorrect as far as the optional fields are considered. Here is a link to an image of my console:
And here is the Firebase remote notification payload that comes across (with some of the long Google numbers edited for anonymity:
{
aps =
{
alert =
{
body = "Eureka! 11";
title = "Patient is not doing well";
};
};
category = provider-body-panel;
gcm.message_id = 0:149073;
gcm.n.e = 1;
google.c.a.c_id = 2825604;
google.c.a.e = 1;
google.c.a.ts = 149073;
google.c.a.udt = 0;
mutable-content = 1;
}
It appears that the "category" and "mutable-content" are not in the correct place. They should be in the aps payload.
How can I get those options to be in the payload so that my app can correctly parse it and connect it with the Content and Service Extensions?
To start off, I'm going to mention that there are two types of message payloads for FCM. notification and data. See the documentation here
When sending notifications through the Firebase Notifications Console, it will be treated as a notification payload. However, if you add in Custom Data, it will add it in the payload as a custom key-value pair.
For example, in your post, the FCM payload should look something like this:
{
"notification": {
"body" : "Eureka!",
"title": "Patient is not doing well"
},
"data": {
"category": "provider-body-panel",
"mutable-content" : true,
"click_action" : "provider-body-panel"
}
}
What's wrong?
click_action should be inside notification.
mutable-content should be mutable_content (notice the underscore) and should be on the same level as notification.
(this one I might've misunderstood, but) There is no category parameter for FCM, click_action already corresponds to it.
See the docs for the parameters here.
It it is currently not possible to set the value for click_action and mutable_content when using the Firebase Notifications Console. You'll have to build the payload yourself, something like this:
{
"to": "<REGISTRATION_TOKEN_HERE>",
"mutable_content" : true,
"notification": {
"body" : "Eureka!",
"title": "Patient is not doing well",
"click_action" : "provider-body-panel"
}
}
Then send it from your own App Server. You could also do this by using Postman or cURL
"mutable-content should be "mutable_content" (keyword for firebase server to send as mutable-content for IOS) as you mentioned in your post, I think you left out in edit.
Below is an example with also the corrected format for the data section in the json sent to the FCM server.
So update would be:
{
"to" : "YOUR firebase messaging registration id here",
"mutable_content":true,
"notification": {
"title": "Its about time",
"body": "To go online Amigo",
"click_action": "NotificationCategoryIdentifier ForYourNotificationActions"
},
"data":{
"customKey":"custom data you want to appear in the message payload"
"media-attachment":"mycustom image url",
"catalogID":"mycustom catalog for my custom app"
}
}
Update Firebase Admin SDK and use sendMulticast(payload) method
var admin = require("firebase-admin")
admin.initializeApp({
credential: admin.credential.applicationDefault(),
});
// Create a list containing up to 500 registration tokens.
// These registration tokens come from the client FCM SDKs.
const registrationTokens = [
'YOUR_REGISTRATION_TOKEN_1',
// …
'YOUR_REGISTRATION_TOKEN_N',
];
// See documentation on defining a message payload.
var message = {
notification: {
title: '$FooCorp up 1.43% on the day',
body: '$FooCorp gained 11.80 points to close at 835.67, up 1.43% on the day.'
},
tokens: registrationTokens,
apns: {
payload: {
aps: {
'mutable-content': true, // use single quote
'category': 'INVITE_CATEGORY' // use single quote
}
},
},
};
// Send a message to the device corresponding to the provided
// registration tokens.
admin.messaging().sendMulticast(message)
.then((response) => {
if (response.failureCount > 0) {
const failedTokens = [];
response.responses.forEach((resp, idx) => {
if (!resp.success) {
failedTokens.push(registrationTokens[idx]);
}
});
console.log('List of tokens that caused failures: ' + failedTokens);
}
});
Ref: https://firebase.google.com/docs/cloud-messaging/send-message#send_messages_to_specific_devices
This worked for me with Cloud functions with Node.js
const payload = {
notification: {
title: name,
body: messageText,
badge: "1",
mutable_content: "true"
},
data: {
type: "MESSAGE",
fromUserId: name,
attachmentUrl: imageUrl
}};

Setting priority Firebase Messaging in Cloud Function for Firebase

I'm using Firebase Messaging to send notifications to users of my iPhone app. In order to not expose the app's messaging server key on the client side I'm using Cloud Function for Firebase to send the notifications to specific topics. Before this I did it from the client side on the app and was able to set the message's priority by making a JSON of this format:
// Swift code in iPhone app
let body: [String: Any] = ["to": "/topics/\(currentPet)",
"priority" : "high",
"notification" : [
"body" : "\(events[eventType]) for \(petsName.localizedCapitalized)",
"title" : "\(myName.localizedCapitalized) just logged an event",
"data" : ["personSent": myId]
]
]
Now in my cloud function I'm trying to make a payload of the same general format, but keep running into the error:
Messaging payload contains an invalid "priority" property. Valid properties are "data" and "notification".
Here's my payload formatting and sending:
const payload = {
'notification': {
'title': `${toTitleCase(name)} just logged an event`,
'body': `${events[eventType]} for ${toTitleCase(petName)}`,
'sound': 'default',
'data': userSent
},
'priority': 'high'
};
admin.messaging().sendToTopic(pet_Id, payload);
Does anybody know how I would accomplish setting the priority? Should I just manually do an HTTP POST instead of using admin.messaging().sendToTopic()?
From the Firebase Cloud Messaging documentation on sending messages with the Admin SDK:
// Set the message as high priority and have it expire after 24 hours.
var options = {
priority: "high",
timeToLive: 60 * 60 * 24
};
// Send a message to the device corresponding to the provided
// registration token with the provided options.
admin.messaging().sendToDevice(registrationToken, payload, options)
.then(function(response) {
console.log("Successfully sent message:", response);
})
.catch(function(error) {
console.log("Error sending message:", error);
});
The difference is that the priority (and ttl in the example) is passed as a separate options argument instead of in the payload.

Resources