Handling GCM Registration Id (Which is expiring after seven days) - android

I am developing app on GCM already i have registered in GCM. But after seven days the keyID is expiring. After expiring the app is again start from first onwords from registering..
My code for checking registration
if (GCMRegistrar.isRegisteredOnServer(First.this)) {
// Skips registration.
Intent regact = new Intent(SplashScreen.this,
LoginScreen.class);
startActivity(regact);
Toast.makeText(getApplicationContext(),
"Already registered with GCM",
Toast.LENGTH_LONG).show();
} else {
Intent mainact = new Intent(SplashScreen.this,
MainActivity.class);
startActivity(mainact);
Toast.makeText(getApplicationContext(),
"Have to Register with GCM",
Toast.LENGTH_LONG).show();
}
This is condition for checking the GCM for registered or not. After seven days it is getting unregistered please help me i cant find the solution...
Thanks in advance...

try below code..
final String regId = GCMRegistrar.getRegistrationId(this);
if (regId.equals("")) {
// Automatically registers application on startup.
GCMRegistrar.register(this, SENDER_ID);
} else {
// save your id
}

GCMRegistrar is a deprecated class which you don't have to use anymore. Even if you choose to continue using that class, you don't have to use isRegisteredOnServer. That method (as you can see below), would return false after 7 days pass since you sent the registration ID to your server. That doesn't mean the registration ID expired. It's only meant to make sure that if your server somehow loses the registration ID, it will receive it again after 7 days. If your server is reliable enough, you don't need to rely on this artificial expiration.
/**
* Checks whether the device was successfully registered in the server side,
* as set by {#link #setRegisteredOnServer(Context, boolean)}.
*
* <p>To avoid the scenario where the device sends the registration to the
* server but the server loses it, this flag has an expiration date, which
* is {#link #DEFAULT_ON_SERVER_LIFESPAN_MS} by default (but can be changed
* by {#link #setRegisterOnServerLifespan(Context, long)}).
*/
public static boolean isRegisteredOnServer(Context context) {
final SharedPreferences prefs = getGCMPreferences(context);
boolean isRegistered = prefs.getBoolean(PROPERTY_ON_SERVER, false);
Log.v(TAG, "Is registered on server: " + isRegistered);
if (isRegistered) {
// checks if the information is not stale
long expirationTime =
prefs.getLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, -1);
if (System.currentTimeMillis() > expirationTime) {
Log.v(TAG, "flag expired on: " + new Timestamp(expirationTime));
return false;
}
}
return isRegistered;
}
If you choose to stop using GCMRegistrar, as is recommended by Google, you can simply use the GoogleCloudMessaging.register method to register. That's a blocking method, so you shouldn't run it on the main thread. You should store the returned registration ID in your shared preferences, and only register again when a new version of your app is installed. This demo will show you how to do it.

Related

How to handle FirebaseInstanceId.getInstance().getToken() = null

I have just migrated to FCM. I have added my class that extends from FirebaseInstanceIdService to receive a refreshedToken as and when appropriate.
My question is specific to the case when user installs my app first time and due to some reason, unable to receive a registration Id from onTokenRefresh. How are we supposed to handle this? Can I set a broadcast receiver from my FirebaseInstanceIdService class which will notify the Main activity when a registration Id is received?
if your device have no connection to the internet onTokenRefresh() is never called and you should notify to user his/her device has no internet connection
firebase has its own network change listener and when a device connected to the internet then try to get token and return it, at this time you can tell your main activity by sending a local broadcast receiver that registration token is received.
use below codes:
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d("FCN TOKEN GET", "Refreshed token: " + refreshedToken);
final Intent intent = new Intent("tokenReceiver");
// You can also include some extra data.
final LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
intent.putExtra("token",refreshedToken);
broadcastManager.sendBroadcast(intent);
}
in your main activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
LocalBroadcastManager.getInstance(this).registerReceiver(tokenReceiver,
new IntentFilter("tokenReceiver"));
}
BroadcastReceiver tokenReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String token = intent.getStringExtra("token");
if(token != null)
{
//send token to your server or what you want to do
}
}
};
}
Change this in manifest.xml file
tools:node="replace"
to
tools:node="merge".
As far as I know, token will be null only when you try to run your app on emulator on which google play service is not there and when you are using dual email id on you google play store(on you actual device), but only one email id is verified for the usage. Those are the cases which will give you null token and I have already implemented FCM in my new project. So for rest of any cases , token won't be null.
Use this class extends with..
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static final String TAG = "MyFirebaseIIDService";
public static final String REGISTRATION_SUCCESS = "RegistrationSuccess";
#Override
public void onTokenRefresh() {
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
Toast.makeText(MyFirebaseInstanceIDService.this,refreshedToken,Toast.LENGTH_LONG).show();
}
}
I was facing the same problem. I looked through a lot of SO posts and other forums and I found a solution that worked for me. FCM documentation says to use this method to get a token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
I found a post online (I apologize, I don't remember which one. I found it a while ago) that used this method instead:
String refreshedToken = FirebaseInstanceId.getInstance().getToken() (String authorizedEntity, String scope);
FCM documentation describes the first method as:
Return the master token for the default Firebase project.
While the second one is described as:
Returns a token that authorizes an Entity to perform an action on behalf of the application identified by Instance ID.
This is similar to an OAuth2 token except, it applies to the application instance instead of a user.
For example, to get a token that can be used to send messages to an application via FirebaseMessaging, set to the sender ID, and set to "FCM".
I have been looking into why the first method call takes a longer time to return a token, but I haven't found an answer yet. Hope this helps.
depending on your application logic you can write the code to handle the "new" token directly in the FirebaseInstanceIdService.onTokenRefresh() method, or you can use a LocalBroadcast to send this information to your activity if you need to change the UI when this event happens.
Note that when onTokenRefresh() is called your activity could be closed.
A possible implementation could a mix of the two options:
add some logic in onTokenRefresh() to send the token to your server
use a LocalBroadcastReceiver to inform your activity, if you have a piece of UI that need to change when the token is available.
If you are running it on your emulator, check that you have Google play services enabled in Tools -> Android -> SDK Manager -> SDK Tools -> Google play services
Once installed, reboot both Android Studio and your emulator
It worked for me

Possible to have multiple receiver ids in GoogleCloudMessaging?

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);
}

How to make a simple data storage which can be used both an app and its service in Android?

I have an Android application and its notification service working regardless of the app. Both work perfectly. Through a user-defined period of time the service accesses the server to check for new data. If there was a new post, the service notifies the user via notification Pending Intent, through which the user can open and read fresh news. Unread notifications are not accumulated and overwrite each other, that is user will always see the latest news published.
All this works fine, but users say that alerts are duplicated - are informed of already read news, if there's no new ones. I keep last read news ID in SharedPreferences.
if (post.id != PreferenceManager.getDefaultSharedPreferences(service).getLong(
service.getString(R.string.notifications_last_id), 0)) {
Intent intent = new Intent(service, PostActivity.class);
intent.putExtra(service.getString(R.string.pref_item_id), post.id);
intent.putExtra(service.getString(R.string.notifications_referrer), true);
service.sendNotification(post.rubric.title, post.title, R.id.notifications_news_id, PostActivity.class, intent);
Preferences.setNotificationNewsId(service, post.id);
Log.d(TAG, service.getString(R.string.notifications_last_id) + ":" + post.id);
}
public static void setNotificationNewsId(Context context, long id) {
try {
final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit().putLong(context.getString(R.string.notifications_last_id), id).commit();
} catch (Exception e) {
e.printStackTrace();
}
}
In what could be the reason for the duplication of notifications? Or is there an alternative way of storing the last identifier available for the application and for the service?

Multiple Application ID in Server side in GCM

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
}

Android, Google Cloud Messaging - push gets to phone, but does not create a push notification on the device

I have been trying to get Google Cloud Messaging to create push notifications. I am able to register the device, store the registration id on the server, and then send the push message back to the device.
I am able to do all these and the catLog showed that the push message got to the device. But on the device the push notification message did not appear.
What could be the cause of this?
Just in case, here is how I register the device:
GCMRegistrar.checkDevice(this);
GCMRegistrar.checkManifest(this);
final String regId = GCMRegistrar.getRegistrationId(this);
if (regId.equals(""))
{
// Automatically registers application on startup.
GCMRegistrar.register(getApplicationContext(), SENDER_ID);
}
else
{
// Device is already registered on GCM, check server.
if (GCMRegistrar.isRegisteredOnServer(getApplicationContext()))
{
// Not sure what to do here :)
}
else
{
if ( user_id != null )
{
GCMRegistrar.register(this, SENDER_ID); // google register
setRegistrationId ( user_id , regId ); // saves id on server
}
}
}
End on onPostExecute I do GCMRegistrar.setRegisteredOnServer(getApplicationContext(), true);
Here is my onMessage() method in my GCMIntentService
#Override
protected void onMessage(Context ctxt, Intent message) {
Bundle extras=message.getExtras();
for (String key : extras.keySet()) {
Log.d(getClass().getSimpleName(),
String.format("onMessage: %s=%s", key,
extras.getString(key)));
}
}
Is this the problem maybe? How should it actually be?
Thank you!
What could be the cause of this?
Here are some possibilities:
You do not have a GCMIntentService subclass in your app.
You do, but it is not registered in the manifest.
You do, but you did not override onMessage()
You did, but your onMessage() is not properly logging the event or otherwise letting you know that the event occurred.

Categories

Resources