we are implementing c2dm to push notifications to users. we want the user to be able to "opt-out" at the beginning. if they opt-in, then we register the device and send the id to our server to store for later delivery and track that by some unique device id.
the problem is that there doesn't seem a reliable way in android to get a device id. everything i've read says, "just generate a guid at first startup of the app". well, this is fine, but if a user starts up the app, opts in, then uninstalls and re-installs the app, then opts out, i have no way of removing that old device (since the device id of the second install is new).
i've tested and an old c2dm registration id works even after an uninstall and re-install.
any suggestions? how do others allow users to opt-out of notifications. how do you track their devices?
Having a Device ID is nice, but you don't need it to handle opt-outs. When you send a C2DM message from your server, include the registration ID. Then, when the device receives a message, it can compare the delivered registration ID with what it thinks its registration ID is.
If it matches, show the notification. If it doesn't match, ping your server and tell it to opt-out that registration ID.
On first run of your app, you could ask the user whether or not they would like to receive C2DM messages, and send that answer to your server. Then it follows that you would only send C2DM messages to devices that want them.
Instead of a GUID, I would look into getting their associated Android Market account (i.e. email address). This way, reinstalls won't change anything assuming they're using the same Android Market account.
Related
I have a android client app, a server side in django and now I am adding push notifications with GCM.
In my app I have users that login/logout, so I will have a table in my database with devices ids coupled with users, so that every time I want to notification a user, I will lookup its device id and send the notification.
my question is:
When is best to register the Device to the GCM?
When to add the Device to my Server side database?
In the Google Docs it says you should do it once, when the app is installed.
Because I have users in my app, and I want to couple a user with a device in the database, when the app is installed there still isn't a user to associate the Device with.
After the user installs the app, he can register, login and so on.
So when you think is best to register the Device to the GCM and to my server side?
Should it be with a user or only associate it later?
Thanks a lot!
My suggestion would be:
Register the device immediately after the first execution
Save device id somewhere accessible anytime by the app
Couple the id with user details after registration
With this approach you will be able to handle issues if something goes wrong with the registration process and send a notification to the device even if the user is not registered.
EDIT:
You should also implement a strategy to check on a regular basis if the association between the user and the device is still valid or needs to be updated
Company creates a project and receives a sender ID. Company creates an app, bakes in its sender ID and places the app in the store.
Attacker reverse engineers the app and extracts both the sender ID and the server interface used to receive GCM registration IDs.
Attacker creates his own app, bakes in Company's sender ID and server registration interface, puts app in the store. The attack app basically impersonates Company's real app as far as GCM goes: it registers to receive messages from Company's sender ID and then sends its GCM registration ID to Company's servers just like the "real" app does.
Now Company wants to broadcast some information to all instances of its app. Maybe it's a reminder than an update is available. Is there any way to differentiate the "attack app" (which registered just like the real one) from "real" versions of the Company's app?
I think from your scenario it's not possible for the attacker to send a message to the user even if he has the registration id. The company server which sends the messages they need to authenticate (OAuth2) there account first through Google. So only if the attacker knows the password of the sending party and the registration id than it can send the user. But the password of the sending party of course is never send to the client side.
well, this might even work in a debug version of the attackers app, but he can not put his app in the store. part of the GCM identification is the app id which needs to be unique in the store.
The same problem could also have existed with C2DM, which you can sniff the sender email address, instead of project ID for GCM.
C2DM or GCM, should never be used to send sensitive user information (i.e. account name, private information, etc), it's mainly useful for notification, which the real app can use it to perform further actions.
I can't see how useful a notification can be to a 'fake/hack' app, what are they going to do with 'You have new message' notification?
The GCM Registration ID is requested by Google, requested from the app and submitted to your server. When someone with a different app (but the same sender ID) creates a Regid, it still has to be committed to the server, and you first have to explicitly send a message to that specific regid.
An app installation, whether legitimate or not, can never receive messages it is not authorised for. (Provided you declare and use the C2D_MESSAGE permission)
Actually, google let's you register a Server Key for GCM, which lets you White-List Server IP's...
So you should add your server IP and you would be safe, since only your server is allowed to send messages with that key.
GCM is safe in this case.
You even can't use your Sender ID in your original app before you register the app in GoogleApiConsole. This means you point private key fingerprint in GoogleApiConsole. It's enough.
I would suggest having your own "interim server" which uses the API key (sender ID as you referred to it). Instead of embedding it in the app itself.
I've been working with de C2DM for sometime and its has been working perfect. Recently I've bumped into a problem that I can't seem to fix and couldn't anything on this forum that might help. The problem is that I have several apps that use C2DM, I've let all apps register with the same sender id which then registers the users token in my database. The problem if a user has two of my apps A & B (same sender id) and launches app A and I send a push notification to users with app B, user who launched app A the last will receive a message which was actually intended for app B.
My question is there a way to use the same sender id for all apps installed on 1 device?
No. A C2DM Registration ID is scoped to one app on one device. If a C2DM message is sent to a Registration ID, it will only ever be delivered to one app. you should have used different C2DM accounts from the start, so each app has its own registration ID. Registration IDs are not per device, they are Per App Per Device.
If you cannot reconfigure the registration IDs then you could use a receiver that then sends a broadcast intent, and both your apps could pick it up by responding to that broadcast. I expect you'd need both apps to listen-and-rebroadcast, but it should work. I'd advise you reconfigure your C2DM usage tho, as your current setup is not ideal and I expect the problem will only get worse.
I assume when you say "sender id" you mean registration id.
When the user uninstalls the app from his android device, it means that the registration_id for C2DM is no more valid. Now, how does the server which sends the push notifications know this. With Apple, there is something called Apple-feedback which lists out all the device-tokens (Android folks, read as registration-id) that are invalid.
Please, help me out with this.
I'm also looking for a sollution to this, so far I've only found one useful sollution which is mentioned here: http://groups.google.com/group/android-c2dm/browse_thread/thread/8e58ed95a0818716
In short: When you SEND the message to the device, send an UID with it (eg. generated on first install). When a message is received in the application, check if the UID is the same, if it is, do you thing (eg create notification), otherwise ignore it, and send a msg to your C2DM server that this Google C2DM registration ID is not valid anymore.
I think that is the reason C2DM are refreshing the Registration ID after random time. If user uninstall the App from his device, he is not not going to update his/her Registration ID either. Then he will not getting any Push Notifications anymore.
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.