I'm working on an IM application on Android platform using asmack lib and openfire as xmpp server. Since user can't persist in chat room when disconnected from server, I decided to implement PubSubManager concept. And I gone through lot of links but couldn't get any good explanation for publishing with Payload and retrieving the message from the payload. Here is my code for creating and subscribing myself to that node and publishing a payload....
ConfigureForm form = new ConfigureForm(FormType.submit);
form.setAccessModel(AccessModel.open);
form.setDeliverPayloads(true);
form.setNotifyRetract(true);
form.setNotifyDelete(true);
form.setPublishModel(PublishModel.open);
leafNode = pubSubManager.createNode("testnode");
leafNode.sendConfigurationForm(form);
leafNode.subscribe(MY_JID);
SimplePayload payload = new SimplePayload(
"elementname",
"pubsub:testnode:elementname",
"<elementname>my content</elementname>");
PayloadItem<SimplePayload> item = new PayloadItem<SimplePayload>(
null, payload);
leafNode.publish(item);
I've no problem while publishing this item.When publishing this, my chat listener gets triggered (since I subscribed myself in that node) with a Message Object, from which I couldn't get message body (null). So whether my publishing process is correct , if so how can I retrieve it when receiving.?
You don't want to receive messages via the Chat, after all, it isn't actually a chat message.
See the pubsub documentation, specifically the section Receiving pubsub messages
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.
I have made movie review app on android.Users create an account with firebase authentication and review movies and rate them.Admin of app can add new movies.
My question is how can I(admin) send a notification to all users (of firebase) whenever I added a new movie?And I want to use one signal push notification.
Please Help me.
Using Tags its possible to send the notification to all users.
1.Primarily you have create a channel eg: allusers from mobile end need to register
JSONObject tags = new JSONObject();
tags.put("allusers", "1");
OneSignal.sendTags(tags);
2.From server end who are all registered in the tag allusers=1 ..Notification will send to all the users
Sending Push from serverside
https://documentation.onesignal.com/reference#create-notification
I'm developing a chat application using Firebase Database in Android.
I've already done the core (chat and user's list activities), but I have yet to do the notification system.
What I want is that when a user is added to a conversation (single or group) and another user writes a new message to the conversation, the first user has to receive a notification that if clicked opens the conversation activity.
My big dilemma is how to structure the service that runs in background to receive the push notification or to listen to the firebase database node I need to look at to know if there are any messages.
I figured out two different approaches:
Approach 1) Use the firebase notification
With this approach I simply send a data notification from the sender client to all the other clients in the conversation when the sender sends a message, and so the receiver will decide to show the notification (if the chat activity it's not opened) and handle the click action.
With this approach I think I will save CPU consumption and then battery.
What I don't understand is how to register a user to receive a group notification (topic notification) because as I understood, I have to subscribe that client to the topic, but if the application is in background or close, how does it knows that a new group, with its user inside, has been created and so it has to subscribe to the topic?
For the two-users conversation scenario this is not a problem as I can send the notification directly to the destination user without needing him to be subscribed to any topic.
Approach 2) Listen to a firebase database data node with a background service
With this approach I just need to create a bootable service that listen to a specific node of the database (with ValueEventListener) and show a notification when data shows that a new message/conversation is coming.
An example of the node to listen to, can be the data about the unseen messages as following:
conversation_user_unseen_messages
$conversationId1
$user1: 3
$conversationId2
$user2: 1
Then, if the data shows new messages/conversations the android app client will decide to show a system notification.
I think that with this approach there will be more energy consumption as it has to constantly check if there are any new message on the db.
Final consideration
I have found a very useful guide written by the mythical Frank van Puffelen,that explains how to set up the system I need, with using an additional server side component (node.js server).
My last question is: do I need to set up a server? Is a better solution than handling everything by the clients (using for example http requests)?
What solution do you think is the best?
Many thanks.
EDIT
I'm still figuring it out, but here it is some consideration.
I have to requesting and using a InstanceID
Instance ID provides a unique ID per instance of your apps.
So i have to request an InstanceID when user is connected and the InstanceId it is avalaible.
And then don't use topics.
Topic messages are optimized for throughput rather than latency. For
fast, secure delivery to single devices or small groups of devices,
target messages to tokens, not topics.
as said in the topic messagin guide that instead suggests to target message to tokens .
To do so I have to collect the user token in my user database reference:
users: {
$userId1: {
name: "John",
email: "john#gmail.com",
token: "Ax8HiP3Edf7....",
}
}
and then when my app client send a new message it has to also has to send a notification for all users involved in the chat, thing that I already can do with my current db structure.
How do I handle and collect the requests?
I implement a node.js server app that connect to Firebase Database and listens for the notification requests made by the app and then sends the notification request by http call to every destination app.
When do I have to register the user token?
When a app client starts for the first time or when the InstanceID expire (onTokenRefresh).
Is this the right way to do it?
EDIT 2
I found a big hole in the FCM implementation. It seems that I can not handle at all notifications delivered to iOs apps that are not in foreground.
As found in the Data notification documentation
On iOS, FCM stores the message and delivers it only when the app is in the foreground and has established a FCM connection. On Android, a client app receives a data message in onMessageReceived() and can handle the key-value pairs accordingly.
And I need to catch the data notification even when the app is in background, I need that specifically because I want to update my badge counter on the app icon to let the user know how many unread messages he has.
I'm now tryng the OneSignal solution can receive notification even when in background, it's free and interfaces with GCM. I'm sad to not stay with Google but if I can't update the badge count using FCM I have to look to an other side.
Any consideration will be appreciated.
Approach 1 is the one that you should use. Frank's guide is using the first approach, so you need to set up a server.
Is it a better solution than handling everything by the clients (using for example http requests)?
Yes. If you send the notification in the client (the app), your API Key will be exposed (via network sniffing or reverse engineering) and you definitely would want to avoid that.
how to subscribe a user to a new group topic if the app is closed or in the background?
Looks like you have to create relation mapping on the server, by calling https://iid.googleapis.com/iid/v1/IID_TOKEN/rel/topics/TOPIC_NAME with Authorization: key=YOUR_API_KEY as the header, the full description is here. Follow this guide to get the Instance ID token.
I hope my answer answers your questions. Cheers :)
Now you can simply achieve this using firebase functions ...
Here's mine
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendFollowerNotification =
functions.database.ref('/whatever/{groupUID}/{userUID}/{todoUID}')
.onWrite(async (change, context) => {
const useruuid = context.params.userUID;
const thisdata = change.after.val();
console.log('sendto:'+useruuid);
var ref = admin.database().ref(`userdatas/${useruuid}/phonetkn`);
return ref.once("value", function(snapshot){
const payload = {
notification: {
image: "default",
sound:"default",
vibrate:"true" ,
title: 'New Mission !',
body: thisdata.titre ,
color: '#22c064',
icon: "notification_icon"
}
};
admin.messaging().sendToDevice(snapshot.val(), payload)
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
});
//
I have a Json URL, which contains data about Latest Job Postings, I am successfully parsing the Json URL and able to display the top job postings in my ListView.
But my requirement is to create a push notification, so that whenever a new job is posted, the user should be able to get a notification on device.
I have followed this: http://www.vogella.com/articles/AndroidNotifications/article.html
But I don't know how to get notifications in my case.
Could anyone help me?
Issue:
Give push notification to user's device about the updated data even when application is in background mode.
Solution:
Upon successful insertion of new data in your database (which is going to give updated set of data to your JSON request) , just call the file which send GCM push notification to all your users.
Reference:
GCM docs
GCM push-notification using php server
In context of implementation presented in demo app of 2nd link,
upon successful insertion,you can call send_message.php file,but make sure that $regId and $message should be retrieved from your database
You have created ActionBar Notifications for your app, but now you need to create the ability to receive notifications from a web client, instead of going to find them yourself from the URL.
To create a push notification you would need to have a constant thread (BroadcastReceiver) on the device that is waiting for the notification from the sever.
Google 'Cloud to Device Messaging' is the simplest way to do this.
This is a good link with lots of info on how to do this :
http://blog.mediarain.com/2011/03/simple-google-android-c2dm-tutorial-push-notifications-for-android/
If you require these notifications to be displayed on the device even when the application is not running (which seems to be the case from what you describe), you can use Google Cloud Messaging.
You would need a server that would poll the Json URL for updates, and send a GCM message to all the devices where your app is installed once such an update is detected.
Your app would have to register to Google Cloud Messaging and send the Registration ID received from Google to your server.
When your app receive a GCM message, you would create a notification and when the notification is tapped, you would start the activity that loads the data from the JSON URL.
I am trying GCM based android app to push messages from server to android client. I am able to push fix string with the following coe. I am wondering about the ways to push XML file from server and parse at the android application. I have done some research but I couldn't find push XML rather I found send XML file. Thank you
if (androidArray.size() == 1) {
String registrationId = androidArray.get(0);
Message message = new Message.Builder()
.collapseKey(collapseKey)
.timeToLive(30)
.delayWhileIdle(true)
.addData("message", Message)
.build();
Result result = sender.send(message, registrationId, 5);
You don't push xml (or JSON preferably) to the android app. You send a simple message to the app.
when the app receives the message it then needs to go and pull the xml/json from the website with an http get request to the relevant url that will supply the xml.
The android app can then parse the response and do whatever you want it to.
Here is an EXCELLENT tutorial on C2DM (The forerunner to GCM) http://www.vogella.com/articles/AndroidCloudToDeviceMessaging/article.html
You should be able to work out the differences needed.
UPDATE
Google Android has a complete section on GCM which can be found here
http://developer.android.com/google/gcm/index.html
Within that link there are getting started guides and a GCM Demo app
There are limits to the amount of data you can send and you should not rely on your data not ever exceeding the limits or Google arbitrarily changing the amount of data you are allowed to send.
Should either of those occur you would need to update your app so just do it right in the first place.
The message you send should act as a "key" to determine what action to take when the message is received.
UPDATE
If you are feeling REALLY adventurous you could use a custom sync adapter to help you consume your web services. It's pretty advanced stuff but if you are feeling curious about this then watch the Google I/O seminar on consuming RESTfull web services http://www.youtube.com/watch?v=xHXn3Kg2IQE