I am developing an Android app that using Push Notification feature. I need to push from server. I use Firebase for it. This is my first time using Firebase. But when I push from server using PHP and CURL, it is giving me invalid registration error.
I get the Firebase token in Android like this
String token = FirebaseInstanceId.getInstance().getToken();
Then I save sent that token to server and saved in the database.
At server, I am pushing like this
class Pusher extends REST_Controller {
function __construct()
{
parent::__construct();
}
public function notification_get()
{
$rows = $this->db->get('device_registration')->result();
$tokens= array();
if(count($rows)>0)
{
foreach($rows as $row)
{
$tokens[] = $row->token;
}
}
$message = array("message"=>"FCM PUSH NOTIFICATION TESTING");
if(count($tokens)>0)
{
$result = $this->send_notification($tokens,$message);
if(!$result)
{
die("Unable to send");
}
else{
$this->response($result, REST_Controller::HTTP_OK);
}
}
}
function send_notification($tokens,$message)
{
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = array(
'registration_ids'=>$tokens,
'data'=>$message
);
$headers = array(
'Authorization:key = AIzaSyApyfgXsNQ3dFTGWR6ns_9pttr694VDe5M',//Server key from firebase
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
if($result==FALSE)
{
return FALSE;
}
curl_close($ch);
return $result;
}
}
I am using CodeIgniter 3 framework for building Rest API. When I push accessing URL from browser, it returns JSON data with error as in the below screenshot.
As you can see it is giving InvalidRegistration error and message is not pushed to devices. What is wrong with my code?
Additional
This is my FirebaseMessagingService class that show notification in Android
public class FirebaseMessagingService extends com.google.firebase.messaging.FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
showNotification(remoteMessage.getData().get("message"));
}
private void showNotification(String message)
{
Intent i = new Intent(this,MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,i,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this).setAutoCancel(true)
.setContentTitle("FCM Test")
.setContentText(message)
.setSmallIcon(R.drawable.info)
.setContentIntent(pendingIntent);
NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
manager.notify(0,builder.build());
}
}
Although I am not using codeigniter, I was encountering the InvalidRegistration error while sending to an iOS device, so I thought I would share my solution here.
I had to change registration_ids to to in PHP when sending a Notification message to a single device token, and make sure the value of to was a string and not an array.
Change this:
'registration_ids'=>$tokens,
To this:
'to'=>$tokens[0],
Invalid Registration ID Check the formatting of the registration ID
that you pass to the server. Make sure it matches the registration ID
the phone receives in the com.google.firebase.INSTANCE_ID_EVENT
intent and that you're not truncating it or adding additional
characters. Happens when error code is InvalidRegistration.
Please check with both the side app side and your side that the exact same registration id is stored in the server which Application on mobile receives it in on onTokenRefresh method. You should have received the exact same registration token as developer got in FirebaseInstanceId.getInstance().getToken()
As i got your comment and you've updated the code here is some change in your code it is from google doc it self...
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// TODO(developer): Handle FCM messages here.
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below.
}
Firebase has three message types:
Notification messages: Notification message works on background or
foreground. When app is in background, Notification messages are
delivered to the system tray. If the app is in the foreground,
messages are handled by onMessageReceived() or
didReceiveRemoteNotification callbacks. These are essentially what is
referred to as Display messages.
Data messages: On Android platform, data message can work on
background and foreground. The data message will be handled by
onMessageReceived(). A platform specific note here would be: On
Android, the data payload can be retrieved in the Intent used to
launch your activity.
Messages with both notification and data payloads: When in the
background, apps receive the notification payload in the notification
tray, and only handle the data payload when the user taps on the
notification. When in the foreground, your app receives a message
object with both payloads available. Secondly, the click_action
parameter is often used in notification payload and not in data
payload. If used inside data payload, this parameter would be treated
as custom key-value pair and therefore you would need to implement
custom logic for it to work as intended.
For Java in Android Do not use FirebaseInstallation
for generating token i don't know why but it does not return the valid token. every time I receive "InvalidRegistration" when try to POST through FCM REST API.
{
"multicast_id": 8303815118005358735,
"success": 0,
"failure": 1,
"canonical_ids": 0,
"results": [
{
"error": "InvalidRegistration"
}
]
}
Instead Use This:
if (firebaseUser != null) {
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(task -> {
if (!task.isSuccessful()) {
Log.d(TAG, "getInstanceId failed", task.getException());
return;
}
if (task.getResult() != null) updateToken(task.getResult().getToken());
});
}
private void updateToken(String refreshToken) {
DocumentReference documentReference;
Token token1 = new Token(refreshToken);//just a class with str field
Map<String, Object> tokenMAp = new HashMap<>();
tokenMAp.put("tokenKey", token1.getToken());
Log.d(TAG, "updateToken: " + token1.getToken());
String id = firebaseUser.getUid();
baseref=sp.getString(BASE_REF,DEFAULT);
documentReference= FirebaseFirestore.getInstance().document(baseref);
updateDocWithToken(documentReference,tokenMAp);
}
private void updateDocWithToken(DocumentReference documentReference, Map<String, Object> tokenMAp) {
documentReference.set(tokenMAp, SetOptions.merge());
}
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 really stuck and want to push notification only to specific user using Firebase. I know the FCM method and have got the token. But this tutorial or other tutorials that I've followed are making me send push notification to both users including the sender. I just want to get notification on Recipient Device. Its been a long day , I've been working on this problem.
Looking for some key or UID of the Recipient now. Is it to be fetched from token that I have : FirebaseInstanceId.getInstance().getToken();
Update : I am not able to store and retrieve token (device token) and other children and also am able to log the message in firebase "Functions" tab , but still not able to push the notification to the device . I am testing it on emulator .Should I test it on real device ?
My Node.js code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var rootRef =
functions.database.ref('/notifications/{user_id}/{notification_id}');
exports.sendNotification = rootRef.onWrite(event => {
const user_id = event.params.user_id;
const notification_id = event.params.notification_id;
var request = event.data.val();
var payload = {
data: {
title : "New Message from ",
body: "userName has sent you message",
icon: "default",
}
};
console.log('We have a notification for device token: ', user_id );
console.log('Checking if getting inside the node -- ', request.user );
admin.messaging().sendToDevice(user_id, payload)
.then(function(response){
console.log('This was the notification Feature',response);
})
.catch(function(error){
console.log('Error sending message ',error);
})
})
MyFirebaseMEssagingService.java
public class MyFirebaseMessagingService extends FirebaseMessagingService
{
private static final String TAG = "FCM Service";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// TODO: Handle FCM messages here.
// If the application is in the foreground handle both data and
notification messages here.
// Also if you intend on generating your own notifications as a result
of a received FCM
// message, here is where that should be initiated.
//remoteMessage.getNotification().getBody());
if(remoteMessage.getNotification()!=null){
Map<String,String> payload = remoteMessage.getData();
// String title =
remoteMessage.getNotification().getTitle();
// String message =
remoteMessage.getNotification().getBody();
// Log.d(TAG, "Message Notification Title : " + title);
// Log.d(TAG, "Message Notification Body: " + message);
System.out.println("Messaging Service : Title - " + payload.get("title")
+ " , body - " + payload.get("body"));
sendNotification(payload);
}
}
#Override
public void onDeletedMessages(){
}
private void sendNotification(Map<String,String> payload){
NotificationCompat.Builder builder = new
NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentTitle("Firebase Push
Notification"+payload.get("title"));
builder.setContentText("Notification Text : "+ payload.get("body"));
Intent intent = new Intent(this, ChatWindow.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addNextIntent(intent);
PendingIntent pendingIntent =
stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, builder.build());
}
}
FirebaseIDService.java:
public class FirebaseIDService extends FirebaseInstanceIdService {
private static final String TAG = "FirebaseIDService";
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
DatabaseReference firebase ;//= new Firebase("https://materialtabs-
b5734.firebaseio.com//messages");
firebase =
FirebaseDatabase.getInstance().getReferenceFromUrl("https://materialtabs-
b5734.firebaseio.com//notifications/");
// TODO: Implement this method to send any registration to your app's
servers.
sendRegistrationToServer(refreshedToken);
}
/**
* Persist token to third-party servers.
*
* Modify this method to associate the user's FCM InstanceID token with any
server-side account
* maintained by your application.
*
* #param token The new token.
*/
private void sendRegistrationToServer(String token) {
// Add custom implementation, as needed.
System.out.println("Reading Token : "+ token);
}
}
And I am starting my 'MyFirebaseMessagingService.java' inside my MainActivity file in "onCreate()"
as "startService(new Intent(this, MyFirebaseMessagingService.class));"
Please help me. I think I am missing some minor details or it could be major, not sure !
For that, you need to store the firebase token of the recipient's device and then whenever you want to send the notification to the recipient you have to retrieve the token of the recipient's from the database and then you can send the notification using that token to the only recipient.
I'm trying to work on a messenger app, but the twist here is I have 2 Entities (i.e. 2 apps A & B) here.
Now I'm trying to put messaging logic between the two using Firebase. Firebase doesn't support communication between two different applications (A & B) over the same project url. In order to overcome that restriction, I have used the same google-service.json of app A for app B as well.
For app B, I have just changed the project id and auth key. That seems to have worked as I intended. I have tested the push notification as well using the Firebase Console and it seemed to have been working.
Then I have tried to implement the server logic. To make one-on-one notification.
CASE 1
But the problem arises here is that from app B, if I send a notification request, I get a MismatchSenderId error where the project id has not been tempered with.
{"multicast_id":[removed],"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"MismatchSenderId"}]}
CASE 2
and for app A, here is the following response I get:
{"multicast_id":[removed],"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1473661851590851%0e4bcac9f9fd7ecd"}]}
For this, the success value is 1 hence, the notification should be sent but it's not sending when I'm making the request from the device. But it works flawlessly when I perform the same server call using Postman or any other client.
Here are my codes MyFirebaseInstanceIDService.java
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static final String TAG = "MyFirebaseIIDService";
private static final String FRIENDLY_ENGAGE_TOPIC = "friendly_engage";
#Override
public void onCreate() {
String savedToken = Utility.getFirebaseInstanceId(getApplicationContext());
String defaultToken = getApplication().getString(R.string.pref_firebase_instance_id_default_key);
Log.d("GCM", savedToken);
if (savedToken.equalsIgnoreCase(defaultToken))
//currentToken is null when app is first installed and token is not available
//also skip if token is already saved in preferences...
{
String CurrentToken = FirebaseInstanceId.getInstance().getToken();
if (CurrentToken != null)
Utility.setFirebaseInstanceId(getApplicationContext(), CurrentToken);
Log.d("Value not set", CurrentToken);
updateFCMTokenId(CurrentToken);
}
super.onCreate();
}
/**
* The Application's current Instance ID token is no longer valid
* and thus a new one must be requested.
*/
#Override
public void onTokenRefresh() {
// If you need to handle the generation of a token, initially or
// after a refresh this is where you should do that.
String token = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "FCM Token: " + token);
Utility.setFirebaseInstanceId(getApplicationContext(), token);
updateFCMTokenId(token);
}
private void updateFCMTokenId(final String token) {
SQLiteHandler db = new SQLiteHandler(getBaseContext());
final HashMap<String, String> map = db.getUserDetails();
//update fcm token for push notifications
StringRequest str = new StringRequest(Request.Method.POST, AppConfig.UPDATE_GCM_ID, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("GCM RESPONSE", response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> param = new HashMap<>();
param.put("user_id", map.get("uid"));
param.put("gcm_registration_id", token);
return param;
}
};
str.setShouldCache(false);
str.setRetryPolicy(new DefaultRetryPolicy(AppConfig.DEFAULT_RETRY_TIME, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
AppController.getInstance().addToRequestQueue(str);
}
}
FirebaseMessagingService.java
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
//Displaying data in log
//It is optional
try {
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getData().get("message"));
} catch (Exception e) {
e.printStackTrace();
}
//Calling method to generate notification
sendNotification(remoteMessage.getData().get("message"));
}
//This method is only generating push notification
//It is same as we did in earlier posts
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, ChatRoomActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
android.support.v4.app.NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("NAME")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
}
And here is the declaration in the Manifest.xml within Application tag
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service
android:name=".MyFirebaseInstanceIDService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
TIA
CASE 1 Solved
I have managed to solve CASE 1 where for B I had to use the server api key of B , similarly for A
EDIT 2
Added Server side code
public function sendNotification($message, $gcm_id, $user_level)
{
if ($user_level == "level") {
$server_key = "xys";
} else $server_key = "ABC";
$msg = array
(
'message' => $message,
'title' => 'Title',
'vibrate' => 1,
'sound' => 1,
'largeIcon' => 'large_icon',
'smallIcon' => 'small_icon'
);
$fields = array
(
'to' => $gcm_id,
'data' => $msg
);
$headers = array
(
'Authorization: key=' . $server_key,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
curl_close($ch);
echo $result;
}
Edit #1:
1) Make sure you are sending a valid json to the fcm.
2) Make sure you are sending to the right token.
Other informations on how to send notifications:
Send messages to specific devices
To send messages to specific devices, set the to the registration token for the specific app instance
curl -H "Content-type: application/json" -H "Authorization:key=<Your Api key>" -X POST -d '{ "data": { "score": "5x1","time": "15:10"},"to" : "<registration token>"}' https://fcm.googleapis.com/fcm/send
Send messages to topics
here the topic is : /topics/foo-bar
curl -H "Content-type: application/json" -H "Authorisation:key=<Your Api key>" -X POST -d '{ "to": "/topics/foo-bar","data": { "message": "This is a Firebase Cloud Messaging Topic Message!"}}' https://fcm.googleapis.com/fcm/send
Send messages to device groups
Sending messages to a device group is very similar to sending messages to an individual device. Set the to parameter to the unique notification key for the device group
curl -H "Content-type: application/json" -H "Authorisation:key=<Your Api key>" -X POST -d '{"to": "<aUniqueKey>","data": {"hello": "This is a Firebase Cloud Messaging Device Group Message!"}}' https://fcm.googleapis.com/fcm/send
Original:
The problem is you server configuration. If you want to manage two firebase apps in single server you have you have to config two firebase apps with your Firebase APK_KEY that located at:
Go to your applications in Firebase console -> Click on three dots at the top right -> Manage -> CLOUD MESSAGES -> (Server key)
After you get your both server keys for your two apps, you have to configure it like this:
var firebaseLib = require("firebase");
var app1Config = {
apiKey: "<PROJECT_1_API_KEY>",
authDomain: "<PROJECT_1_ID>.firebaseapp.com",
databaseURL: "https://<PROJECT_1_DATABASE_NAME>.firebaseio.com",
storageBucket: "<PROJECT_1_BUCKET>.appspot.com",
}
var app2Config = {
apiKey: "<PROJECT_2_API_KEY>",
authDomain: "<PROJECT_2_ID>.firebaseapp.com",
databaseURL: "https://<PROJECT_2_DATABASE_NAME>.firebaseio.com",
storageBucket: "<PROJECT_2_BUCKET>.appspot.com",
}
var firebaseApp1 = firebaseLib.initailize(app1Config); // Primary
var firebaseApp2 = firebaseLib.initailize(app2Config, "Secondary"); // Secondary
I fixed error MismatchSenderId
Example, below:
valid token: cwsm26j-8qM:APA91bEGbg5xxxxxxxxxxxxxxxxxxxxxx
invalid token: APA91bEGbg5xxxxxxxxxxxxxxxxxxxxxx
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);
}
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