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
Related
I'm making chat application trying to get push notification when new message received to user from another when app is in background using send notifications between Android devices using Firebase Database, Cloud Messaging and Node.js.
I'm following this blog.Here's
[https://firebase.googleblog.com/2016/08/sending-notifications-between-android.html]
and below is my code which I tried.
#Override
public void onClick(View view) {
if (view.getId() == R.id.btnSend) {
String content = editWriteMessage.getText().toString().trim();
if (content.length() > 0) {
editWriteMessage.setText("");
Message newMessage = new Message();
newMessage.text = content;
newMessage.idSender = StaticConfig.UID;
newMessage.idReceiver = roomId;
newMessage.timestamp = System.currentTimeMillis();
FirebaseDatabase.getInstance().getReference().child("message/" + roomId).push().setValue(newMessage);
sendNotificationToUser(newMessage.idReceiver,newMessage.text);
}
}
}
public void sendNotificationToUser(String user, String message) {
Map notification = new HashMap<>();
notification.put("username", user);
notification.put("message", message);
FirebaseDatabase.getInstance().getReference().child("notificationRequests").push().setValue(notification);
}
By using above codes the username and message is getting saved in real time database in notificationRequests.
And I really don't have idea that how can the push notification is received by this line of code.
FirebaseMessaging.getInstance().subscribeToTopic("user_"+username);
And the most important where do i need to put the above code to make it work.
and also I have created the bucket to host my node.js file.
thanks in advance.
EDIT: I misunderstood your problem. Make sure that firebase messaging service is in your manifest.xml file.
Original:
Use the functions.database.ref().onCreate() method. Inside the ref() parameters put the path to your notification requests.
Here's some base code in TypeScript.
export const notificationListener = functions.database
.ref('/NotificationRequests/{notification}').onCreate((snapshot, context) =>
{
try {
admin.initializeApp();
} catch (e) {
}
//Code to send notification here
return admin.database().ref('/NotificationRequests/' + context.params.notification)
}
)
The information you need for the notification is located under snapshot.child('your path here').
See why and how this works
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 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.
Official documentation advises not to use client push notification. Instead cloud push notifications should be used. But does that count as an API call?
CODE:
// WRONG WAY TO SEND PUSH - INSECURE!
ParseQuery pushQuery = ParseInstallation.getQuery();
pushQuery.whereEqualTo("user", userObject);
ParseUser currentUser = ParseUser.getCurrentUser();
String message = currentUser.getString("name") + " says Hi!";
ParsePush push = new ParsePush();
push.setQuery(pushQuery); // Set our Installation query
push.setMessage(message);
push.sendInBackground();
vs (cloud version + missing cloud code):
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("recipientId", userObject.getObjectId());
params.put("message", message);
ParseCloud.callFunctionInBackground("sendPushToUser", params, new FunctionCallback<String>() {
void done(String success, ParseException e) {
if (e == null) {
// Push sent successfully
}
}
});
I mean, if I would have use client push notifications, would that be 1 call per push less? Since parse.com is restricting users on call/s, then it is very important to know.
UPDATE:
The first option, is not right one, it is client push which performs only 1 API call/request.
While second one, just asks ParseCloud to do the push for itself. But that means, it is 2 API calls/requests. Because one is performed by Android app to cloud, and then cloud is doing the actual push. But I just wanted to know if it is really like that.