I'm developing a small application using GCM Service.
Before, I tried to send to my self a message, but (server side) the answer has been:
"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"NotRegistered"}]}
But at the beggining of my app i check this:
final String regId = GCMRegistrar.getRegistrationId(this); if (regId.equals(""))
{
// Register
GCMRegistrar.register(this, SENDER_ID);
}
else ...
It seems evident that getRegistrationId() works fine only locally, (SharedPreferences ?)..
The nice thing is that i never did Unregister my app,just reinstall it, not changing version number (because it is in test,still) so in this case my account has expired, in those cases google should not send me another id that i could catch here:
#Override
protected void onRegistered
???
However there is a safe way to understand if my app is registered GCM server side?
Thanks!
EDIT:
I'm thinking this:
When i reinstall my application through Eclipse, there is a moment where my application is not installed, if GCM server send me a message in that moment there is no receiver and so google unvalidates my ID.
In your opinion is this idea, a stupid idea?
follow these steps http://developer.android.com/google/gcm/gs.html.
It could happen because some time gcm registartion id gets expired so everytime you should check that is it registered or not if not register it
You should only register the device one time. Save the registrationId in some way (shared preferences is a good one) and use it.
From the documentation:
Register the application for GCM and return the registration ID. You must call this once, when your application is installed, and send the returned registration ID to the server.
In some tests i've made, the registration id returned by gcm.register(id) isn't always the same for the device,app pair. However, Google says:
Repeated calls to this method will return the original registration ID.
If the method gcm.register(id) returns an id, it will be valid ever since.
Best.
Related
I have a list of GCM registered users and their corresponding registration Ids in a database table, and I actually want to unregister a user whenever he/she is deleted from the table. I found a lot of examples here in Stackoverflow, but most of them are based on the old GCMRegistrar API which is now deprecated. I'm using GoogleCloudMessaging API and registering a user by following method:
private void registerUser(){
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(getBaseContext());
String regId = "";
try {
regId = gcm.register(getString(R.string.project_number));
Log.i("registrationId", regId);
}
catch (IOException e) {
Log.i("Registration Error", e.getMessage());
}
}
I have an administrator app, which acts as a 3rd-party application server, since it pushes notifications to all users. I want to unregister a specific user from this administrator app with following method:
private void unRegister(String regId) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(getBaseContext());
try {
gcm.unregister();
}
catch (IOException e) {
System.out.println("Error Message: " + e.getMessage());
}
}
But it confuses me that unregister() method does not take registration Id as an argument, which makes it impossible to unregister a specific device. Is there any way to unregister a specific device from GCM by registration Id ?.
This method does the trick:
gcm.unregister();
However, gcm.unregister() is now deprecated, hence, you must use one of these:
InstanceID.deleteToken() or InstanceID.deleteInstanceID().
These methods take the following parameters:
public void deleteToken (String authorizedEntity, String scope)
Being authorized entity the entity that you want to remove...
// THE FOLLOWING EXPLANATION IS ONLY FOR "UNREGISTER"
So, based on your comment:
But it confuses me that unregister() method does not take registration
Id as an argument, which makes it impossible to unregister a specific
device.
That's because you are expecting it to work in a way that it doesn't. It seems like you want to be able to make an http request passing a parameter to uregister(e.g. "http://www.gcmserver.com?unregisterid=xxxx"), and that's not the way it works, this is the way it works based on Google's Documentation:
How unregistration works
An application can be automatically unregistered after it is
uninstalled from the device. However, this process does not happens
right away, as Android does not provide an uninstall callback. What
happens in this scenario is as follows:
The end user uninstalls the application.
The 3rd-party server sends a message to GCM server.
The GCM server sends the message to the device.
The GCM client receives the message and queries Package Manager about
whether there are broadcast receivers configured to receive it, which
returns false.
The GCM client informs the GCM server that the
application was uninstalled.
The GCM server marks the registration ID for deletion.
The 3rd-party server sends a message to GCM.
The GCM returns a NotRegistered error message to the 3rd-party server.
The 3rd-party deletes the registration ID.
So, based on that, what the method gcm.unregister() actually does is marking that device for deletion(think of it as forcing the first steps of the process without actually uninstalling the app), letting the server know that it no longer needs to get notifications, also by not taking an "Id" as a parameter it means that it is referencing to that specific device.
Regards!
unregister() is now deprecated:
https://developers.google.com/android/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#unregister()
Quoting the docs you should call:
Instead use InstanceID.deleteToken() or InstanceID.deleteInstanceID().
I wanted a solution for the following problem:
I want to send notification specific to user like thank you message for one user and job posted say another user. I am looking for a way so that I can send separate messages depending on user id and registration id.
I tried the following method ie.
When a new user registers then, that users userid gets created on the database. I thought if I also create a registration id at the same time then I can save that in a separate table on the server. which will contain user id and registration_id and device type
But I noticed that at the time of GCM registration it is the Asynchronous task so I obtain it but till the user gets registered the id is still null. So it fails to get into the database.
If anyone has ideas on this particular problem. Or also has solved similar issue. Then do let me know.
Thanks for reading.
Actually the problem is GCM registration often reuires some time to register. So there is a simple way to get your id registered in your database. One is, if you are using splash screen in your app, then try to register for GCM there and in onRegistered method of your GCMIntentService save your registrationId in preferences like this
#Override
protected void onRegistered(Context arg0, String regId) {
Log.v("registrationId", regId);
prefs = getSharedPreferences("filename", 0);
prefs.edit().putString("regid", regId).commit();
}
Now at the time of login you should try to get your registrationId from the prefs where you have stored in onRegistered method. But still there is 1-2 % chance that you will not get you regId here. so for that, you can make a separate api for GCM Registration, that you will hit((if your regid is not registered at Login time)) in Activity next to your LoginActivity to get the id registered to your database.
Secondally, if you are not using splash screen, then you have to make separate api for GCM Registration because there is more chance that you will not get your registrationId during login.
Is there something wrong in the fact that every time I log in to my android application, the first thing I do is to register to GCM.
I know it's not necessary to do this, but in order to check if the registration id is refreshed to a new one or it s still the same, I plan to re-register.
final String regId = GCMRegistrar.getRegistrationId(this);
if (regId.equals("")) {
GCMRegistrar.register(this, SENDER_ID);
} else {
Log.v(TAG, "Already registered");
}
I would also like to know if by re-registering to GCM I am somehow forcing the registrationID to expire.
Thank you!!!
Part 1:
In order to check if the registration id is refreshed to a new one or it is still the same, I plan to re-register.
Now, if you see the second point under the heading Enable GCM on Architectural Overview page, it says:
Note that Google may periodically refresh the registration ID, so you should design your Android application with the understanding that the com.google.android.c2dm.intent.REGISTRATION intent may be called multiple times. Your Android application needs to be able to respond accordingly.
So, Google automatically sends you this broadcast, when it renews the ID. You might not necessarily send check the emptyness of the ID. When Google changes the ID, then also it won't be empty, right? So if you want to handle the renewal/refreshing of the ID then you may do the following:
You should have a Broadcast Listener which could handle com.google.android.c2dm.intent.REGISTRATION intent, which Google send to the app when it has to refresh the registration ID. The broadcast receiver will have the onReceive method with an Intent. From the intent you can get the Bundle using which you can extract the new registration ID from Google. You can save that and send it to the 3rd part server to replace your previous registered ID for that user.
Also you may see this answer on the question In GoogleCloudMessaging API, how to handle the renewal or expiration of registration ID?.
Part 2:
Answering your second part of question:
You may want to read Unregistration here. The docs says If you unregister and then re-register, GCM may return the same ID or a different ID—there's no guarantee either way.
I think that whenever an ID will be about to expire/renew, Google will send you the new ID. Then the response from Google will contain a Canonical Registration ID (which is the new registration ID). This response indicates that your server should delete the old registration ID and use only the new one. ( Source : Answer at Unregistering and re-registering for GCM messages causes two regId's to be valid. Is this as intended? question by #Eran)
Hope this helps you understand how to handle it.
I am using GCM for app notifications as illustrated here. The code is boilerplate:
GCMRegistrar.checkDevice(this);
GCMRegistrar.checkManifest(this);
final String regId = GCMRegistrar.getRegistrationId(this);
if (regId.equals("")) {
GCMRegistrar.register(this, SENDER_ID);
} else {
Log.v(TAG, "Already registered");
}
Then the onRegistered() callback updates my server with the returned registration id.
However, on several occasions GCM has gotten into an inconsistent state. In one case, it doesn't forward any notifications even though GCMRegistrar.getRegistrationId() gives me a non-empty registration id string. In other cases, I end up getting two or more duplicate messages.
In attempt to avoid these situations, I currently have a brute force solution that works like this:
if (GCMRegistrar.isRegistered(this))
GCMRegistrar.unregister(this);
else
GCMRegistrar.register(this, GCMConstants.SENDER_ID);
In the onUnregistered() callback, I tell my server to delete the registration id, and then call GCMRegistrar.register(). In the onRegistered() callback, I tell my server to add the registration id back.
So far, it's working, but it's obviously less efficient than the way this is supposed to work, and I don't know for sure if it's immune to the inconsistency problems. It would be better if I could count on getRegistrationId() to always return a valid id, i.e., the current/canonical registration id.
What's the simplest/cleanest way to ensure consistency between my app, my server, and GCM? Thanks.
The problem of getting duplicate messages can be solved if you parse the response you get from Google, and identify the situation where you receive a canonical registration id in the response. In this case you can delete the old registration id, and keep the canonical one instead.
I think a better solution than your brute force solution is to always call register when the app is launched. You may receive in onRegistered() the same registration ID you got on the previous call, but if you persist that registration id in your device, you can compare the persisted ID to the received ID and avoid re-sending the registration ID to your server if it didn't change.
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.