Registration confusion Android GCM - android

I am trying to migrate to GCM in Android, C2DM now being deprecated. The registration process described here is different from registration described here. Are both registration same? Can we see code for GCMRegistrar to know for sure?

I've successfully migrated my C2DM project to GCM. Tested, it works fine. The only changes were:
in the Android app - change the value of sender upon registration
on the server side - change the auth header and the URL
That was it, as far as the interaction with Google goes. There were more some changes dictated by the app's logic:
in the Android app, the registration ID was cached in its preferences. Upon upgrade, I remove reg ID from the preferences to force re-registration, this time with GCM.
the logic of passing the reg ID to the server got an extra boolean parameter - if this is a C2DM or GCM reg ID
the logic of sending messages became conditional upon the said parameter.
Throwing out the C2DM logic completely out of the server would be unwise - not everyone upgrades their Android apps. The old, C2DM-enabled versions will be out in the wild for some time. And Google pledged to keep C2DM running in the short term. So message sending is conditional - depending on reg ID type, it sends either to GCM or to C2DM.
EDIT re: conditional logic:
if($RegID_Is_GCM)
{
$Auth = GCM_Auth();
$URL = $GCM_URL;
}
else
{
$Auth = C2DM_AUTH();
$URL = $C2DM_URL;
}

They are actually the same thing. The second one encapsulates the first one in a static method and registers a broadcast receiver. You can attach the source to the gcm.jar and see for yourself. You can find source code in ~/android-sdks/extras/google/gcm/gcm-client/gcm-src.jar

The Thing I like most in GCM is the RegID we will get from GCM server,it is not only an ID its an Address of this application on this Device. So this time you don't need to send a device Id to server along with your Registration Id as per was in C2DM.
In C2DM every time you request a registration id you will get a new ID.
But in GCM RegId generated by using your application package along with some device id so if you will request for Registration Id again and again you will receive the same RegId.
And if you uninstall an application and will install it again still GCM server will give you the same Registration Id.
So one Registraion Id will do no need of any Device Id to send to server.

I have been successful at migrating from C2DM to GCM. I have also documented how to implement GCM at
http://android.amolgupta.in/2012/07/google-cloud-messaging-gcm-tutorial.html

GCMRegistrar is just a helper that does the leg work described in the first page.
You can see the class here. android-sdk\extras\google\gcm\gcmclient\src\com\google\android\gcm.

Related

Is a GCM Registration Token equal to the GCM Registration ID ?

i got confused by gcm today. I dont know if my registrationid is correct. I got characters and a colon in front of a registrationid starting with APA. The Pattern is xXXXxxX:APA... . I implemented google cloud messaging for a android client using the example from here: https://developers.google.com/cloud-messaging/android/client . If i use a older implementation (for example with GCMRegistrar) i only get a registration id starting with APA. Till now i though a registration id has to start with APA.
Is the stuff before the colon some tokenspecific stuff? Do i have to pass the full token to the webservice or is it okay if i cut the chars before the colon and send the registration starting with APA?
GCM Registration Token is equal to registration_id. As I mentioned in my answer here:
An FCM Token, or much commonly known as a registrationToken like in google-cloud-messaging. As described in the GCM docs:
An ID issued by the GCM connection servers to the client app that allows it to receive messages. Note that registration tokens must be kept secret.
Different terms point to the same thing. The format for the registration token may also vary as seen this answer:
The GCM registration token is usually around 140 chars in length, and can contain colons, underscores and hyphens. Maximum size is supposed to be 4k.
Though I'm not entirely sure with regards to the character length, I think I've read on a post here somewhere that it may exceed that number. Do search around.
gcm.register() is deprecated. use instance id method with token instead.
https://developers.google.com/cloud-messaging/android/legacy-regid
GCM register() is deprecated starting May 28, 2015. New app
development should use the Instance ID API to handle the creation,
rotation, and updating of registration tokens. For more information,
see Registering Client Apps and Set up a GCM Client App on Android.

Correct use and update of GCM-Ids

I have a question about the correct use of GCM-IDs.
At the moment I have a InstanceIDListenerService a GcmListenerService and a RegestrationIntentService.
The RegeistrationIntentServie get started in the MainActivity every time someone opens the app.
I think this is a correct implementation of the Google guidelines.
But what is the best way to handle the GCM-ID so that I will not have incorrect GCM-IDs on my server after the refresh in the InstandeIDListenerService. Because at the moment the refresh only registers a new GCM-ID on my server.
Would it be an idea to generate a random Device ID so that I can update the old GCM-ID?
How do you handle the IDs?
Because at the moment I ask the server every start of the app if he knows a GCM-ID in combination with a (randomly generated) Device-ID and update one of both if the other one is incorrect or does not exist.
And I think that produces a lot of network traffic for nothing.
Just to be sure, you are not calling InstanceIDListenerService.onTokenRefresh() yourself right? This will be called by the system if necessary.
To answer your question, you should use the GCM 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.
To be more precise, if there are two registrations for the same device and you send a notification using the older registration ID, you will get the canonical ID (the registration ID of the newest registration for this device). If this ID is already stored on your server, delete the old registration. If the canonical ID is not stored on your server for any reason, replace the registration ID you used to send the notification with the canonical ID.
#leet GCM ID token initiates callback periodically when your token needs to be refresh, or sometime when:
- Security issues; like ssl or platform issues
- Device info is no longer valid; for example backup and restore.
- Instance ID service is otherwise affected.
public class MyInstanceIDService extends InstanceIDListenerService {
public void onTokenRefresh() {
refreshAllTokens();
}
private void refreshAllTokens() {
// assuming you have defined TokenList as
// some generalized store for your tokens
ArrayList<TokenList> tokenList = TokensList.get();
InstanceID iid = InstanceID.getInstance(this);
for(tokenItem : tokenList) {
tokenItem.token =
iid.getToken(tokenItem.authorizedEntity,tokenItem.scope,tokenItem.options);
// send this tokenItem.token to your server
}
}
};
Keeping the Registration State in
Sync
To protect the client app and app server from potential malicious
re-use of registration tokens, you should periodically initiate token
refresh from the server. When GCM registration token refresh is
initiated from server side, the client app must handle
a tokenRefreshed message with the GCM registration client/server
handshake. This link may help you verify on how
to handle Refresh Token.
As Baris have metioned, your server must use canonical IDs when you are sending message to the device. The tokenRefresh would remove the idea of generating a random device ID and Canonical IDs would solve on how you verify if the ID is correct or not.

Get GCM canonical registration ID without sending a message

I have a problem with an app using GCM, the scenario is this:
the app is installed
the app calls the GCM register method getting the registration id "RID-1"
the app is uninstalled
the app is installed again
the app calls the GCM register method again getting the registration id "RID-2"
In step 5, I need to get the previous registration id so I can update my model.
Limitations:
- I am trying to do this without using the external storage
- I can't update the model when the server sends a message, it should be done after the registration because a new profile is created in the app for each new device
I know that this information is in Google servers because it is sent to you when you send a message to the old registration id. For example, if I send a message to "RID-1", in the response I get that the new (canonical) registration id is "RID-2". What I need is a way to get this information without sending a message.
Let me know if you need more context.
I found several related questions but the answers doesn't apply to this scenario:
Registration ID duplication for GCM
gcm canonical id should be updated or not
Persistance of gcm registration id
Google Cloud Messaging - Registration ID status
Android GCM: How to detect registered canonical ids in my own server?
Handling registration ID changes in Google Cloud Messaging on Android
(all answered by #eran)
You can specify "dry_run": true option in /send request.
I found that devices do not receive any push notifications with "dry_run": true option, while a server get canonical_ids response.
Here is a sample code in Ruby. You may have to install gcm Gem beforehand.
$ gem install gcm
ask_canonical_ids.rb
require 'gcm'
require 'json'
API_KEY = "YourApiKey"
gcm = GCM.new(API_KEY)
registration_ids = [
'OldRegistrationId',
]
option = { data: { 'message' => 'Hello Gcm!' }, dry_run: true }
response = gcm.send_notification(registration_ids, option)
p response[:canonical_ids]
output of $ ruby ask_canonical_ids.rb (formatted)
[{
:old => "OldRegistrationId",
:new => "NewRegistrationId"
}]
Again, your device will not receive any push notifications.
We need to update registration id with Canonical Id( By finding index position of array). You may Follow this working Ready use Code
If all you need is that the user should not get a notification, send a message with parameters that your application is not looking for. You will get the canonical and your app will discard the notification if it does not have the mandatory text and message.
For example, my Cordova application plugin requires the key 'message' in the data received from the server. Otherwise it does not create a notification.
I know this is sort of a hack, but I think given the limitations, this will be the easiest to achieve.

Prevent GCM client displaying messages from old reg ids

I am experiencing a problem with getting duplicate notifications using GCM push notifications on the Android client side.
I install the app and register with GCM like so: regid = gcm.register(SENDER_ID);
This gives me a registration ID (for example: "ABC"). If I try and re-register I get the same ID ("ABC"). If I clear the app data (in Androids app settings) and reload the app I get the same ID ("ABC"), however if I uninstall the app and reinstall, I get a new ID (for example: "DEF").
This is fine, however after registering the second time, my app will now receive notifications sent to both "ABC" and "DEF". This results in some in my app.
Is there a way to ignore all messages sent to any reg ID except the last one that was registered (in my example: "DEF")?
The example I am using to test is the official GCM-Client (https://developer.android.com/google/gcm/client.html).
There's no way to ignore the messages sent to the old reg id.
The best you can do:
In the client side, try to store some app data on the external storage. This would allow you to identify if the app was previously installed on the device, and to tell your server to replace the old reg id with the new one.
In the server side, handle canonical reg id responses from GCM. This won't prevent the sending of a message to an old reg id, but once you send a message to such reg id, you'll immediately remove the old reg id from your DB, and won't send any more messages to it.

Android duplicate registration id for different devices

I am seeing this issue on my push notifications server - different Android devices (identified by their IMEI) receive the SAME registration id from Google's GCM service.
Isn't the registration id supposed to be unique? at east for the same application or GCM API Key?
I saw this thread but there doesn't seem to be an answer there:
Can two different devices have same GCM Registration ID?
Any help would be much appreciated
EDIT
here is the relevant code for registration:
Intent intent = new Intent(
"com.google.android.c2dm.intent.REGISTER");
intent.setPackage("com.google.android.gsf");
intent.putExtra("app",
PendingIntent.getBroadcast(context, 0, new Intent(), 0));
intent.putExtra("sender", flatSenderIds);
context.startService(intent);
The only idea that comes to my mind is that this deprecated method will assign the same ID on different devices if the extra value for sender is the same on all of them. That differs from the current version where you don't say who you are, you don't even send an Intent, you just call register() and Google determines who you are and what ID you should be given.
If you finally use this new library, there's an example snippet of how to register (inside an AsyncTask or a Thread):
GoogleCloudMessaging gcm = null;
try {
// Will be for the first time
if (gcm == null)
gcm = GoogleCloudMessaging.getInstance(your_context);
// Registration against the GCM service
String regid = gcm.register(YOUR_SENDER_ID_OBTAINED_FROM_YOUR_PROJECT);
// You'll need to send the registration info to your remote server
registerRemoteServer(regid);
Log.d("MyGCM", "Registered on GCM as " + regid);
}
catch (final IOException ex) { ex.printStackTrace(); }
Sometimes Google changes the registration ID and you'll have multiple IDs associated. The server that sends the notification (your server) has to update the database with the new ID.
For more info check this document:
http://developer.android.com/google/gcm/adv.html
they says:
It's an Canonical IDs
On the server side, as long as the application is behaving well,
everything should work normally. However, if a bug in the application
triggers multiple registrations for the same device, it can be hard to
reconcile state and you might end up with duplicate messages.
GCM provides a facility called "canonical registration IDs" to easily
recover from these situations. A canonical registration ID is defined
to be the ID of the last registration requested by your application.
This is the ID that the server should use when sending messages to the
device.
If later on you try to send a message using a different registration
ID, GCM will process the request as usual, but it will include the
canonical registration ID in the registration_id field of the
response. Make sure to replace the registration ID stored in your
server with this canonical ID, as eventually the ID you're using will
stop working.
Well, after adding your registration code, I can see you are using the old method of registration. That method has been depecated since the middle of last year. It is likely to be less reliable than the new registration method.
You should try registering via the GoogleCloudMessaging.register method of the Google Play Services library. That's the recommended way by Google. See the official demo here.

Categories

Resources