I'm developing a GCM Application.
My issue is that when first install(launch) the app, it takes some time to get GCM token.
But My app just 'POST' to server to register the user.
So at first launch , because of registering when GCM token is null, my app always register GCM token null at first time.
How could I solve this problem?
Actually I tried to solve this by using Progressbar but Progressbar doesn't show like the sample project of GCM provided by google.
How do you guys solve this problem?
You should only send the token to your application server after it has been returned by your InstanceID.getToken call which should not happen on the main thread.
You should use an IntentService that will get the token AND send it to your application server, then if necessary, you can use a BroadcastReceiver/LocalBroadcastManager to let your UI know when the the token has been successfully sent to the application server.
Consider the GCM quickstart sample. In particular look at the RegistrationIntentService that gets the token and sends it to the server.
// [START get_token]
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
// [END get_token]
Log.i(TAG, "GCM Registration Token: " + token);
// TODO: Implement this method to send any registration to your app's servers.
sendRegistrationToServer(token);
This should be quite an easy fix. if you followed googles example then the registering to the GCM should be done using an async task class called RegisterApp.
The async task has 3 main methods OnPreExecute, DoInBackground and OnPostExecute. DoInBackground is the method that runs on a seperate thread and that will be why it is failing currently. It hasn't finished running that thread and you have already sent an empty regID to your backend. This wont be failing next time you login to your app because more than likely you are saving the regId to a file and reading it if your app is already registered to the GCM
You can send the regId to your backend in either the DoInBackground, which is where you should be registering to the GCM, or in the OnPostExecute.
I do it in the DoInBackground method straight after it registers as this is the only part that runs on a separate thread and if for some reason it fails to send to my backend it is handled on a seperate thread to the main UIThread.
Dont forget you will also need your current method of sending it because the RegisterApp wont run if your app is already registered.
Hope this helps.
This is the sample i followed. Here
Currently it works for me as the activity that handles the registering is locked to portrait and not much else is going on, but each to their own.
Arthur makes some valid points
Related
I have implemented GCM in my project using guidelines from https://developers.google.com.
Steps that I have take are:
For receiving device Token:
-> Class GCMRegistrationIntentService which extends IntentService and it is started from my mainActivity.
-> In this service I have used:
InstanceID instanceID = InstanceID.getInstance(getApplicationContext());
token = instanceID.getToken(AppConstants.SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
I have received the token successfully.
LocalBroadcastListener in my main activity to get the token generated in step 1 and store it in shared preference (Also send it to my message Server).
Class GCMTokenRefreshListenerService which extends InstanceIDListenerService to get the token in case old one expired.
-> In this I made a call to GCMRegistrationIntentService in onTokenRefresh()
Now my questions are:
In which case GCMTokenRefreshListenerService be called?
What is instanceID? What is lifecycle of instanceID?
I ran the service from terminal using:
./adb shell am startservice -a com.google.android.gms.iid.InstanceID --es "CMD" "RST" -n package.name/service.name.
Which gave me new token every time. How do I save this newly generated token in my shared preference?
When I receive new token from this service, I don’t receive notification as my token is changed. I will have to open my app in order to update the token. How to update this token?
Do I have to call GCM every time when my app opens to get the token?
You don't have to call your GCMTokenRefreshListenerService it is called automatically by android system whenever your token is refreshed.
Instance ID provides a unique ID per instance of your apps. You can find more about it here.
First you don't have to run your service, as i said earlier it will be called automatically every time your token is refreshed. To send the token to your server you should call a separate service say RegistrationService. To save the token in your SharedPreference you can do that from your RegistrationService once you have received your token.
You won't receive notification in your GcmListenerService this service is called only if your server has send some data to you via the push notification. Whenever your token is changed/refreshed you get a call in your onTokenRefresh() method. You should than make your server aware of this new token to receive notifications properly using the RegistrationService. And you don't have to open your app to get the refreshed token.
No you don't have to call or start any of the service required for push notification you just have to specify the service properly in your manifest rest all things will be handled by android system
I am using Google's GCM service in my app. I tried the sample code and it worked fine for me. But there is one thing regarding the registration token that confuses me.
The sample code inside the function onHandleIntent(Intent intent) in RegistrationIntentService.java has lines to get the token and then uses is to subscribe the topic
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
I understand that the token refresh may be initiated by the system from reading the sample code MyInstanceIDListenerService.java, and then I will have to notify the server from the callback function onTokenRefresh().
I found that the function onHandleIntent(Intent intent) is always called when I tap the notification to open the app, as a result, the registration token will be generated again. My question is, I can set flat at the point when onTokenRefresh() to determine if I need to update the server and re-subscribe the topic. But can I safely assume the token will never get changed from app launch?
"Does GCM registeration token remain unchanged if app never update and the InstanceID provider never initiate refresh"
The short answer is yes. It never changes. If it does on token refresh will be called. As for the google sample code, there are few vital pieces missing from it which you have to fill up yourself. The first is that RegistrationIntentService does not check if the device is already registered. You should save this information in shared preferences.
If the device is already registered there is no need for this bit of code:
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
Now the question arises what happens if you do call execute this code over and over again? I did experiment with that and found that some devices kept giving the same token over and over again but other devices returned different tokens.
I am implementing Google Cloud Messaging service in my cordova app. so far everything is working well. I however have some few issues bothering I wish someone can clarify them for me.
1) At this section of the code where I get the device GCM regID and further save it to on my server. I will like to know if I should call this script and thus save GCM regID to my server anytime the user opens the App or it should be called and saved once..
function onNotification(e) {
switch( e.event )
{
case 'registered':
if ( e.regid.length > 0 )
{
console.log("regID = " + e.regid);
}
break;
}
}
2) I have noticed on the console that my registered ID sometime changes. I will like to know why that happens, whether it is normal and also if I should be updating the users GCM regID on my server.
I wil be glad if anyone can clarify these for me. Thank you
for (1) it should be called and saved on server once. as am working in my applications and save this id to server once, and all things working fine.
for (2) however in development the registrations id's sometimes changes. The reason is that in development we uninstall or reinstall the application completely. thus makes the registration id's to change.because registration id assigned on app installation. but for exceptional case also see this.
You should call the script every time. Only update the registration ID if it has changed.
Read my answer. Also, this answer for more details
You only need to send your registration token to your server once. If your registration token changes you should send the changed registration token to your server.
The registration token may change if the application is uninstalled and reinstalled or if GCM determines that the token has been compromised in some way.
You should register a service to listen for registration token changes it should extend InstanceIDListenerService and you override its onTokenRefresh method like this:
#Override
public void onTokenRefresh() {
// Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
Log.i(TAG, "GCM Registration Token: " + token);
// Send token to server.
}
Consider GCM getting started documentation for more details.
I have tried to register my device by calling the push notification service which stores tokens inside push_notification_token table.
Registering the token is no problem but in the same app i wanted to delete the token from the table in some situation so i was trying to see if same service is helpful or not.
I tried calling the service by using URL http://mysite/endpoint/push_notifications to register the token where i will pass parameters as token is token generated from GCM service and type is android. This is working fine.
So to delete the token what is the procedure.
I solved the issue by following these steps.
1) Used DELETE method instead of normal POST method
2) Sent the tokens in the URL => http://example.com/endpoint_name/push_notifications/{token}
Like http://example.com/endpoint_name/push_notifications/abcgr123 whole token value in the end.
This will delete that token from the database.
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.