I am confused while implementing the upstream message using the new GoogleCloudMessaging APIs :
public void onClick(final View view) {
if (view == findViewById(R.id.send)) {
new AsyncTask() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
Bundle data = new Bundle();
data.putString("hello", "World");
String id = Integer.toString(msgId.incrementAndGet());
gcm.send(SENDER_ID + "#gcm.googleapis.com", id, data);
msg = "Sent message";
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
} else if (view == findViewById(R.id.clear)) {
mDisplay.setText("");
}
}
We send the messages(XMPP) to GCM server using the SENDER_ID id, so how can my third party server identify my device only with the SENDER_ID?
gcm.send(SENDER_ID + "#gcm.googleapis.com", id, data);
The code you posted sends a message from your device to your 3rd server, not to another device. Your server should establish a connection with the Cloud Connection Server, and since establishing that connection requires using SENDER_ID + "#gcm.googleapis.com" for user name, the GCM server can identify your 3rd party server.
When you 3rd party server sends a message to your device, it uses the Registration ID, which identifies your app on a specific device.
EDIT :
I may have misunderstood your question. If you are asking how does the 3rd party server know which device sent the upstream message to it, the message that your 3rd party server receives contains the Registration ID of the sender, as you can see here :
<message id="">
<gcm xmlns="google:mobile:data">
{
"category":"com.example.yourapp", // to know which app sent it
"data":
{
"hello":"world",
},
"message_id":"m-123",
"from":"REGID"
}
</gcm>
</message>
Even though you don't specify the Registration ID when you call gcm.send(...), GCM knows which device sent the message, so (assuming your app registered to GCM and therefore has a Registration ID) they can add the Registration ID to the message (I'm not sure if they add it on the client side before connecting the GCM server, or if the add it at the GCM server, but it doesn't really matter).
Related
I followed Google Cloud Messaging (GCM) with local device groups on Android gives HTTP Error code 401 to manage local device groups on Android and successfully got a notification key, but when I send message to the notification key, I never get the message back.
Has anyone ever got this work?
My send code is like:
public void sendMessage(View view) {
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
try {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(getApplicationContext());
String to = notificationKey; // the notification key
AtomicInteger msgId = new AtomicInteger();
String id = Integer.toString(msgId.incrementAndGet());
Bundle data = new Bundle();
data.putString("hello", "world");
gcm.send(to, id, data);
Log.e(TAG, "sendMessage done.");
} catch (Exception ex) {
Log.e(TAG, ex.toString());
}
return null;
}
};
task.execute();
}
It seems there's a misunderstanding about the GCM concept. The app server is an integral part of GCM messaging.
The server side of Google Cloud Messaging (GCM) consists of two
components:
GCM connection servers provided by Google. These servers take messages
from an app server and send them to a client app running on a device.
Google provides connection servers for HTTP and XMPP.
An application
server that you must implement in your environment. This application
server sends data to a client app via the chosen GCM connection
server, using the appropriate XMPP or HTTP protocol.
Try the Android GCM Playground to get a better understanding of this.
Here's a snippet:
public void sendMessage() {
String senderId = getString(R.string.gcm_defaultSenderId);
if (!("".equals(senderId))) {
String text = upstreamMessageField.getText().toString();
if (text == "") {
showToast("Please enter a message to send");
return;
}
// Create the bundle for sending the message.
Bundle message = new Bundle();
message.putString(RegistrationConstants.ACTION, RegistrationConstants.UPSTREAM_MESSAGE);
message.putString(RegistrationConstants.EXTRA_KEY_MESSAGE, text);
try {
gcm.send(GcmPlaygroundUtil.getServerUrl(senderId),
String.valueOf(System.currentTimeMillis()), message);
showToast("Message sent successfully");
} catch (IOException e) {
Log.e(TAG, "Message failed", e);
showToast("Upstream FAILED");
}
}
}
The to field of the send method represents the sender ID of your project. You cannot use this method to send messages to Instance ID tokens (other devices), Device to Device messaging is not currently supported by GCM.
You are correct to avoid including the API key in your client app, so currently you will need an app server to send these types of messages.
I'm working on a mobile application and i'm on Push Notification.
I can retrieve a token from a phone (apple or android) for send a push but i have a question :
This token is always the same ? If a get one time the token, i need to check if the token change ?
From apple documentation,
The form of this phase of token trust ensures that only APNs generates
the token which it will later honor, and it can assure itself that a
token handed to it by a device is the same token that it previously
provisioned for that particular device—and only for that device.
If the user restores backup data to a new device or reinstalls the
operating system, the device token changes.
So, its always good to update the server with the token received from APN. As part of optimisation, if you are receiving the same token, there is no need to update the server.
For Android:
It depends on your implementation, but what is recommended from google is that the registration id, can be changed after the app is updated...
Everytime the registration id is changed, the client should update the server with the new value.
check: http://developer.android.com/google/gcm/client.html#sample-register
if (checkPlayServices()) {
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(context);
if (regid.isEmpty()) {
registerInBackground();
}
} else {
Log.i(TAG, "No valid Google Play Services APK found.");
}
private void registerInBackground() {
new AsyncTask() {
#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.
// The request to your server should be authenticated if your app
// is using accounts.
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 doing work on GCM (Google Cloud Messaging) in Android. I am looking for the upstream message using GCM.
Code send the GCM messages to cloud here
try {
Bundle data = new Bundle();
// the account is used for keeping
// track of user notifications
data.putString("account", account);
// the action is used to distinguish
// different message types on the server
data.putString("action", Constants.ACTION_REGISTER);
String msgId = Integer.toString(getNextMsgId());
gcm.send(projectId + "#gcm.googleapis.com", msgId,
Constants.GCM_DEFAULT_TTL, data);
} catch (IOException e) {
Log.e("grokkingandroid",
"IOException while sending registration id", e);
}
Now question is that what cloud would do for that upstream message, Where it can be useful in Android and How ??
When you send an upstream message from your app, the GCM Cloud Connection Server (CCS) transfers that message to your server. In order for that to work, you must implement a server that supports XMPP protocol and establishes a TLS connection with GCM Cloud Connection Server. You also need your API project to be white-listed for using this feature. You can read more about it here.
As for usefulness, it allows you to send messages to your app via the GCM connection instead of via your own connection between your app and your server. That's more battery efficient.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "FCM Token creation logic");
// Get variables reference
deviceText = (TextView) findViewById(R.id.deviceText);
editTextEcho = (EditText) findViewById(R.id.editTextEcho);
buttonUpstreamEcho = (Button) findViewById(R.id.buttonUpstreamEcho);
//Get token from Firebase
FirebaseMessaging.getInstance().subscribeToTopic("test");
final String token = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Token: " + token);
deviceText.setText(token);
//Call the token service to save the token in the database
tokenService = new TokenService(this, this);
tokenService.registerTokenInDB(token);
buttonUpstreamEcho.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Echo Upstream message logic");
String message = editTextEcho.getText().toString();
Log.d(TAG, "Message: " + message + ", recipient: " + token);
FirebaseMessaging.getInstance().send(new RemoteMessage.Builder(FCM_PROJECT_SENDER_ID + FCM_SERVER_CONNECTION)
.setMessageId(Integer.toString(RANDOM.nextInt()))
.addData("message", message)
.addData("action", BACKEND_ACTION_ECHO)
.build());
// To send a message to other device through the XMPP Server, you should add the
// receiverId and change the action name to BACKEND_ACTION_MESSAGE in the data
}
});
}
This is a sample Android project to showcase the Firebase Cloud Messaging (FCM) to manage upstream and downstream messages.
https://github.com/carlosCharz/FCMTest
This is the video in youtube that explains what it does.
https://www.youtube.com/watch?v=SEzOKSoAMG0
Hope you find it useful.
hello i am following the official documentation of android to send the push notification as the old method is deprecated but im facing problem in implementing GCM Client
http://developer.android.com/google/gcm/client.html
the tutorial is written here, scroll down and see
private void registerInBackground()
when i write this function on my app it gives me this error
Syntax error on token "void", # expected
i have googled it and i know the error now that this method is trying to create a method inside a method but still im confused because it is the official documentation i must have done something wrong, can anybody point out plz?
here is the method on this tutorial:
private void registerInBackground() {
new AsyncTask() {
#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.
// The request to your server should be authenticated if your app
// is using accounts.
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);
...
/**
* Sends the registration ID to your server over HTTP, so it can use GCM/HTTP
* or CCS to send messages to your app. Not needed for this demo since the
* device sends upstream messages to a server that echoes back the message
* using the 'from' address in the message.
*/
private void sendRegistrationIdToBackend() {
// Your implementation here.
}
}
now see that sendRegistrationIdToBackend is inside a method itself, any help plz?
here is the solution i found for it and disappointed that 33 people viewed it but nobody bother to ans anyways here is the code
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 trying to understand GCM from the developer android site. I have implemented the client side android app following the instructions at http://developer.android.com/google/gcm/client.html. The code i used is downloaded from https://code.google.com/p/gcm/ as they have mentioned. The GCM registration function works perfectly on my phone.
Now the problem is, no where in the android app code do i see a place to mention my xmpp based app server name. So if i don't mention my server name, how will the message go to my server? i am confused as to how will my app interact with my server. The exact code that sends the message from the android app to the server is :
// Send an upstream message.
public void onClick(final View view) {
if (view == findViewById(R.id.send)) {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
Bundle data = new Bundle();
data.putString("my_message", "Hello World");
data.putString("my_action", "com.google.android.gcm.demo.app.ECHO_NOW");
String id = Integer.toString(msgId.incrementAndGet());
gcm.send(SENDER_ID + "#gcm.googleapis.com", id, data);
msg = "Sent message";
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
} else if (view == findViewById(R.id.clear)) {
mDisplay.setText("");
}
}
When you send a device to cloud message from your app to your server you use the following call :
gcm.send(SENDER_ID + "#gcm.googleapis.com", id, data);
The GCM CCS server identifies your server by the SENDER_ID (since your server uses that SENDER_ID when establishing the XMPP connection with the GCM CCS server).