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.
Related
I am trying to create an Android chat client using ejabberd XMPP server (19.02), Smack library (4.2.4) and Android SDK 25 using Android Studio.
I followed the example app found here: https://www.blikoontech.com/tutorials/android-smack-xmpp-introductionbuilding-a-simple-client
All is working well and I can send messages between two different Android devices running that sample app.
In ejabberd, there are options to send messages to the clients directly from the server using a CLI tool called ejabberdctl or ejabberd REST API. When I sent messages that way, the Android client doesn’t receive those messages. I tried with other clients like Conversations and Gajim and they could all receive it. I am pretty sure messages sent using those methods arrived because they were received as offline messages (on ejabberd web admin) when sent to offline clients.
Here is the part of the Android (java) code (roosterconnection.java from that sample app) that is to receive incoming messages. Please suggest me if I am missing anything. Thanks a lot.
ChatManager.getInstanceFor(mConnection).addIncomingListener(new IncomingChatMessageListener() {
#Override
public void newIncomingMessage(EntityBareJid messageFrom, Message message, Chat chat) {
///ADDED
Log.d(TAG,"message.getBody() :"+message.getBody());
Log.d(TAG,"message.getFrom() :"+message.getFrom());
String from = message.getFrom().toString();
String contactJid="";
if ( from.contains("/"))
{
contactJid = from.split("/")[0];
Log.d(TAG,"The real jid is :" +contactJid);
Log.d(TAG,"The message is from :" +from);
}else
{
contactJid=from;
}
//Bundle up the intent and send the broadcast.
Intent intent = new Intent(RoosterConnectionService.NEW_MESSAGE);
intent.setPackage(mApplicationContext.getPackageName());
intent.putExtra(RoosterConnectionService.BUNDLE_FROM_JID,contactJid);
intent.putExtra(RoosterConnectionService.BUNDLE_MESSAGE_BODY,message.getBody());
mApplicationContext.sendBroadcast(intent);
Log.d(TAG,"Received message from :"+contactJid+" broadcast sent.");
///ADDED
}
});
Here is a possible explanation, based in my experiments with a desktop client, Tkabber:
I login to ejabberd using Tkabber client, account user1#localhost, resource tka1, priority -3. The negative priority in this experiment is important.
Then I execute the command to send to full JID, including the correct resource:
ejabberdctl send_stanza aaa#localhost user1#localhost/tka1
"<message>..."
The client receives the stanza correctly.
Now I send to bare JID (without providing resource), and another setting another resource:
ejabberdctl send_stanza aaa#localhost user1#localhost
"<message>..."
ejabberdctl send_stanza aaa#localhost user1#localhost/sdsd
"<message>..."
In those cases, none of them are received by the client, because the resource doesn't match, and because its priority is negative. I can see those messages stored offline in the database.
In your client, maybe you have to add another call to set the presence online, with a positive priority.
In Android L Preview doc,
https://developer.android.com/preview/notifications.html
there is a mention of "Cloud-synced notifications - act on a notification on your Android tablet and it is also dismissed on your phone." but no detailed information on it.
Any idea where can I find more information about this and how to implement this new feature in my app ?
This can be achieved with User Notifications, which is a feature of Google Cloud Messaging.
The idea is that your server registers a group of devices (identified by their GCM registration ID) that belong to the same user and gets a single notification ID for that user. Then you can send a GCM message to all the devices of that user using that single notification ID. This message can be sent either from your server to all devices of the user or from one device to the other devices of that user.
When one device handles the notification, you can send a GCM message to all the other devices belonging to the same user, to let them know the notification was viewed on one device, and the other devices would receive that message and dismiss the notification.
To send an upstream (device-to-cloud) message, you must use the GoogleCloudMessaging API. Specifying a notification_key as the target for an upstream message allows a user on one device to send a message to other devices in the notification group—for example, to dismiss a notification. Here is an example that shows targeting a notification_key:
GoogleCloudMessaging gcm = GoogleCloudMessaging.get(context);
String to = 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);
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 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.
I use the example provided by goole and I built an client side application to get notifications and a server side, both applications (code) is those provided by google.
I run the application on the client side and I get the registration_id. some huge string, in this format which is below:
APA91bEgguwt98xLbivrXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLxDalNoEktCSVbOkT0-uFH2FaRnfpkRME2tzuvr0BycMNEhX_Ix1PV_XXXXXXXXXXXXXXXXXXXXXN5hcseY_wA.
This proves me that the client application works. Now the server (java, google example):
public static void main(String[] args) {
Sender sender = new Sender("AIzaSXXXXXXXXXX_XXXXXXXXXXXXXXXrQOnoGZw");
Message message = new Message.Builder()
.collapseKey("1")
.timeToLive(3)
.delayWhileIdle(true)
.addData("message",
"this text will be seen in notification bar!!")
.build();
try {
Result result = sender.send(message, "APA91bEgguwt98xLbivrXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLxDalNoEktCSVbOkT0-uFH2FaRnfpkRME2tzuvr0BycMNEhX_Ix1PV_XXXXXXXXXXXXXXXXXXXXXN5hcseY_wA", 3);
System.out.println(result.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
This is the server. When I run the server I got as result something like this:
[ messageId=0:1341907115903155%921c249a00000031 ]
but no message on the client and I don't understand why. What is the meaning of the response I got from server? Is it the success response?
I need help to understand what is wrong?
Please review their comment
http://developer.android.com/guide/google/gcm/gcm.html
Note: If your organization has a firewall that restricts the traffic to or from the Internet, you'll need to configure it to allow connectivity with GCM. The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs. It changes IPs frequently.
According to the GCM Documentation:
When a 3rd-party server posts a message to GCM and receives a message ID back, it does not mean that the message was already delivered to the device. Rather, it means that it was accepted for delivery. What happens to the message after it is accepted depends on many factors.
In the best-case scenario, if the device is connected to GCM, the screen is on, and there are no throttling restrictions (see Throttling), the message will be delivered right away.
Remove your internet firewall if you are using it and try again
Please go through this
If your facing delay notification or message problem in GCM then try this solution.
I know this is not proper solution but it's WORKS Install this app it's really work for me HERE