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"}]}
Related
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 setting up a service to send push notifications to our apps using an Azure Notification Hub. Registering the android device works fine (shows up correctly in VS 2015 Azure tools) but when I try and send a test post through the Azure portal or the VS 2015 Test Send tool I get the error "The Push Notification System handle for the registration is invalid" and the registration is deleted. I understand that when the notification hub gets an error it deletes the registration so that part makes sense. I can't find any info on why the PNS would be invalid. My registration code is:
public class PushRegObject
{
public string Platform { get; set; }
public string Handle { get; set; }
public string[] Tags { get; set; }
}
public async static Task<ObjectResultObject<string>> RegisterDevice(PushRegObject reg)
{
string newRegistrationID = null;
var hub = NotificationHubClient.CreateClientFromConnectionString(_connectionstring_, _name_);
if (reg.Handle != null)
{
// Get the Registration ID
var registrations = await hub.GetRegistrationsByChannelAsync(reg.Handle, 100);
foreach(var registration in registrations)
{
if (newRegistrationID == null)
newRegistrationID = registration.RegistrationId;
else
await hub.DeleteRegistrationAsync(registration);
}
if (newRegistrationID == null)
newRegistrationID = await hub.CreateRegistrationIdAsync();
// Register the Device
RegistrationDescription regObj = null;
switch (reg.Platform)
{
case "android":
var regDesc = await hub.CreateGcmNativeRegistrationAsync(newRegistrationID);
return new ObjectResultObject<string>(true, null) { Object = regDesc.GcmRegistrationId };
case "ios":
regObj = new AppleRegistrationDescription(reg.Handle);
break;
default:
return new ObjectResultObject<string>(false, "Unknown device type");
}
}
return new ObjectResultObject<string>(true, null) { Object = newRegistrationID };
}
Any ideas?
Update
With the help of Dmitry in narrowing down the problem, I found the solution which was to use the full token return from GCM in the CreateGcmNativeRegistrationAsync call.
var regDesc = await hub.CreateGcmNativeRegistrationAsync(reg.Handle);
Jason, my name is Dmitry and I work in Notification Hubs team. Below are a few steps that will help us to troubleshoot this issue.
Use NotificationHubClient.GetAllRegistrationsAsync(100) to get all your registrations from the notification hub, find the registration from your test android device there and compare the GcmRegistrationId of this registration with the actual registration id which device recieves from GCM.
If the registration ids on the previous step are equal, then make sure that you uploaded the correct GCM API Key to the notification hub.
If GCM credentials in the notification hub are correct, then try to send a notification to your device using some third-party tools, for example cURL and command line as Google suggests here - https://developers.google.com/web/fundamentals/getting-started/push-notifications/step-07?hl=en. Make sure that you use the same API Key, that was configured in the notification hub, and registration id, that was uploaded into the notification hub.
If you were able to successfully send a notification to your device using a third-party tool, then please send namespace and notification hub name to nhubsupport#microsoft.com and I'll take a look.
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"
}
]
}
Background
I have an Android app with a working receiver that can receive the push notification sent from iOS device and Parse website.
However, the following cases are not working:
send push notifications from Android to Android
send push notifications from Android to iOS
Since the Android app can receive push notifications without any problems, I guess there must be something with my logic/code of sending the push notifications
Problem Description
When sending push notifications using parsePush.sendInBackground(SendCallback) method, it returns no ParseExceptions. So it means no error.
But the Parse Dashboard does not show this push notifications and the target destination (either iOS or Android device in this case) does not get anything.
In the normal case, when a push notification is sent via Parse, it will show up as a push history in the Dashboard (the working case does that), but when I tried to send pushes from Android device, it just not show anything in the Dashboard and the pushes are never get delivered.
Code
The problematic Android code:
public void onShouldSendPushData(MessageClient messageClient, Message message, List<PushPair> pushPairs) {
//TODO setup offline push notification
Log.d(TAG, "Recipient not online. Should notify recipient using push");
if (pushPairs.size() > 0 && !chatRecipient.isEmpty()) {
PushPair pp = pushPairs.get(0);
String pushPayload = pp.getPushPayload();
ParsePush parsePush = new ParsePush();
ParseQuery query = ParseInstallation.getQuery();
ParseQuery userQuery = ParseUser.getQuery();
userQuery.whereEqualTo("username", chatRecipient);
query.whereMatchesQuery("user", userQuery);
parsePush.setQuery(query);
// JSON object for android push
String alertString = getResources().getString(R.string.push_notification_msg);
try {
JSONObject data = new JSONObject();
data.put("alert", String.format(alertString, chatRecipient));
data.put("badge", "Increment");
data.put("sound", "default");
// pass the sender name as "title"
data.put("title", ParseUser.getCurrentUser().getUsername());
data.put("uri", "");
data.put("SIN", pushPayload);
parsePush.setData(data);
parsePush.sendInBackground(new SendCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Log.i(TAG, String.format("Push notification to %s sent successfully", chatRecipient));
} else {
Log.e(TAG, String.format("Private chat push notification sending error: %s", e.getMessage()));
}
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
}
The working iOS code:
- (void)message:(id<SINMessage>)message shouldSendPushNotifications:(NSArray *)pushPairs {
// use parse to send notifications
// send notifications
NSLog(#"Recipient not online. Should notify recipient using push");
if (pushPairs.count > 0 && userSelected != nil) {
pushData = [[pushPairs objectAtIndex:0] pushData];
pushPayload = [[pushPairs objectAtIndex:0] pushPayload];
PFPush *push = [[PFPush alloc] init];
PFQuery *query = [PFInstallation query];
PFQuery *userQuery = [PFUser query];
[userQuery whereKey:#"username" equalTo:userSelected];
[query whereKey:#"user" matchesQuery:userQuery];
[push setQuery:query];
NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat:#"You have a new Message from %#", [PFUser currentUser].username], #"alert",
#"Increment", #"badge",
#"default", #"sound",
pushPayload, #"SIN",
nil];
[push setData:data];
[push sendPushInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
NSLog(#"Push notification to %# sent successfully.", userSelected);
} else {
NSLog(#"push notifications sending error: %#", error);
}
}];
} else {
NSLog(#"Error: No push pairs.");
}
Note
I can confirm that the code above is getting called each time I want to send push notifications, and no exceptions are returned. I can also confirm that the data packaged inside the push is not null.
I'm not posting the receiver's code as that part of code is working and should do nothing with this issue.
The iOS code and Android code basically are the same, why the sending pushes function in Android not working?
UPDATE
I upgraded Parse SDK to 1.8.2, with its Logging options set to VERBOSE and still can't find any clue why the Push notifications are not sent.
I even made a simple project out of the Parse example project with only Login and send message functions and its sending message function is still not working. So frustrating.
I have found the reason.
It is the "uri" field inside JSON.
As long as this field is included (with or without the content), notifications seemed being ignored by Parse, although you'll get a non-error callback.
If you remove "uri" field inside your JSON, notifications will become normal.
I've reported this bug to Parse and they've started to solve it.
Update
According to the reply from Parse.com, this is an intended feature, so the notifications with "uri" field will be discarded on the server side, thus it will not be sent.
related link:
https://developers.facebook.com/bugs/338005256408244
I am doing work on GCM (Google Cloud Messaging) in Android. I am looking for the upstream message using GCM.
Code send the GCM messages to cloud here
try {
Bundle data = new Bundle();
// the account is used for keeping
// track of user notifications
data.putString("account", account);
// the action is used to distinguish
// different message types on the server
data.putString("action", Constants.ACTION_REGISTER);
String msgId = Integer.toString(getNextMsgId());
gcm.send(projectId + "#gcm.googleapis.com", msgId,
Constants.GCM_DEFAULT_TTL, data);
} catch (IOException e) {
Log.e("grokkingandroid",
"IOException while sending registration id", e);
}
Now question is that what cloud would do for that upstream message, Where it can be useful in Android and How ??
When you send an upstream message from your app, the GCM Cloud Connection Server (CCS) transfers that message to your server. In order for that to work, you must implement a server that supports XMPP protocol and establishes a TLS connection with GCM Cloud Connection Server. You also need your API project to be white-listed for using this feature. You can read more about it here.
As for usefulness, it allows you to send messages to your app via the GCM connection instead of via your own connection between your app and your server. That's more battery efficient.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "FCM Token creation logic");
// Get variables reference
deviceText = (TextView) findViewById(R.id.deviceText);
editTextEcho = (EditText) findViewById(R.id.editTextEcho);
buttonUpstreamEcho = (Button) findViewById(R.id.buttonUpstreamEcho);
//Get token from Firebase
FirebaseMessaging.getInstance().subscribeToTopic("test");
final String token = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Token: " + token);
deviceText.setText(token);
//Call the token service to save the token in the database
tokenService = new TokenService(this, this);
tokenService.registerTokenInDB(token);
buttonUpstreamEcho.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Echo Upstream message logic");
String message = editTextEcho.getText().toString();
Log.d(TAG, "Message: " + message + ", recipient: " + token);
FirebaseMessaging.getInstance().send(new RemoteMessage.Builder(FCM_PROJECT_SENDER_ID + FCM_SERVER_CONNECTION)
.setMessageId(Integer.toString(RANDOM.nextInt()))
.addData("message", message)
.addData("action", BACKEND_ACTION_ECHO)
.build());
// To send a message to other device through the XMPP Server, you should add the
// receiverId and change the action name to BACKEND_ACTION_MESSAGE in the data
}
});
}
This is a sample Android project to showcase the Firebase Cloud Messaging (FCM) to manage upstream and downstream messages.
https://github.com/carlosCharz/FCMTest
This is the video in youtube that explains what it does.
https://www.youtube.com/watch?v=SEzOKSoAMG0
Hope you find it useful.