I have built and Android app (not in the Market yet) and I am struggling to figure out why C2DM is failing. I am able to register my device, and I get back a registration Id.
I have built a server app that submits the request to google's C2DM server and I get back a 200 response and a message id. (Success). The issue is, my device never gets the messages.
One of the things that surprises me is that if I try to register a device twice within seconds I get back a different registration id. Most likely they use time as a seed.
Is it normal for this registration id to change so frequently? Any clues / advice (I read the guidelines already)?
Cheers...
Note:
I do not have a sim card and all I use is a corporate WiFi network. My last hope is that maybe port 5228 is closed on my network.
Google says that C2DM will change anytime. So you have to update your server with the correct registration id for the device. If the id server has doesnt match the one which google sent to your device, it will not be able to deliver the push.
So as a golden rule, "always update the server with the latest c2dm registration id as soon as you get it"
if Google replies with 200, the body should contain an id. if there is an error, there will be an error in the body. the error codes are given below.
QuotaExceeded — Too many messages sent by the sender. Retry after a while.
DeviceQuotaExceeded — Too many messages sent by the sender to a specific device. Retry after a while.
MissingRegistration — Missing registration_id. Sender should always add the registration_id to the request.
InvalidRegistration — Bad registration_id. Sender should remove this registration_id.
MismatchSenderId — The sender_id contained in the registration_id does not match the sender id used to register with the C2DM servers.
NotRegistered — The user has uninstalled the application or turned off notifications. Sender should stop sending messages to this device and delete the registration_id. The client needs to re-register with the c2dm servers to receive notifications again.
MessageTooBig — The payload of the message is too big, see the limitations. Reduce the size of the message.
MissingCollapseKey — Collapse key is required. Include collapse key in the request.
This info is from http://code.google.com/android/c2dm/#testing
Yes as Rihan said every time you registered your device you will get a new registration ID.and if you are getting registration ID that your c2dm is successfully implemented from google server.Now you have to send this ID to your server .And by using this ID you have send push notification to your device.
Now you will get message in OnReceive() method of C2DReceiver and you have to handle this message(May you give a notification to user)
The issue was that port 5228 was closed on the network I was using.
I had a similar problem, the issue was in the app I wasn't sending the right email address used to register for the C2DM messaging. So it kept failing.
So check if you are sending the correct email address as the senders email address when registering for C2DM from the device that is the email address registered with google for push notifications.
Although Rihan is correct. The registration id changes every time. The reason why I was not getting the messages is because the port was locked.
For other googlers, make sure 5228 is open before you go mad...
Related
This question already has answers here:
Do old GCM tokens live on even after an uninstall?
(2 answers)
Closed 7 years ago.
I'm currently trying to use GCM to send notification to user and currently I'm still studying on how I can maximize it. For now I just use the sample project provided on the documentation here and I use the gcm-client sample to work on it.
Now using this project from Git I tried to push a message using the registration ID created by the app and yes it successfully delivers the message.
Now the problem is that after I uninstalled the application. After I reinstall it it will generate a new registration ID wherein I store it on a server together with the previous one except that I can't tag the previous registration ID to not receive any further message since the uninstall might happen when user has no internet connection. After that I send a message to two registration ID's which is the ID before uninstalling the app and the ID after reinstalling the application. What happen is that I receive two push messages eventhough I expected it to only get one since the app already changes the registration ID.
I expect that the app might receive twoor more duplicate apps if ever I also updated the app since as said on documentation the registration ID might change on update.
Any workaround I can do to handle this duplicate messages?
From the official documentation:
How uninstalled client app unregistration works
A client app can be automatically unregistered after it is
uninstalled. However, this process does not happen immediately. What
happens in this scenario is:
The end user uninstalls the client app.
The app server sends a message to GCM connection server.
The GCM connection server sends the message to the GCM client on the device.
The GCM client on the device receives the message and detects that the client app has been uninstalled; the detection details depend on the platform on which the client app is running.
The GCM client on the device informs the GCM connection
server that the client app was uninstalled.
The GCM connection server
marks the registration token for deletion.
The app server sends a
message to GCM.
The GCM returns a NotRegistered error message to the
app server.
The app server should delete the registration token.
Note
that it might take a while for the registration token to be completely
removed from GCM. Thus it is possible that messages sent during step 7
above get a valid message ID as a response, even though the message
will not be delivered to the client app. Eventually, the registration
token will be removed and the server will get a NotRegistered error,
without any further action being required from the app server.
However, it can apparently happen that you still get the notification for the old registration ID, as users state in other questions:
Android GCM and multiple tokens
Unregistering and re-registering for GCM messages causes two regId's to be valid. Is this as intended?
Do old GCM tokens live on even after an uninstall?
For this problem, there is a functionality called "canonical IDs":
Canonical IDs
If a bug in the client app triggers multiple registrations for the
same device, it can be hard to reconcile state and the client app
might end up with duplicate messages.
Implementing canonical IDs can help you more easily recover from these
situations. A canonical registration ID is the registration token of
the last registration requested by the client app. This is the ID
that the server should use when sending messages to the device.
If you try to send a message using an old registration token, GCM will
process the request as usual, but it will include the canonical ID in
the registration_id field of the response. Make sure to replace the
registration token stored in your server with this canonical ID, as
eventually the old registration token will stop working.
#KaHel When client app was uninstalled regId will be valid during some time, you are right. But, when client app will be installed again and your push server try to send message on old reg id that message will be successfully sent but GCM server put cannonical_id in response. And you should correct processes this response with cannonical_id. How do this i described at this post and there is not big documentation about cannonical_id. I.e. as soon as you get cannonical_id from GCM server you should immediately replace old reg_id by new one value. It will allow you not to produce a many regIds for one client, just one to one.
After reinstal you will get new RegId and prev not valid anymore. So, even if you send push to both RegIds, only last will received it.
You can implement logic for accounts in application.
For example, when user login in application you send his GoogleId + RegId. After reinstall of application and relogin you just update RegId on server. So, you can have only one RegId for every user.
There is problem: only one device will receive push msg (if you login in 2 devices with same account). So, you can send to server GoogleId + RegId + DeviceId after start application.
I am trying to write an application which notifies a cellphone using GCM. I was able to implement basic functionality, but there is one question I'm still unsure of
As I understand, the flow goes like this:
Device start up
Device registers, obtains registration id
Server gets the knowledge of registration id on device
Server is using it's API key + registration id to send payload to device
Device receives payload.
One thing which is unclear to me is: what is a proper methodology to implement step #3?
I could not find any way to obtain a list of registered devices. Lets imagine, I am using GCM for a purpose of posting to a known device, and I could email that ID to myself and then register it on the server manually. But as I understand, it expires.
So, it there an expectation that I have to keep re-registering and somehow notifying server every time it happens?
Yes, your app on device must send registration ID to your server application in order for server to be able to send GCM messages. See third point in Enabling GCM.
So I have a situation which I didn't think would happen based on my understanding of the registration My understanding:
Phone Registers with google gets registration_id, send registration_id to the server, use registration_id when sending out push notifications. If registration_id is updated by google, they will send a new registration broadcast.
However, I have case where a phone was registered, and was successfully receiving push notifications, but than one day the server goes to send a push notification to the phone and I get a error "NotRegistered" which would suggest the registration_id refreshed but did not get propagated through the system properly, whether it be on the phone side or the server side.
My question is has anyone else hand issues like this? What is the best approach to making sure this doesn't happen?
From the Android Cloud to Device Messaging Framework documentation:
Note that Google may periodically refresh the registration ID, so you should design your application with the understanding that the REGISTRATION Intent may be called multiple times. Your application needs to be able to respond accordingly.
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'm wondering if anyone has faced this issue with Google C2DM? This is the scenario I am faced with:
User installs the app and registers
with C2DM server for a registration
key.
User uninstalls the app.
User reinstalls the app (and
registers with C2DM server for new
registration key).
Now I send message from my server to the user's phone and they get a duplicate message.
Could anyone shed any insight into wether this is expected behaviour or how I can fix it?
Thanks,
Not sure if this is the best approach, but there's a relevant thread over at the android-c2dm group, where the poster offers one technique:
I am sending registration id in the message, so I can check it against the stored registration id on the device.
If it's not the same, discard it and notify the service that registration Id is no longer in use
Downside is sending registration Id takes up some space in already
limited message size. But works perfectly in my case since my
original message is no more than a few chars long.
This should only happen for the first push notification after re-installing your application.
Google C2DM service is working in passive mode when it comes to detecting uninstalled applications.
First push notification after uninstalling your application (without unregistering from C2DM!!!) will NOT return any error in response. However, the second push notification will return an "invalid registration" or "not registered" error codes where you can realize the application was uninstalled.
The reason is that C2DM servers return the response code immediately and only then tries to push the client. When client respond that an application was uninstalled, it is deleted from C2DM servers. Next push attempt will return an error code immediately.
Another solution could be to provide your server with a unique identifier for the device. In that case you can just update the registrationID for that UUID when the device tries to register after re-installation.
Yup, I've run into the same issue and in my opinion it's a big oversight in the Android C2DM implementation. iOS handles this much better in that an app can only ever receive notifications for one and only one device token (equivalent of the c2dm registration id)
The workaround I use is to send the last 10 characters of the registration id as part of the c2dm payload and then in my onMessage method I do the following check:
if (!regId.endsWith(bundle.getString("regsuffix"))) return null;
Both #Zamel and #johan answers are good and need to be combined. If you combine both solutions than you will minimize your server's database.
So the best solution will be to:
Send device id when sending the push token to the server
Update push token when is sent for existing device id
Invalidate push token in the server's database, if push notification returns an "invalid registration" or "not registered" error codes to the server
When push token is recognized as "invalid registration" or "not registered" you can invalidate it(mark it as null), delete the row in the database or implement expiration functionality. It depends on your needs