Is there a way to rollback the notification request placed to GCM server?
As in, consider a GCM-message-request is placed to GCM server.
If the user sees the message in web before coming online in mobile, the GCM request should be rolled back. And user should not see the notification in mobile.
There is no built in mechanism for such rollback in the case you describe. You can try implementing it yourself - when your server notices the message was viewed in web, you can send another GCM message to the device with some data that represents a need to rollback. When you process that message, you should clear any notifications that were created by your app on that device (I'm not sure if that's possible, you'll have to check).
There is such a mechanism in a similar case - if the user has multiple Android devices, and you send a GCM message to all of them (using the new user notifications feature), once the user views the notification on one device, it would be automatically removed from the other devices.
If a message has been handled on one device, the GCM message on the other devices are dismissed. For example, if a user has handled a calendar notification on one device, the notification will go away on the user's other devices.
If a message has not been delivered yet to a device and but it has been handled, the GCM server removes it from the unsent queue for the other devices.
Related
According to the Firebase Cloud Messaging documentation if the app server sets a field "delivery_receipt_requested" in the upstream message, it will receive a delivery confirmation when the app confirms receipt. However it works only if app server is connected with XMPP connection server. It will not work for HTTP connection server.
I'm very new to GCM/FCM and haven't setup my server yet. Hence am working with Firebase console to test my app for notification receipts.
So, following are my queries.
Will the field "delivery_receipt_requested" be sent to the app or the connection server itself will consume it.?
If the app receives this field in a notification will it need to act differently from the notification which do not contain this field.?
Any references to documentation or example implementation which makes use of this field is highly appreciated.
Thanks in advance.
Will the field "delivery_receipt_requested" be sent to the app or the connection server itself will consume it.?
The FCM client installed in Google Play services will handle this.
The application will not notice anything different.
If the app receives this field in a notification will it need to act differently from the notification which do not contain this field.?
The application doesn't need to take any action. indeed the app will not receive this field.
Longer explanation:
delivery_receipt is not exactly a confirmation that the app received the message, but it's a confirmation that the device received the message. To be clear it's still possible that the device crashed or run out of battery while the message is being passed to the app.
this feature is implemented outside of the application. so the application doesn't need to be aware that this message requires a delivery receipt
you can implement a more precise "application delivery receipt" by calling your backend in the method that receives the message.
(like an http call to: http://mywebsite.com/confirm-msg-processed-successfully.php?id=133)
Scenario: I have a 3rd-party app server, a gcm http connection server, and an android app setup for push notifications. When the user uninstalls the app, I can delete them from my 3rd-party server by sending their (no-longer-valid) registration id a push notification and handling the "NotRegistered" error returned from the gcm connection server.
However, this similar approach does not seem to work when you send a push notification to users subscribed to a "Topic", as here the gcm connection server only returns a json object with the "message_id".
The notable columns in my 3rd-party server database table are as follows:
| gcmRegistrationID (string) | subscribedToNotificationTopic (boolean) |
Does anyone know how to identify a user that has previously set true in the subscribedToNotificationTopic column, then uninstalled the app?
I have an idea on how to resolve this, but it seems somewhat messy.
Every so often, instead of only sending push notifications to a topic e.g.
{
"to" : "/topics/global",
...
}
send a push notification to the registration ids of the users subscribed to the topic e.g.
{
"registration_ids" : {list of registration ids},
...
}
such that I can retrieve and handle any "NotRegistered" errors.
The problem with this however, is that multicast messaging has a limit of 1000 users so I'd have to send a message for each thousand.
This seems like bad practice (especially if there is more than one topic involved), but maybe it's the only way?
(Extra tags: topic messaging, pubsub, unregister, google cloud messaging)
First off, I am not sure it is correct to assume that an "NotRegistered" error can only be the result of the user uninstalling your app. It seems like the device can become unregistered if the device receives a message but that message can not be delivered. This can happen if the user stops the app (which is different from uninstalling it, or even if the app was killed and remains stopped due to a power saving mode.
https://developers.google.com/cloud-messaging/ccs#response
If it is NotRegistered, you should remove the registration ID from
your server database because the application was uninstalled from the
device, or the client app isn't configured to receive messages.
What you can do is from the device side, periodically register the device, and make sure that the token you get back is the same as the one you stored, if not update your server with the new token.
As far as detecting if a user has uninstalled your app via a response to a topic message, I agree with you it does not seem to be directly possible. As an alternative to your proposed solution, you might, every now and then include a flag in the topic message that would ask the device to validate itself with your server, if a device does not validate itself after some number of attempts or some period of time you might conclude the user is not longer listening.
The other question is why do you really need to know. Is there any harm in sending some extra regid's to google? If a user quits your web service you can remove them from the list, but do you really need to take action if they just un-install your app from there device? - Just some thing to consider. Hope this helps.
I have implemented Google Cloud Messaging for a user profile.
When the user updates the profile on the web app, it instantly sends a GCM request to GCM Server, and from there it is sent to my registered Android Device and the user profile is updated on the device.
But when the device is Offline, and the user updates the user profile two times. Two requests are sent when the device comes online, how to get only the recent request ?
Any help would be appreciated.
Thank you in advance.
That's what the collapse_key parameter is for. If you send two GCM messages with the same collapse_key to the same device, if the device is offline, the GCM server stores only the last message and will deliver a single message to the device when it gets back online.
Here's a quote about collapse_key :
If the device is connected but idle, the message will still be delivered right away unless the delay_while_idle flag is set to true. Otherwise, it will be stored in the GCM servers until the device is awake. And that's where the collapse_key flag plays a role: if there is already a message with the same collapse key (and registration ID) stored and waiting for delivery, the old message will be discarded and the new message will take its place (that is, the old message will be collapsed by the new one). However, if the collapse key is not set, both the new and old messages are stored for future delivery. Collapsible messages are also called send-to-sync messages.
(Source)
The syntax is simple. For example, if you are sending a JSON request, add the following :
"collapse_key" : "something",
The collapse key doesn't have to be unique for each device.
My usecase: A user logged into my app, should be able to send messages to himself logged into the app on another Android device. If the user has more than one devices, then once he opens the message, the notification on other devices must disappear.
Doubts:
How to send data to a particular user across devices? I understand how to send messages to different users on different devices using GCM but this seems rather confusing.
How to achieve this in MQTT with adequate security? I read as much as I could about the security and got to the conclusion that MQTT isn't in the charge of it and that I've to implement my own security measures at the broker level. As of now Mosquitto broker allows username/password authentication, but for an app implementing Oauth, username/password seems rather vulnerable.
Or should I move over to XMPP?
You can use the new User Notifications feature of GCM.
What are User Notifications?
Third party servers can send a single message to multiple instance of
an app running on devices owned by a single user. This feature is
called user notifications. User notifications make it possible for
every app instance that a user owns to reflect the latest messaging
state. For example:
If a message has been handled on one device, the GCM message on the other
devices are dismissed. For example, if a user has handled a
calendar notification on one device, the notification will go away on
the user's other devices.
If a message has not been delivered yet to a device and but it has been handled, the GCM server removes it from the unsent queue for the
other devices.
Likewise, a device can send messages to the notification_key, which is the token that GCM uses to fan out notifications to all devices whose registration IDs are associated with the key.
I just added C2DM capability to my Android App.
At the moment the following happens if C2DM is started in my App.
My App sends the registration Intent
The answer broadcast is received by my app
The device token is retrieved from the intent and sent to my server
From that moment everything is working fine. The client receives the push notifications etc.
A problem occurs if the following hapens:
The user uninstalls the application without disabling push. (Completely deleting it not only updating)
The user reinstalls the application
If after step 5 a push notification is sent my app still receives this notification.
It seems that the token which was retrieved from the previous install is still active and is reconnected to the new instance of my application.
This leeds to the following problem:
A user who reinstalls my app but has no intention of receiving push notifications has no possibility to remove himself from the service because the new instance of the app has no way to unregister the old token from my server.
Is this a bug in the C2DM system or is something wrong in my setup?
Update
I followed Berdons advice and did the following:
For testing purposes only start an unregister Intent every time my app starts up.
After I send the unregister intent no push notification from my server is sent to my application. That seems to do the trick, but if I now go the C2DM Settings Screen and turn on push notifications for my app all the old tokens get active again and I receive information that I did not register for in the current installation of my app.
Next Update
It seems I'm not the only one with this problem:
Android C2DM : Duplicate message to the same device and App
I hoped that Google would manage those tokens in a way that old tokens from the same device get disabled after a new one was issued. I also expect that after I sent an unregister Intent all tokens for that application and that device are marked as invalid or deleted from the Google Server for ever. If this is somehow a design decision by Google for special use cases I don't see please enlighten me.
We now found a solution that should work in most of the cases.
The server adds the C2DM registration id as a data field with every C2D Message.
The device now only shows a notification if the token in the message and the token that is stored in a pref file match. That way we guarantee that we don't show messages for device tokens that were obtained by previous installs.
If the tokens do not match we found an old token that should not be active anymore. We now mark the token on our own web server as inactive to prevent the server from sending more unnecessary C2D Messages
This solution enables us to show only relevant data without the need to store a unique user id.
In my C2DM implementation, each user's device token is saved in a database against their UDID and the package name of the app (among other things). The UDID and package name form the primary key, meaning that the table can list multiple apps from the same device (UDID). When a user runs a particular app, the device token is recorded, and if they uninstall and re-run the app, the new device token would be recorded over the old one. We also have columns to record whether push is active for that particular app/device combo, and which types of push messages the user has enabled/disabled.
When the time comes to send a push for a particular app, no UDID will be registered more than once (since these two fields form the primary key), and therefore only the latest device token will be used. Furthermore, our query only returns the rows that have push messages enabled.
This solution should solve your problem because it prevents you from sending the push to both device tokens. I hope this helps!
More like an unexpected "feature". You might consider issuing an unregister request on the "first run" (first run ever) of your application to prevent this from occuring.
Update
You could could do the work of differentiating between different C2DM messages by using the collapse_key (or anything of your own creation) as an identifier. Update it between registrations and pass it to the device following registrations, unregistrations and messages.