I would like to create a Google Cloud Messaging app but the problem is I would like to create Registration Token per user not per application (so that different user on same devices receives specific message not app wide). I have google cloud messaging working but I cant seem to figure out how to generate Registration ID so i can send a message to specific user
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId ),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
If I am correct it generates here but how would I for example put user ID here (or where). Or did I misunderstood this entirely.
You can use the topic messaging functionality from GCM.
Your server can send a GCM message to /topics/{userId} and your app should subscribe to the users that are using that device. Your app will then receive the GCM message with the from field set to the topic and your app can take it from there.
You do something like this in your GCM registration service:
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId ),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
GcmPubSub pubSub = GcmPubSub.getInstance(this);
pubSub.subscribe(token, "/topics/user1", null);
pubSub.subscribe(token, "/topics/user2", null);
Note that you don't even need to send the GCM token to your backend service because it is never going to send GCM messages to particular devices, only to topics. Because your app subscribed to the corresponding topics it will receive those messages.
In your GCM onMessageReceived you just get the private message and the userId and store it somewhere.
public void onMessageReceived(String from, Bundle data) {
final int topicsLength = "/topics/".length();
String userId = from.substring(topicsLength);
String privateMessage = data.getString("privateMessage");
saveMessageSomewhere(userId, privateMessage);
}
Then when a user logs on your app they have their messages waiting for them.
Note that it is up to you to generate unique user IDs. You can have your app request one from your backend service, or you could just rely on UUID.randomUUID().
Update
Note that the GCM topic must conform to the specification: /topics/[a-zA-Z0-9-_.~%]+. I had mistakenly assumed path separators are allowed, but if you use something like /topics/users/user1 you will run into:
java.lang.IllegalArgumentException: Invalid topic name: /topics/users/user1
This is because of the path separator character in users/user1. GCM does not allow a hierarchy of topics such as you might have in a REST API.
I have updated the above sample code to avoid this mistake.
You cannot create gcm token yourself. It is generated per application and generated outside your app.
What you can do is to maintain intallation --> user & user-installation table in your database and send notification to all installed instances belonging to a particular user.
Related
I have an InstanceID. I get two differentt tokens for a different app server:
token1 = instanceID.getToken()
token2 = instandeID.getToken()
Can I delete a specific token, for example token1?
You could with deleteInstanceId. Although this would resort in the InstanceId service to generate a new one.
It's intended behavior for each server to generate it's own Registration token for each app instance.
I've been reading on canonical IDs in GCM and how they help to rectify sending duplicate push notifications and with security. But now with Firebase Cloud Messaging (FCM), does this issue still exist?
I am the registration part has been taken away from the developer now and we just wait for a token refresh as per below:
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
// Get updated registration ID
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Logger.d("Refreshed FCM token: " + refreshedToken);
}
}
Some info on canonical IDs can be found here.
Update:
I recently revisited this topic on Canonical IDs and have concluded the following.
In FCM, it seems the Canonical IDs are no longer used (or at the very least extremely rarely) because of the way the Instance ID service works. To put it simply, the service works that there would only be one valid token per App Instance.
If the older token expires (for whichever reason), FCM triggers a tokenRefresh event where you would get a new registration token, and where you must also handle it accordingly (in onTokenRefresh()).
Short answer, Yes. It's still necessary.
The onTokenRefresh() method is expected to trigger whenever the token is actually refreshed. From there, it's the developer's responsibility to send the registration token towards an App Server.
BUT in an event where you weren't able to get a hold of the new registration token (e.g. forgot to save it, deleted it and only have the previous registration token, etc.), it may result to you (the developer) to send towards a supposed to be no longer valid registration token. That's when Canonical IDs come in.
I guess you can treat Canonical IDs as another safety measure so that developers can still get a hold of the valid registration token. Details about Canonical IDs (how it is handled and stuff) are mentioned in the FCM docs here.
Previously registering with multiple senderId's was quite described and easy approach.
final GoogleCloudMessaging instance = GoogleCloudMessaging.getInstance(context);
final String registrationId = instance.register(senderId1, senderId2);
I could not find how to acheive the same using the InstanceId flow. I tried
String token = instanceID.getToken("SENDER_ID1,SENDER_ID2,SENDER_ID3", GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
but seems like it does not work. I know that, registering getToken() for each senderId(authorizedEntity) would work, thus providing me 3 different token but the objective is to have 1 and only 1 registrationId.
Also if we go by sample and use google services plugin in AS, there seems to be a
'google-services.json' file that consist only one google-project/client information.
Does it have any relation with that.
Upon checking the internet for the solution in your problem, I found here in Multiple GCM senders in the same app, that Google support multiple GCM senders in a single app, but you have to account for it. If not, one or more GCM senders will fail to send GCM intents, and GCM intents that do come in may randomly fail to reach GCM receivers in your manifest.
The best way to do this is to handle GCM registration yourself, rather than letting individual libraries perform the registration. Note that you would use gcm_defaultSenderId or googleCloudMessagingSenderId on the Layer client; instead, you'll have to join the sender IDs of each library with a comma.
This is a sample code on how to register multiple senderID using instanceID.
public class RegistrationIntentService extends IntentService {
#Override
public void onHandleIntent(Intent intent) {
InstanceID instanceID = InstanceID.getInstance(this);
// Comma-concatenated sender IDs
String senderIDs = "SENDER_ID_1,SENDER_ID_2";
String token = instanceID.getToken(senderIDs, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
// ...
}
}
To make this possible, all you need to do is have each sender generate its own project number. Then include those IDs in the sender field, separated by commas, when requesting a registration. Finally, share the registration ID with your partners, and they'll be able to send messages to your application using their own authentication keys.
For more information about instanceID, you can check this page.
I am using GCM for triggering notification to my android app. notification are triggered from my server. for example suppose the user registers an account in app then server will be sending notifications for that I am passing GCM registration id in my registration request. till now it works perfectly. now I have one more API that is another server. and I am sending the same GCM Registration Id in that request, but I am not getting any notification from that server, so from some reading I have found that each registration_id is associated with a particular app and its corresponding server API key i.e. a single device has different registration_ids for different apps Thus, we got a MismatchSenderId error while trying to send push notifications using the registration_id. how do I resolve this ? I have googled and didn't find any proper solution.
I am generating GCM registration in this way :
String token = instanceID.getToken(defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
Since you have 2 different servers, I believe you have two different sender ID. So in your code, you must have 2 token, one for each server.
Sample:
Token for server 1:
String token = instanceID.getToken(<sender_id_1>),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
Token for server 2:
String token2 = instanceID.getToken(<sender_id_2>),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
There can be an issue in case when a token is updated:
in InstanceIDListenerService I see no way to identify token was updated - for sender_1 or for sender_2.
So it seems when onTokenRefresh is called we have to get new tokens for both senders.
I am started to exploring on GCM. Please clarify the following things.
By Registering with GCM server using the SenderID (Project ID get it from google API console), the Different device will giving unique registration id. I have used the following code to send message from server to all the devices by adding registration id as deviceid in the devicelist . I got the registration id of device by logging in the logcat.
Sender sender = new Sender("MY_API_KEY");
Message message = new Message.Builder().collapseKey("1")
.timeToLive(3)
.delayWhileIdle(true)
.addData("message",
"this text will be seen in notification bar!!")
.build();
MulticastResult result;
ArrayList<String> devicesList = new ArrayList<String>();
devicesList.add(deviceid1);
devicesList.add(deviceid2);
result = sender.send(message, devicesList, 1);
Is it right way to send message like above mentioned?
If that's the case how can design the code it will work after release the particular application? how can i get the registration id of all the devices after releasing?
Your server needs to keep track of all the registration ids from the devices. Therefore, you need a database table to store those registration ids. Then you need to expose a web service, or a HTTP POST entry point for your clients to upload their registration ids.
After a device successfully register with Google GCM server, you will receive the registration id in the onRegistered() callback method in GCMBaseIntentService. This is where you want to upload the registration id to your server.