How to push notification to client when Firebase has a new entry?
You can make a very simple node.js server or a java servlet (based on your language preferences) then using firebase server sdk you can add childEventListener. When value changes you can use FCM to send push notifications using http protocol. I am using this in my app and it is very feasable and reliable.
Note: If you are using this flow for an android app then using java server sdk will be beneficial as it is almost similar to what you have on android.
EDIT: After getting some spotlight on this answer I thought to share some more info regarding same.
//example node.js server as seen on this official firebase blog
var firebase = require('firebase');
var request = require('request');
var API_KEY = "..."; // Your Firebase Cloud Server API key
firebase.initializeApp({
serviceAccount: ".json",
databaseURL: "https://.firebaseio.com/"
});
ref = firebase.database().ref();
function listenForNotificationRequests() {
var requests = ref.child('notificationRequests');
ref.on('child_added', function(requestSnapshot) {
var request = requestSnapshot.val();
sendNotificationToUser(
request.username,
request.message,
function() {
request.ref().remove();
}
);
}, function(error) {
console.error(error);
});
};
function sendNotificationToUser(username, message, onSuccess) {
request({
url: 'https://fcm.googleapis.com/fcm/send',
method: 'POST',
headers: {
'Content-Type' :' application/json',
'Authorization': 'key='+API_KEY
},
body: JSON.stringify({
notification: {
title: message
},
to : '/topics/user_'+username
})
}, function(error, response, body) {
if (error) { console.error(error); }
else if (response.statusCode >= 400) {
console.error('HTTP Error: '+response.statusCode+' - '+response.statusMessage);
}
else {
onSuccess();
}
});
}
// start listening
listenForNotificationRequests();
//example test java servlet which I made just to demonstrate this use case
@WebServlet("/TestServlet")
public class MainServlet extends HttpServlet {
* @see HttpServlet#HttpServlet()
*/
public MainServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Get context and then relative path to saved json config file from
// firebase
ServletContext context = getServletContext();
String fullPath = context.getRealPath(FILE_PATH_FOR_JSON_SERVER_AUTH);
// Check if we actually got a file from above path
if (fullPath != null) {
} else {
}
// Setup connection to firebase database here
FirebaseOptions options = new FirebaseOptions.Builder().setServiceAccount(new FileInputStream(fullPath))
.setDatabaseUrl(FIREBASE_DATABSE_URL).build();
// Check to make sure we don't initialize firebase app each time webpage
// is refreshed
if (!exists) {
// If firebase app doesn't exist then initialize it here and set
// exists to true
FirebaseApp.initializeApp(options);
exists = true;
}
// Call this to begin listening *notify* node in firebase database for notifications
addNotificationListener(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Build apache httpclient POST request
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(ENDPOINT_URL);
//Get the required id stored in lastMsgId tree map here
if (!(chatLogs.getLastMsgIdTreeMap().isEmpty())) {
sendToID = chatLogs.getLastMsgIdTreeMap().firstKey();
lstmsg = chatLogs.getLastMsgIdTreeMap().get(sendToID);
}
//Set up a unique id with concatenating sendToID and lstmsg
uniqueID = sendToID + lstmsg;
//Set up a previous id to check with unique id. To avoid instant duplicate notifications
previousID = fcmHelper.getPreviousid();
// Check uniqueId and PreviousID beforeSending
if (!(uniqueID.equals(previousID))) {
fcmHelper.setPreviousid(uniqueID);
//Check if device token and user Id hashmap is not null
if (!(userLogs.getUserIdAndFcmTokenHashMap().isEmpty())) {
//Get the device token of sendTo Id here
deviceToken = userLogs.getUserIdAndFcmTokenHashMap().get(sendToID);
// Create JSON object for downstream data/notification
JSONObject mainNotificationJsonObj = new JSONObject();
JSONObject outerBaseJsonObj = new JSONObject();
try {
// Notification payload has 'title' and 'body' key
mainNotificationJsonObj.put(TITLE, NEW_MESSAGE_RECEIVED);
mainNotificationJsonObj.put(BODY, lstmsg);
mainNotificationJsonObj.put(NOTIFICATION_SOUND, NOTIFICATION_SOUND_TYPE_DEFAULT);
//mainNotificationJsonObj.put(TAG, fcmHelper.getFcmTagId());
System.out.println("This is sentBy id =" + fcmHelper.getFcmTagId());
// This will be used in case of both 'notification' or 'data' payload
outerBaseJsonObj.put(TO, deviceToken);
// Set priority of notification. For instant chat setting
// high will
// wake device from idle state - HIGH BATTERY DRAIN
outerBaseJsonObj.put(PRIORITY_KEY, PRIORITY_HIGH);
// Specify required payload key here either 'data' or
// 'notification'. We can even use both payloads in single
// message
outerBaseJsonObj.put(NOTIFICATION, mainNotificationJsonObj);
} catch (JSONException e) {
e.printStackTrace();
}
// Setup http entity with json data and 'Content-Type' header
StringEntity requestEntity = new StringEntity(outerBaseJsonObj.toString(),
ContentType.APPLICATION_JSON);
// Setup required Authorization header
post.setHeader(AUTHORIZATION, FIREBASE_SERVER_KEY);
// Pass setup entity to post request here
post.setEntity(requestEntity);
// Execute apache http client post response
HttpResponse fcmResponse = client.execute(post);
// Get status code from FCM server to debug error and success
System.out.println(RESPONSE_CODE + fcmResponse.getStatusLine().getStatusCode());
// Get response entity from FCM server and read throw lines
BufferedReader rd = new BufferedReader(new InputStreamReader(fcmResponse.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
if (response != null) {
// Print out the response to webpage
PrintWriter out;
out = response.getWriter();
out.println(result);
System.out.println("This is Result - " + result);
}
} else {
//Abort this process if conditions not met
post.abort();
System.out.println(THIS_MSG_ALREADY_SENT);
}
}
}
/*
* This is the main method to be called to setup notifications listener on server startup
*/
private void addNotificationListener(HttpServletRequest request, HttpServletResponse response) {
//Initialize Value event listener
lastMsgListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot arg0) {
// Clear idLastMessagerecivedhash map if not null
if (lastMsgIdTreeMap != null) {
lastMsgIdTreeMap.clear();
}
//Get lastmsg to be sent as notification here
lstmsg = (String) arg0.child(LAST_MESSAGE).getValue();
//Get sendToID here
String sendToID = (String) arg0.child(SEND_TO).getValue();
//Get Sent by ID here
sentBy = (String) arg0.child(SENT_BY).getValue();
//Set fcmTag ID here
fcmHelper.setFcmTagId(sentBy);
//Check if lstmsg is not null
if (lstmsg != null) {
// Create lastmsgTimestampHashMap here
lastMsgIdTreeMap.put(sendToID, lstmsg);
}
//Check for null again
if (lastMsgIdTreeMap != null) {
chatLogs.setLastMsgIdTreeMap(lastMsgIdTreeMap);
}
try {
doPost(request, response);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onCancelled(DatabaseError arg0) {
}
};
//Set up database reference to notify node here
messageRef = FirebaseDatabase.getInstance().getReference().child(NOTIFY);
//Add value listener to database reference here
messageRef.addValueEventListener(lastMsgListener);
}
"Java servlet is just a personal test. Some parts have been edited or removed to only give an idea about it's setup this is in no way production ready servlet please don't just copy - paste. I encourage you to understand and build your own."