This question already has answers here:
FCM (Firebase Cloud Messaging) Send to multiple devices
(4 answers)
Closed 4 years ago.
I have Created a Chat App and I need to Send Notification when group messages receives,i can send notification to one device but i don't know what to do with group notification.
any idea?
You need to subscribe these token and send notification to that topic.
Subscribe to a topic
var registrationTokens = []
db.collection('room').document({roomId}).get().then(result => {
registrationTokens = result.data().usersTokens // get user tokens in that chat room
})
// Subscribe the devices corresponding to the registration tokens to the
// topic.
admin.messaging().subscribeToTopic(registrationTokens, topic)
.then(function(response) {
// See the MessagingTopicManagementResponse reference documentation
// for the contents of response.
console.log('Successfully subscribed to topic:', response);
})
.catch(function(error) {
console.log('Error subscribing to topic:', error);
});
Now you can send to specific group like this
// The topic name can be optionally prefixed with "/topics/".
var topic = 'highScores';
// See documentation on defining a message payload.
var message = {
data: {
score: '850',
time: '2:45'
},
topic: topic
};
// Send a message to devices subscribed to the provided topic.
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
Related
Anyone can tell me how to send a push notification to a batch of group ids using FCM.
I tried
url = "https://fcm.googleapis.com/fcm/send"
headers = {
"Content-Type":"application/json",
"Authorization":"key={}".format(API_KEY)
}
body = {
"registration_ids":["group_id1","group_id2",...."group_idn"],
"data": {
"hello": "This is a Firebase Cloud Messaging Device Group Message!",
}
}
but it is giving me error.
{"multicast_id":6704816187425274139,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"NotRegistered"}]}
Let me go straight to the point, with Firebase Cloud Messaging and Android Oreo there have been some major changes when it comes to using their APIs.
I have entered my Firebase Server Api Key in the PubNub Console, push notification works absolutely fine on the Firebase console, but when publishing notification with PubNub, remoteMessage.toString gives => com.google.firebase.messaging.RemoteMessage#ffe9xxx in the OnMessageReceived function.
I am publishing something like this
JsonObject payload = new JsonObject();
JsonObject androidData = new JsonObject();
androidData.addProperty("contentText","test content");
androidData.addProperty("contentTitle","Title");
JsonObject notification = new JsonObject();
notification.add("notification",androidData);
JsonObject data = new JsonObject();
data.add("data", notification);
payload.add("pn_gcm", data);
in
PubNubObject.publish()
.message(payload)
etc..
Any idea why is this happening?
Thank you in advance.
Code on the receiving end
There is a class which extends FirebaseMessagingService, codes for OnMessageReceived function:
if (remoteMessage.getNotification() != null) {
//for testing firebase notification
Log.d(TAG, "Message Notification
Body:"+remoteMessage.getNotification().getBody());
} else {
//for anything else, I wanted to see what was coming from the server
//this is where I am getting the message when using PubNub notification
Log.d(TAG, "onMessageReceived: remoteMessage to
str:"+remoteMessage.toString() );
}
Android getData vs getNotification API
You are nesting the notification key/value inside of the data key and just need to use the API, remoteMessage.getData() instead of remoteMessage.getNotification().
If notification key was at the top level, it would work. See Android docs here.
Instead of this:
{
"pn_gcm": {
"data": {
"notification": {
"contentText": "test content",
"contentTitle": "Title"
}
}
}
}
This if switing to remoteMessage.getData():
{
"pn_gcm": {
"data": {
"contentText": "test content",
"contentTitle": "Title"
}
}
}
Or this if sticking with remoteMessage.getNotification():
{
"pn_gcm": {
"notification": {
"contentText": "test content",
"contentTitle": "Title"
}
}
}
}
PubNub basically just looks for the pn_gcm in the message payload when it is published and grabs whatever is inside of it and passes that directly to Google's FCM service for the devices that are registered (with PubNub) for that channel to receive GCM (FCM).
If the data is not formatted properly we would receive an error back from FCM which should be reported on the channel's -pndebug channel (assuming pn_debug:true was included in the published message payload).
For full details on troubleshooting FCM (GCM) or APONS issues with PubNub, please review How can I troubleshoot my push notification issues?
I am trying to learn to use azure mobile app, but I am having serious problems in using the NotificationHub. I have an Imagine subscription to Azure. I creating an android mobile app with azure backend. I have created a notification hub associated to the azure mobile app on the azure portal.
To register the app on the notification hub I used the code in this tutorial:
https://learn.microsoft.com/en-gb/azure/notification-hubs/notification-hubs-android-push-notification-google-fcm-get-started
The users are authenticated on the azure backend previuosly by using their google account, microsoft account or facebook account. New users are inserted into the table Users by the following node js code written for the table script Users.js. I want a push notification to Welcome the new User.
var azureMobileApps = require('azure-mobile-apps');
var logger = require('azure-mobile-apps/src/logger');
var table = azureMobileApps.table();
table.access = 'authenticated';
/**
* Adds the email address from the claims to the context item - used for
* insert operations
* #param {Context} context the operation context
* #returns {Promise} context execution Promise
*/
function addEmailToContext(context) {
/*
* Getting claim fields
*/
return context.user.getIdentity().then((data) => {
if( data.microsoftaccount != undefined){
context.item.email = data.microsoftaccount.claims.emailaddress;
context.item.name = data.microsoftaccount.claims.givenname;
context.item.surname = data.microsoftaccount.claims.surname;
}
if( data.google != undefined){
context.item.email = data.google.claims.emailaddress;
context.item.name = data.google.claims.givenname;
context.item.surname = data.google.claims.surname;
context.item.picture_url = data.google.claims.picture;
}
if( data.facebook != undefined){
context.item.email = data.facebook.claims.emailaddress;
context.item.name = data.facebook.claims.givenname;
context.item.surname = data.facebook.claims.surname;
}
logger.info('[tables/Users.js] --> NEW USER REGISTERED:'
+'\n\t Name:'+context.item.name
+'\n\t Surname:'+context.item.surname
+'\n\t Email:'+context.item.email);
// Execute the insert. The insert returns the results as a Promise,
// Do the push as a post-execute action within the promise flow.
return context.execute()
.then(function (results) {
// Only do the push if configured
if (context.push) {
// Mobile Apps adds a user tag when registering for push notifications
// Define the GCM payload.
var payload = {
"data": {
"message": 'Welcome '+context.item.username
}
};
context.push.gcm.send(context.user.id, payload, function (error) {
if (error) {
logger.error('Error while sending push notification: ', error);
} else {
logger.info('Push notification sent successfully!');
}
});
}
// Don't forget to return the results from the context.execute()
return results;
})
.catch(function (error) {
logger.error('Error while running context.execute: ', error);
});
});
}
// CREATE - add or overwrite the authenticated user
table.insert(addEmailToContext);
module.exports = table;
According to "How to: Send push notifications to an authenticated user using tags" in the tutorial on How to use the Azure Mobile Apps Node.js SDK
"When an authenticated user registers for push notifications, a user ID tag is automatically added to the registration. "
So in the Users.js, as suggested in this tutorial I wrote the following code to send the push notification to the user.
context.push.gcm.send(context.user.id, payload, function (error) {
if (error) {
logger.error('Error while sending push notification: ', error);
} else {
logger.info('Push notification sent successfully!');
}
});
With this code the push notification results to be sent successfully, but the device doesn't receive any notifications. If I use null instead of context.user.id then all devices receive the push notification correctly:
context.push.gcm.send(null, payload, function (error) {
if (error) {
logger.error('Error while sending push notification: ', error);
} else {
logger.info('Push notification sent successfully!');
}
});
I also tried to invoke the following custom API to create tag when the user is registered to the hub. The invoked API is the following:
var logger = require('azure-mobile-apps/src/logger');
exports.post = function(req, res) {
logger.info('[api/registerTag.js] --> Invoked');
// Get the notification hub used by the mobile app.
var push = req.azureMobile.push,
installationId = req.get('X-ZUMO-INSTALLATION-ID'),
tags = req.body.tag.toString();
// Define an update tags operation.
var updateOperation = [{
"op": "add",
"path": "/tags",
"value": tags
}];
// Update the installation to add the new tags.
push.patchInstallation(installationId, updateOperation, function(error) {
if(error){
logger.error('[api/registerTag.js] --> An error occurred while adding'
+'the following tags: \n\t'+tags, error);
res.status(error.statusCode).send(error.detail);
} else {
logger.info('[api/registerTag.js] --> The following tags have been added'
+'to the Notification Hub: \n\t'+tags, error);
res.status(200).send(tags);
}
});
};
On the console it is printed that the tag has been added successfully. But if I then modify the Users.js code like this:
...
// Only do the push if configured
if (context.push) {
// Mobile Apps adds a user tag when registering for push notifications
var userTag = '_UserId:' + context.user.id;
logger.info("TAG "+userTag);
// Define the GCM payload.
var payload = {
"data": {
"message": 'Welcome '+context.item.username
}
};
context.push.gcm.send(userTag, payload, function (error) {
if (error) {
logger.error('Error while sending push notification: ', error);
} else {
logger.info('Push notification sent successfully!');
}
});
}
...
again nothing is received. I have also tried whitelisting tags or adding them automatically using the Push section of the mobile app like shown in the image:
IMAGE LINK: i.stack.imgur.com/KBvQI.png
But the problem is still there. Hope someone can help me. Thanks.
After several times of testing, I succeeded in reproducing your issue and got the same problem. To achieve your requirement I did some modification in Android client-end:
1, Cache authentication user in the MainActivity class. Following is my code snippet. For more details you can refer here.
public static final String SHAREDPREFFILE = "temp";
public static final String USERIDPREF = "uid";
public static final String TOKENPREF = "tkn";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
// Create the Mobile Service Client instance, using the provided Mobile Service URL and key
mClient = new MobileServiceClient(
"https://yourwebsitename.azurewebsites.net",
this).withFilter(new ProgressFilter());
// Extend timeout from default of 10s to 20s
mClient.setAndroidHttpClientFactory(new OkHttpClientFactory() {
#Override
public OkHttpClient createOkHttpClient() {
OkHttpClient client = new OkHttpClient();
client.setReadTimeout(20, TimeUnit.SECONDS);
client.setWriteTimeout(20, TimeUnit.SECONDS);
return client;
}
});
authenticate();
} catch (MalformedURLException e) {
createAndShowDialog(new Exception("There was an error creating the Mobile Service. Verify the URL"), "Error");
} catch (Exception e){
createAndShowDialog(e, "Error");
}
}
private void authenticate() {
// We first try to load a token cache if one exists.
if (loadUserTokenCache(mClient)) {
createTable();
register();
}
// If we failed to load a token cache, login and create a token cache
else {
// Login using the Google provider.
ListenableFuture<MobileServiceUser> mLogin = mClient.login(MobileServiceAuthenticationProvider.Google);
Futures.addCallback(mLogin, new FutureCallback<MobileServiceUser>() {
#Override
public void onFailure(Throwable exc) {
createAndShowDialog("You must log in. Login Required", "Error");
}
#Override
public void onSuccess(MobileServiceUser user) {
createAndShowDialog(String.format("You are now logged in - %1$2s", user.getUserId()), "Success");
cacheUserToken(mClient.getCurrentUser());
createTable();
register();
}
});
}
}
private void cacheUserToken(MobileServiceUser user) {
SharedPreferences prefs = getSharedPreferences(SHAREDPREFFILE, Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString(USERIDPREF, user.getUserId());
editor.putString(TOKENPREF, user.getAuthenticationToken());
editor.commit();
}
private void register() {
NotificationsManager.handleNotifications(this, NotificationSettings.SenderId, MyHandler.class);
registerWithNotificationHubs();
}
2, In RegistrationIntentService class replace regID = hub.register(FCM_token).getRegistrationId(); with the following code:
regID = hub.register(FCM_token, prefs.getString("uid", "")).getRegistrationId();
3, Make sure add the line below to the first line within onHandleIntent method.
SharedPreferences prefs = getSharedPreferences("temp", Context.MODE_PRIVATE);
I'm using Firebase with an Android app (Auth, Database and Notification).
I'm trying to send notification from an external server (in nodejs) so an user can send a notification to another user.
So the android app memorize a list of UserId (the same ids from Firebase Auth) and then send this list to the nodejs server.
With this list, the server contact the url 'https://fcm.googleapis.com/fcm/send', but Firebase returns me a InvalidRegistration because i'm sending a list of userId and not the list of registration token created by firebase notification.
Should I memorize those tokens or there is a way to send notification with the user id ?
(And when I try with a list of tokens, of course it's working.)
var requestData = {
"registration_ids": userIds, //Problem is here
"data": {
"message": "A message"
}
};
request({
url: "https://fcm.googleapis.com/fcm/send",
method: "POST",
json: true,
headers: {
"Authorization": "key=firebaseKey",
"content-type": "application/json",
},
json: requestData
},
function(err, response, body) {
});
Yes, you can. For this you have to register these user Ids instead of device Id token. Then firebase recognized your user Ids.
#Override
public void onNewToken(#NonNull String token) {
super.onNewToken(token);
Log.d("user_token: ",token);
}
When I send GCM messages to multiple reg_ids some times I get NotRegistered Error.
How can I know which reg_id is not valid
{"multicast_id":5825324801553069805,"success":2,"failure":1,"canonical_ids":0,"results":[{"message_id":"0:1453198766912894%d41b519ed41b519e"},{"message_id":"0:1453198766913761%d41b519ed41b519e"},{"error":"NotRegistered"}]}
The response messages have same order with sent data's reg_id order.
As your example, the 3th reg_id is not registered.
{
"multicast_id":5825324801553069805,
"success":2,
"failure":1,
"canonical_ids":0,
"results":[
{
"message_id":"0:1453198766912894%d41b519ed41b519e"
},
{
"message_id":"0:1453198766913761%d41b519ed41b519e"
},
{
"error":"NotRegistered"
}
]
}