On server side, i found for one device there multiple registration IDs, which obviously is creating for me lots of issues. like messages received many times.
How could I get red of old registration IDs, or make sure that registration doesn't happen if there a valid registration ID.
I follow the example tutorial on Android doc when I wrote my app as below:
checkNotNull(SERVER_URL, "SERVER_URL");
checkNotNull(SENDER_ID, "SENDER_ID");
// Make sure the device has the proper dependencies.
GCMRegistrar.checkDevice(this);
// Make sure the manifest was properly set - comment out this line
// while developing the app, then uncomment it when it's ready.
// NOT required any more GCMRegistrar.checkManifest(this);
/**
* this code to register reciver moved to message actvity
*/
//registerReceiver(mHandleMessageReceiver, new IntentFilter(
// DISPLAY_MESSAGE_ACTION));
/* final String */regId = GCMRegistrar.getRegistrationId(this);
/**
* save regId in pref to be used by Location update service
*/
SavePreferences("regId", regId);
if (regId.equals("")) {
// Automatically registers application on startup.
GCMRegistrar.register(this, SENDER_ID);
} else {
// Device is already registered on GCM, check server.
if (GCMRegistrar.isRegisteredOnServer(this)) {
;;
// Skips registration.
// -- mDisplay.append(getString(R.string.already_registered) +
// "\n");
// System.out.println(getString(R.string.already_registered)
// + "\n");
} else {
// Try to register again, but not in the UI thread.
// It's also necessary to cancel the thread onDestroy(),
// hence the use of AsyncTask instead of a raw thread.
final Context context = this;
mRegisterTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
boolean registered = ServerUtilities.register(context,
regId);
// At this point all attempts to register with the app
// server failed, so we need to unregister the device
// from GCM - the app will try to register again when
// it is restarted. Note that GCM will send an
// unregistered callback upon completion, but
// GCMIntentService.onUnregistered() will ignore it.
if (!registered) {
GCMRegistrar.unregister(context);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
mRegisterTask = null;
}
};
mRegisterTask.execute(null, null, null);
}
}
Please refer link: http://stackoverflow.com/questions/15030233/gcm-multiple-application-id-in-server-side/15030465#comment21123039_15030465
Also check canonical registration ids concept :http://developer.android.com/google/gcm/adv.html
or
when a new id is generated you will try to register it GCM registrar. when this new registration id successfully register your onRegister() method of service will be called .
here you can add code to replace previous one with new one.but for this along with registration id you need to send some unique reference to server,so for next time you can check this unique reference and replace existing registration id with new one
checked following code:
#Override
protected void onRegistered(Context context, String registrationId) {
ServiceUtilities.register(context, registrationId);
//call service and replace id
}
Related
I am using eclipse IDE for development. I followed lots of tutorials and implemented push notifications in my project but I'm not getting the GCM Registration id, So my questions is: will eclipse support the push notifications or not?
Below is the code snippet; if you need more clarity please comment below.
registerReceiver(mHandleMessageReceiver, new IntentFilter(DISPLAY_MESSAGE_ACTION));
Log.v("testing", "testing");
// Get GCM registration id
final String regId = GCMRegistrar.getRegistrationId(this);
Log.v("regId", regId);
// Check if regid already presents
if (regId.equals("")) {
// Registration is not present, register now with GCM
Log.v("registerd","am here");
GCMRegistrar.register(this, SENDER_ID);
} else {
// Device is already registered on GCM
if (GCMRegistrar.isRegisteredOnServer(this)) {
// Skips registration.
Toast.makeText(getApplicationContext(), "Already registered with GCM", Toast.LENGTH_LONG).show();
} else {
// Try to register again, but not in the UI thread.
// It's also necessary to cancel the thread onDestroy(),
// hence the use of AsyncTask instead of a raw thread.
final Context context = this;
Log.v("hello","am here");
mRegisterTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// Register on our server
// On server creates a new user
ServerUtilities.register(context, name, email, regId);
return null;
}
#Override
protected void onPostExecute(Void result) {
mRegisterTask = null;
}
};
mRegisterTask.execute(null, null, null);
}
Push notifications will work no matter what IDE you're using, but I have two pieces of advice for you:
You need to migrate your project to Android Studio for better support.
Your GCM registration library GCMRegistrar is too old. You need to get the latest version, checkout here.
Hope this helped :)
Finally got the answer by using following tutorial.. link
I used this code to get gcm registration id. (Earlier)
// Make sure the device has the proper dependencies.
GCMRegistrar.checkDevice(this);
// Make sure the manifest was properly set - comment out this line
// while developing the app, then uncomment it when it's ready.
GCMRegistrar.checkManifest(this);
// registerReceiver(mHandleMessageReceiver, new IntentFilter(
// CommonUtilities.DISPLAY_MESSAGE_ACTION));
// Get GCM registration id
final String regId = GCMRegistrar.getRegistrationId(this);
// Check if regid already presents
if (regId.equals("")) {
// Registration is not present, register now with GCM
GCMRegistrar.register(this, CommonUtilities.SENDER_ID);
} else {
AppSharedPreferences.saveDeviceIDPreference(ctx, regId);
// Device is already registered on GCM
if (GCMRegistrar.isRegisteredOnServer(this)) {
// Skips registration.
// Toast.makeText(getApplicationContext(), "Already registered with GCM", Toast.LENGTH_LONG).show();
} else {
// Try to register again, but not in the UI thread.
// It's also necessary to cancel the thread onDestroy(),
// hence the use of AsyncTask instead of a raw thread.
final Context context = this;
mRegisterTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// Register on our server
// On server creates a new user
ServerUtilities.register(context, regId);
return null;
}
#Override
protected void onPostExecute(Void result) {
mRegisterTask = null;
}
};
mRegisterTask.execute(null, null, null);
}
}
But, shockingly, it seems to change everytime on execution, for the same device and same application. Please let me know the possible reason of that.
EDITED
modified GCM to the newer version
gcm = GoogleCloudMessaging.getInstance(this);
new RegisterBackground().execute();
Followed this tutorial.
But, still same behaviour, i.e, getting new reg id on every install.
I am successful in registering to GCM server and posting registration id to our server but it is taking two attempts to complete the whole cycle. I need to do all these in single attempt. I am adding my code below please correct me if I am wrong.
First attempt: It will register to gcm server.
Second attempt : It will register to our server
protected void RegisterApp() {
// -----------------------------------
aServerUtility = (GCMServerController) getApplicationContext();
// Check if Internet present
if (!aServerUtility.isConnectingToInternet()) {
// Internet Connection is not present
aServerUtility.showAlertDialog(this, "Internet Connection Error",
"Please connect to Internet connection", false);
// stop executing code by return
return;
}//
// Make sure the device has the proper dependencies.
GCMRegistrar.checkDevice(this);
// Make sure the manifest permissions was properly set
GCMRegistrar.checkManifest(this);
// Register custom Broadcast receiver to show messages on activity
registerReceiver(mHandleMessageReceiver, new IntentFilter(Config.DISPLAY_MESSAGE_ACTION));
// Get GCM registration id
final String regId = GCMRegistrar.getRegistrationId(this);
final String Username = etUserName.getText().toString();
if (regId.equals("")) {
// Register with GCM
GCMRegistrar.register(common_signin.this, Config.GOOGLE_SENDER_ID);
} else {
// Device is already registered on GCM Server
if (GCMRegistrar.isRegisteredOnServer(this)) {
// Skips registration.
Toast.makeText(getApplicationContext(),
regId + " - Already registered with GCM Server",
Toast.LENGTH_LONG).show();
Log.i(TAG, "Registered device (regId = " + regId + ")");
} else {
// Try to register again, but not in the UI thread.
// It's also necessary to cancel the thread onDestroy(),
// hence the use of AsyncTask instead of a raw thread.
final Context context = this;
mRegisterTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// Register on our server
// On server creates a new user
try {
aServerUtility.register(context, Username, "", regId);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
mRegisterTask = null;
}
};
// execute AsyncTask
mRegisterTask.execute(null, null, null);
}
}
// ---------------------------------------
// Create a broadcast receiver to get message and show on screen
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString(
Config.EXTRA_MESSAGE);
// Waking up mobile if it is sleeping
aServerUtility.acquireWakeLock(getApplicationContext());
// Display message on the screen
// lblMessage.append(newMessage + "");
Toast.makeText(getApplicationContext(),
"Got Message: " + newMessage, Toast.LENGTH_LONG).show();
// Releasing wake lock
aServerUtility.releaseWakeLock();
}
};
}
Two calls to this method were needed because you only called GCMRegistrar.register() when there is no existing registration ID (in if (regId.equals(""))). The method ends after that and does not call aServerUtility.register(), which performs the server registration. It is only in the second call, when if (regId.equals("")) is false, that you actually make the call to register with your server.
Having said all this, please take note that GCMRegistrar is deprecated. I would suggest moving to GCM.
I am following this tutorial:
http://www.androidhive.info/2012/10/android-push-notifications-using-google-cloud-messaging-gcm-php-and-mysql/
my app is getting gcm_regid, that is stored in mysql. With this id, I can send message via php to chosen regid;
but when i deinstall the application - and reinstall, it get's a new reg_id - thats ok too, this is stored in mysql too.
But when I send a message to the first gcm_regid (this was it's previous gcm_regid) the phone is getting that message too, even it has got a new gcm_regid (due to reinstall) - why is that so, and how can I delete the previous id?
and where is that id? in my device? stored in gcm server?
and a second question:
do I have to take majour changes when I change GCMRegistrar in the tutorial above to Google Cloud Messaging - what I have to do there
When GCM assigns a new Registration ID to your device, the previous IDs that were assigned to it continue to work. If you send a message to an older Registration ID assigned to your device, the message will be delivered, but your server will get a response containing a canonical Regsitration ID, which is the newest Registration ID of that device. If you get such a response, you should delete the old Registration ID from your DB.
As for your second question, you don't have to make major changes in order to stop using GCMRegigtrar and use GoogleCloudMessaging instead. In fact, your code should look simpler after you make that change.
You'll have one call to GoogleCloudMessaging.register inside an AsyncTask in one of your activities. This method has to be called in an AsyncTask because it's blocking, so it can't be executed on the main thread. The good thing about it is that you get the response in the same place you call the method, and don't have to wait for it in the GCMBroadCastReceiver/IntentService.
Your GCMBroadcastReceiver/IntentService will have to handle just incoming messages. They won't have to deal with registration anymore.
Here's a partial example of the new registration process, taken from the official GCM Demo :
/**
* Registers the application with GCM servers asynchronously.
* <p>
* Stores the registration ID and the app versionCode in the application's
* shared preferences.
*/
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP, so it
// can use GCM/HTTP or CCS to send messages to your app.
sendRegistrationIdToBackend();
// For this demo: we don't need to send it because the device will send
// upstream messages to a server that echo back the message using the
// 'from' address in the message.
// Persist the regID - no need to register again.
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
}
I am embedding GCM for push notification in my app. I'm facing a very weird problem, on first run I'm not able to get GCM registration token, but when you run my app second time you will get the registration ID printing on the console. I don't know what am I doing worng. Here is what I have done so far.
This is my onCreate() method where I want to print GCM regID:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String regId = GCMRegistrar.getRegistrationId(this);
GCM_regID = regId;
System.out.println("GCM regId: "+GCM_regID);
Doing the following code inside onCreate():
/**
* Google Cloud Messaging - Getting server Url and device ID to send it
* across Google server for the notification..
*/
mGCMReceiver = new GCMReceiver();
mOnRegisteredFilter = new IntentFilter();
mOnRegisteredFilter.addAction(Constants.ACTION_ON_REGISTERED);
if (Constants.SENDER_ID == null) {
// mStatus.setText("Missing SENDER_ID");
return;
}
if (Constants.SERVER_URL == null) {
// mStatus.setText("Missing SERVER_URL");
return;
}
GCMRegistrar.checkDevice(this);
GCMRegistrar.checkManifest(this);
if (!regId.equals("")) {
sendIdToServer(regId);
} else {
GCMRegistrar.register(getApplicationContext(), Constants.SENDER_ID);
}
sendIdToServer(regId);
}
Sending GCM_regId to server via these method as guided in one of the tutorial:
/**
* GCM - sending the data in json format to server db
* */
public void sendIdToServer(String regId) {
(new SendRegistrationIdTask(regId)).execute();
GCM_regID = regId;
}
private class GCMReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String regId = intent
.getStringExtra(Constants.FIELD_REGISTRATION_ID);
token = regId;
}
}
private final class SendRegistrationIdTask extends
AsyncTask<String, Void, HttpResponse> {
// private String mRegId;
public SendRegistrationIdTask(String regId) {
// mRegId = regId;
}
#Override
protected HttpResponse doInBackground(String... regIds) {
// String url = Constants.SERVER_URL + "/register";
return null;
}
#Override
protected void onPostExecute(HttpResponse response) {
if (response == null) {
return;
}
StatusLine httpStatus = response.getStatusLine();
if (httpStatus.getStatusCode() != 200) {
Log.e(Constants.TAG, "Status: " + httpStatus.getStatusCode());
return;
}
}
}
I don't think so, GCMIntentService class is needed here for my problem. Please look into this and help me in getting out of this issue.
I'm able to print in GCMIntentService class, on onRegistered(). Here it goes:
#Override
protected void onRegistered(Context context, String regId) {
Intent intent = new Intent(Constants.ACTION_ON_REGISTERED);
intent.putExtra(Constants.FIELD_REGISTRATION_ID, regId);
context.sendBroadcast(intent);
}
I have to print the regId on MainActivity, on onCreate().
Registering the device will take some time.. So if you will try to retrieve the registration id immediately after registering the device in onCreate() then every time it will return a null value.. So try to register your device inside onCreate() and retrieve the id in any different activity/Service (You can retrieve the Id from GCMIntentService class the api from GCM). Note method of GCM Intent Service class.
protected void onRegistered(Context arg0, String arg1) {
Logger.d(arg0, "REG ID="+arg1);
regID = arg1;
}
This is method is called after Reg is done.
So for my case the regID i took this as a static string and am accessing it else.
OR Like u want the regID on Activity B it is preferred to Register it on Activity A and retrieve it via the static string in the above method from the GCMIntent Class.
The reason that you are not getting the regID the first time you run your app is because your app does not have a regID yet, it needs to ask the GCM servers for it. So when you call final String regId = GCMRegistrar.getRegistrationId(this); the first time it will return an empty string. However once you have been registered with GCM the next time you make that call (the next time your app starts) your regID will be returned. The GCM jar simply stores the regID as a string in the app prefs.
When the GCM servers register your device, you will know about it when GCMIntentService.OnRegistered() is called. In your code you are broadcasting an intent with your regID in the GCMIntentService.OnRegistered() which I assume you want to handle with your GCMReceiver (?) although in the code sample you have shown I do not see you creating an instance of the class or registering it as a receiver.
What I think you will want to in GCMReceiver.onReceive() is call sendIdToServer() with the regID that you got from the intent. e.g.
#Override
public void onReceive(Context context, Intent intent) {
String regId = intent
.getStringExtra(Constants.FIELD_REGISTRATION_ID);
Log.i("regID: ", regId);
sendIdToServer(regId);
}
We have a GCM/Airbop client sample that you might want to look at. It is based on the GCM Demo app which you should take a look at.
If you are not logged into a Google account in the emulator will not work. Try logging in with a valid account of Google ( gmail ) and see .