I need a little help understanding couple of things about gcm - server side.
I am working on instant messaging app with the example of server-side here http://developer.android.com/google/gcm/ccs.html
After I execute this code It connects but terminates after few seconds. I can guess that the reason it's because of the main() function.
public static void main(String[] args) throws Exception {
final long senderId = 1234567890L; // your GCM sender id
final String password = "Your API key";
SmackCcsClient ccsClient = new SmackCcsClient();
ccsClient.connect(senderId, password);
// Send a sample hello downstream message to a device.
String toRegId = "RegistrationIdOfTheTargetDevice";
String messageId = ccsClient.nextMessageId();
Map<String, String> payload = new HashMap<String, String>();
payload.put("Hello", "World");
payload.put("CCS", "Dummy Message");
payload.put("EmbeddedMessageId", messageId);
String collapseKey = "sample";
Long timeToLive = 10000L;
String message = createJsonMessage(toRegId, messageId, payload,
collapseKey, timeToLive, true);
ccsClient.sendDownstreamMessage(message);
}
Isn't supposed to be a 'while' statement which keeps the XMPP connection alive between the app-server to GCM server?
Isn't The purpose of the server-side in this case (instant messaging app) is to keep the connection alive with GCM server and to listen for incoming messages from clients.
messages like:
2.1 When client want to register to the app so I need to store it's details in a database.
2.2 When client want to send message to another client so the server-side app is in charge to forward the message to it's destination?
I have looked for couple of examples for implementing gcm server side using xmpp and all of them were with this kind of main function I mentioned above... Am I getting something wrong?
Yes, the XMPP connection must stay alive. Otherwise, your server won't be able to receive upstream (device to cloud) messages.
I can't say why all the examples you saw don't maintain an open connection. I guess they are simplified examples.
Related
There is a ton of documentation explaining how to send messages from the server to the Android device, but next to nothing available for how to send it from the Android device to the server.
We are working on making an app where the users can receive notifications from one another in certain circumstances. I am receiving messages just fine and my code works to parse them when received. Sending messages, on the other hand, is not working.
The code I am attempting to work with is:
public static void sendNotificationToUser(String userId, final String message){
FirebaseMessaging messaging = FirebaseMessaging.getInstance();
Bundle someBundle = new Bundle();
someBundle.putString("STRING_KEY_HERE", "STRING_VALUE_HERE");
//I have tried excluding the #gcm as well, no luck.
String str = "user_" + userId + "#gcm.googleapis.com";
RemoteMessage.Builder myBuilder = new RemoteMessage.Builder(str);
Map<String, String> aMap = new HashMap<>();
aMap.put("DATA_KEY_1", "DATA_VALUE_1");
myBuilder.setData(aMap);
myBuilder.addData("ADD_DATA1", "ADD_DATA11");
myBuilder.setMessageId("SOME_MESSAGE_ID123");
myBuilder.setTtl(0); //Send immediately
myBuilder.setMessageType("SOME_MESSAGE_TYPE");
myBuilder.setCollapseKey("SOME_COLLAPSE_KEY");
//Can't do this, private access, how do I instantiate this?
RemoteMessage.Notification notification = new RemoteMessage.Notification();
RemoteMessage remoteMessage = myBuilder.build();
messaging.send(remoteMessage);
}
The problem here is that once this fires off, nothing ever happens. Specifically, what I am trying to do is send a message as per subscribed topics. So, if I were subscribed to android_tag, I want to send this message to the android_tag, which is where the userId is set; I have that user subscribed to user_{theirtag}.
Does anyone have any clue how to go about sending an outbound FCM message to a specific topic? Also, how do I instantiate and include a RemoteMessage.Notification object since it cannot be done the way I have listed above?
Thanks all.
EDIT:
It looks like the answer as per Mr Frank van Puffelen is that no, it cannot be done via the SDK directly. It can be done via a combination of topic subscriptions and including a server to process the actual sends (here), but it should not be done without the use of a server in order to prevent secret/ server key exposure.
I used Paho MQTT client in Android to connect to IBM Bluemix quickstart IoT service. The connection part works well, but when I publish, the cloud application displays that I'm disconnected, but in the client I don't get exceptions.
I use this permission:
<uses-permission android:name="android.permission.INTERNET"/>
Connect:
String broker = "tcp://quickstart.messaging.internetofthings.ibmcloud.com:1883";
String clientId = "d:quickstart:iotqs-sensor:myDeviceID";
try {
client = new MqttClient(broker, clientId, null);
MqttConnectOptions connOpts = new MqttConnectOptions();
client.connect(connOpts);
} catch(MqttException me) {
Publish:
String topic = "iot-2/evt/iotsensor/fmt/jon";
String content = "{ \"d\" : { \"data\" : 5 } }";
try {
MqttMessage message = new MqttMessage(content.getBytes());
message.setQos(0);
client.publish(topic, message);
} catch(MqttException me) {
The strange thing is: this code worked yesterday.
What could be the problem?
The next step will be to connect and publish to my own Bluemix IoT service, but if I can't send messages to the demo, I can't hope for more.
UPDATE:
If I connect, and publish, the quickstart app shows that I'm disconnected, but the client still lets me publish for about 3 secs, after that I get an exception: 32104 (the client is not connected).
A Device must be registered before it can connect. Refer to quickstart documentation at https://docs.internetofthings.ibmcloud.com/messaging/devices.html#/ I don't see any devices registered under your org. Also, under the org it shows your email/ID as "expired". Please sign in at https://internetofthings.ibmcloud.com/#/ and add yourself as a permanent user under the access tab.
I have successfully registered my Android app with locally managed device groups as described here: Google Cloud Messaging (GCM) with local device groups on Android gives HTTP Error code 401.
This works fine, and I can send GCM messages from Android to Android by following the guidelines here: https://developers.google.com/cloud-messaging/downstream.
However, this uses the SERVER_API key, which supposedly isn't a nice thing to have lying around on a client.
My question is: Is it a problem at all to use the SERVER_API key on the client?
Second: Is it possible to send a GCM message without using the SERVER_API key?
I tried passing the notification_key received from the device group registration to this method, but nothing arrives:
private void sendMessage2(String recipient) throws IOException {
Log.i(TAG, "Sending message to " + recipient);
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
AtomicInteger msgId = new AtomicInteger();
String id = Integer.toString(msgId.incrementAndGet());
Bundle data = new Bundle();
data.putString("hello", "world");
gcm.send(recipient, id, data);
Log.i(TAG, "Successfully sent message to " + recipient);
}
// recipient is the notification_key of the device group.
Don't use the SERVER_API key on your client!
This key is a secret, and will not be obfuscated in your binary. Someone can easily download your APK, run strings (or a similar tool) and then start sending GCM messages on behalf of your application.
If you want to do Android <--> Android messaging, you will actually need to do Android <--> Server <--> Android.
I've an app that uses GCM push notifications. It works fine and my device registers and receives push messages.
If i uninstall the app from my device i no longer receive the messages as you would expect. The TextBox in which you send messages on the server is still there after i un-install the app, which i'd also expect.
I've looked at the documentation regarding unregistering and you can do it manually or automatically.
The end user uninstalls the application.
The 3rd-party server sends a message to GCM server.
The GCM server sends the message to the device.
The GCM client receives the message and queries Package Manager about whether there are broadcast receivers configured to receive it, which returns false.
The GCM client informs the GCM server that the application was uninstalled.
The GCM server marks the registration ID for deletion.
The 3rd-party server sends a message to GCM.
The GCM returns a NotRegistered error message to the 3rd-party server.
The 3rd-party deletes the registration ID.
I don't understand the next to last statement in the above list.
The GCM returns a NotRegistered error message to the 3rd-party server.
How is this acheived?
Also if the app is uninstalled from the device, how can it do the statement below? Is there an app lifecycle method that execute as an app is removed from a device? If there is, is this the place where code is placed that informs GCM server of the uninstall and the calls a php script on the 3rd party server that removes the regID from the DB?
The GCM client informs the GCM server that the application was uninstalled.
thanks in advance,
Matt
[edit1]
static void unregister(final Context context, final String regId) {
Log.i(TAG, "unregistering device (regId = " + regId + ")");
String serverUrl = SERVER_URL + "/unregister.php";
Map<String, String> params = new HashMap<String, String>();
params.put("regId", regId);
try {
post(serverUrl, params);
GCMRegistrar.setRegisteredOnServer(context, false);
String message = context.getString(R.string.server_unregistered);
CommonUtilities.displayMessage(context, message);
} catch (IOException e) {
// At this point the device is unregistered from GCM, but still
// registered in the server.
// We could try to unregister again, but it is not necessary:
// if the server tries to send a message to the device, it will get
// a "NotRegistered" error message and should unregister the device.
String message = context.getString(R.string.server_unregister_error,
e.getMessage());
CommonUtilities.displayMessage(context, message);
}
}
[EDIT2]
The unregister code below is for unregistering the device on the 3rd party server after deleting the app from the phone. The code is in addition to the tutorial below.
tutorial
send_messages.php
<?php
if (isset($_GET["regId"]) && isset($_GET["message"])) {
$regId = $_GET["regId"];
$message = $_GET["message"];
$strRegID = strval($regId);
include_once './GCM.php';
include_once './db_functions.php';
$gcm = new GCM();
$registatoin_ids = array($regId);
$message = array("price" => $message);
$result = $gcm->send_notification($registatoin_ids, $message);
$db = new db_Functions();
if (strcasecmp ( strval($result) , 'NotRegistered' )) {
$db->deleteUser($strRegID);
}
}
?>
db_functions.php
public function deleteUser($regid) {
$strRegID = strval($regid);
$serverName = "LOCALHOST\SQLEXPRESS";
$uid = "gcm";
$pwd = "gcm";
$databaseName = "gcm";
$connectionInfo = array( "UID"=>$uid, "PWD"=>$pwd, "Database"=>$databaseName);
$db = sqlsrv_connect($serverName,$connectionInfo) or die("Unable to connect to server");
$query = "DELETE FROM gcmUser2 WHERE gcuRegID = '$regid'";
$result = sqlsrv_query($db, $query);
}
When the GCM server attempts to send the message to the device after the app has been uninstalled, the GCM client detects that this app is not longer installed on the device. You don't do it in your application code. The GCM client component of the Android OS does it.
The next time to try to send a message to the app on the device that uninstalled it, the GCM server will already know it has been uninstalled, and send you the NotRegistered error.
There is no lifecycle method called when the app is removed from the device. If there was, you wouldn't need the sequence of events you quoted above in order for the GCM server and the 3rd party server to detect that the app was uninstalled (since you could have used such a method to both unregister your app from the GCM server and to let the 3rd party server know the app was uninstalled from that device).
I am playing around with the Google Cloud Messaging sample code given in Android SDK. Both the client and server code works fine. I have installed the GCM client android app in three android devices and when the server is running each of the devices gets registered successfully to the GCM Server. And whenever I try to send message the server broadcasts the messages to all the three devices. But my question is whether we can blacklist any of the device or allow the server to send message to any of the particular device.
Is there any method to restrict the device using the registrationID generated in the server for each devices?
Here is the server code for sending push notification
if (devices.size() == 1) {
String registrationId = devices.get(0);
if(!(registrationId .equalsIgnoreCase("APA91bE61KYmI4Qzn9NKkh6wkHr1ya8FIfGbc_gYJf0_33558IeFnj9j8j4EPRaJeSKJ_CK6_a9FQLt_CapLE4e_mvRaq3hytJalfjTBbkAxbLIdfdXyoxatSrDPmtxSdyaeiRV-Bav-4qOSlURH5mL69Fa9ktX8JFoow")))
{
Message message = new Message.Builder().build();
Result result = sender.send(message, registrationId, 5);
results = Arrays.asList(result);
}
} else {
// send a multicast message using JSON
Message message = new Message.Builder().build();
MulticastResult result = sender.send(message, devices, 5);
results = result.getResults();
}
There is no built-in method to restrict some devices in GCM-Server but you can create your own blackList and send message to the devices other than this list.
You can create your devicesList which does not include registrationIds in the blackList and send multicast message to this list.
Check javadoc for more information about the GCM server-side code here.