Send push notification after X minutes using Firebase Functions - android

I have a mobile app for iOS & Android, and I'm trying to implement a feature that sends a push-notification X minutes after a user exists the app.
In my database, I can already tell when a user is no longer active.
I thought about using App Engine & Firebase Functions & FCM
https://firebase.googleblog.com/2017/03/how-to-schedule-cron-jobs-with-cloud.html
But it seems that cron.yaml is static (sends notifications on a regular time basis),
And I'm looking for a dynamic approach where I can dynamically decide the time to send the push notification.
For instance - based on some database data,
1 user will get the notification after 30 minutes of inactivity,
while other user will get it after 15 minutes.
How can I achieve that specific behavior?
Thanks.

Here is what I have done to solve the notification scheduling problem. I have allowed 5 min tolerance (i.e. If you want to send notification on 10:03 then it will be sent on 10:05).
Say you have a function, sendNotificationFunction(userId, notificationMessage) , ready which takes userId & notificationMessage as arguments and sends notification to that particular user.
In firebase realtime database, I have made a node which has information regarding the notification schedule:
scheduleNotification: {
<pushId>: {
"userId":<userId>,
"scheduledTimestamp":<1530000000000>,
"notificationMessage":<Message that you want to send>
}
}
Make function which will be triggered every5Mins and check which notifications to schedule.
exports.every5MinTrigger = functions.https.onRequest((req,res)=>{
let currentTime = new Date().getTime(); //Say 10:00
let startTime = currentTime; //10:00
let endTime = currentTime + 5*60*1000; //10:05
firebase.database.ref().child("scheduleNotification").orderByChild("scheduledTimestamp").once('value').then((snap)=>{
if(snap.exists()){
snap.forEach(childSnap=>{
let userId = childSnap.child('userId').val()
let notificationMessage = childSnap.child('notificationMessage').val()
//Now you have userId and your notification's language. Call your sendNotificationFunction() Here
})
}
})
})
Deploy this function in your firebase cloud functions. And you will get the url of this function let's say it is something like this: https://us-central1-<your-project>.cloudfunctions.net/every5MinTrigger .
Call this ,https://us-central1-<your-project>.cloudfunctions.net/every5MinTrigger, url from your cron job every 5 mins so it will schedule the notifications for next 5 mins.
Hope it helps.

Related

Retrieve message from a notification push

This push notification is used to notify when a new chat message is available. I want to do like Instagram, that is to say, the message into this notification is updated at each new income message received, until the user open the chat.
So, how can I retrieve the message for this specific notification? Is it possible, or I have to save (in cache) the latest messages... ?
Thank you very much
I suggest saving messages in the database, and then in the function that sends notifications, get messages (probably recent unread ones - I don't know what your logic looks like in this case).
If there are more than one, use InboxStyle():
val otherMessagesToShow = getMostRecentUnreadMessages()
if(otherMessagesToShow.size > 1) {
val style = NotificationCompat.InboxStyle()
otherMessagesToShow.forEach { style.addLine(it) }
builder.setStyle(style)
builder.setNumber(otherMessagesToShow.size)
}
Finally, update the existing one (passing the same notificationID):
notificationManager.notify(notificationId, builder.build())

Creating a local notification in response to a push notification (from firebase) in cordova/ionic

I'm building an application using Ionic Framework that implements a chat function similar to good-old facebook messenger, in that i want to notify users of a chat message, but if they view it elsewhere, i want to remove the notification from their home screen.
I'm using firebase as a back-end for push notifications (though that could be changed i suppose).
I know that you can't expire a remote notification, but i've been told you can expire + remove a local notification, so my question is - can i reliably receive a remote notification, create a local one, and display that, and then in response to a notification with a scope of 'expire' or 'remove', delete a local notification so that my users don't see a duplication of information?
Most plugins tend to detect the status of the app and add a remote notification to the homescreen with the info you've pushed by default, is there a way to avoid this?
Thanks guys.
EDIT:
- Local notifications: http://ionicframework.com/docs/native/local-notifications/
- Firebase cloud messaging: https://github.com/fechanique/cordova-plugin-fcm
As far as I can tell there're no plugins which accomplish all what you need. However..
can i reliably receive a remote notification, create a local one, and display that, and then in response to a notification with a scope of 'expire' or 'remove', delete a local notification so that my users don't see a duplication of information?
Most plugins tend to detect the status of the app and add a remote notification to the homescreen with the info you've pushed by default, is there a way to avoid this?
Yes, by using silent notifications and building the local notification by yourself.
For a project I'm working in, I modified the plugin cordova-plugin-fcm to add support for (local on demand) notifications dismiss/display, send multiple notifications to the cordova app, and some PRs that are not included yet. Also I build the notification by myself, to have full control of what is displayed. You can take a look at the code to get some ideas.
In brief it works like this:
Firstly, I send a "silent" push to the app, which is not displayed by Android:
{
"content_available": true, // IMPORTANT: For Apple -> content-available: 1, for firebase -> content_available: true
"priority": "high",
"to": "/topics/all", // or to a fcm token
"data"{
"title": "My title", // this implies that you display the notification by yourself
"body": "My body", // this implies that you display the notification by yourself
"type": "NEW_USER_MESSAGE", // only relevant to this project
"userId": "1", // only relevant to this project
"timestamp", "150000000"
}
}
Note: If the payload have the "notification": {} item, Android will display it on the system tray (if the app is in background).
https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages
Secondly, when the push arrives to the app (in onMessageReceived()), I build the local notification, assigning it a TAG and an ID. This is the way you can use to dismiss it later.
For example, you could create a local notification with the TAG "NEW_USER_MESSAGE" and ID 1 (a constant indicating a state of the message, or the user ID for example). Also, Android will replace notifications with the same TAG and ID, so this is another way to automatically replace notifications (for example if you send a generic message, like "New update available").
public static String TYPE_NEW_USER_MESSAGE = "NEW_USER_MESSAGE";
public static String TYPE_USER_LEFT_ROOM = "USER_LEFT_ROOM";
NotificationManager notificationManager =
(NotificationManager) _ctx.getSystemService(Context.NOTIFICATION_SERVICE);
// based in the type of the message you've received, you can stylize the notification
if (type.equals( TYPE_USER_LEFT_ROOM )){
notificationBuilder.setColor(Color.RED);
notificationBuilder.setLights(Color.RED, 1000, 500);
}
else if (type.equals( TYPE_NEW_USER_MESSAGE )){
notificationBuilder.setColor(Color.BLUE);
notificationBuilder.setLights(Color.BLUE, 1000, 1000);
}
Notification n = notificationBuilder.build();
notificationManager.notify(type, userId, n);
One advantage of doing it in this way, is that you have full control of the notification to be displayed, so you can stylize it like you want.
If you want to discard expired messages, you can check out the elapsed time between the sent timestamp and the current timestamp:
java.util.Date now = new java.util.Date();
java.util.Date sent_timestamp = new java.util.Date( Long.valueOf(timestamp.toString()) );
final Long elapsed_time = ((now.getTime() - sent_timestamp.getTime()) / 1000);
Log.d(TAG, "New message. sent " + elapsed_time + "s ago");
Thirdly, when the user clicks on a notification Android will launch your app, and the plugin will send the payload of the push message to the cordova view (onNotificationReceived()).
Once your app is opened and you have received the push message, you can dismiss it adding a new action to the plugin:
onNotificationReceived(data){
if (data.wasTapped === true){
if (data.type === 'NEW_USER_MESSAGE'){
FCMPlugin.dismissNotification(NEW_USER_MESSAGE, 1);
}
}
}
The Android action:
else if (action.equals( ACTION_DISMISS_NOTIFICATION )) {
cordova.getThreadPool().execute(new Runnable() {
public void run() {
try{
Log.d(TAG, "FCMPlugin dismissNotificaton: " + args.getString(0)); //tag
NotificationManager nManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
nManager.cancel(args.getString(0)/*NEW_USER_MESSAGE*/, args.getInt(1) /*1*/);
Log.d(TAG, "FCMPlugin dismissNotificaton() to remove: " + id); //tag
callbackContext.success();
}catch(Exception e){
callbackContext.error(e.getMessage());
}
}
});
https://github.com/TrustedCircles/cordova-plugin-fcm/blob/master/src/android/FCMPlugin.java#L286
And the method exposed to the cordova app:
// dismisses a notification by tag+id
FCMPlugin.prototype.dismissNotification = function( tag, userId, success, error ){
exec(success, error, "FCMPlugin", 'dismissNotification', [tag, userId]);
}
https://github.com/TrustedCircles/cordova-plugin-fcm/blob/master/www/FCMPlugin.js#L65
The only tricky bit with notifications in cordova/ionic is the JS part receiving the notification and triggering the Android code.
I used https://github.com/phonegap/phonegap-plugin-push library and its pretty straight forward.
There is a callback when notifications are received in JS(Cordova/Ionic), use this to render you notifications locally in Android.
P.S: Basel's answer tells you how to clear your notifications, so I decided to leave that bit out.

Unable to handle event in background push notification

I am using cordova plugin add phonegap-plugin-push plugin for push notification
In forground notification works fine.and i can handle event also.
When my app is in background then i got notification as well but on click of push notification my event is not fire.
I am using below code
$cordovaPushV5.initialize(options).then(function() {
// start listening for new notifications
$cordovaPushV5.onNotification();
// start listening for errors
$cordovaPushV5.onError();
// register to get registrationId
if (PNdeviceToken == null) //becuase registration will be done only the very first
{
$cordovaPushV5.register().then(function(registrationId) {
// save `registrationId` somewhere;
window.localStorage.setItem('PNdeviceToken', registrationId);
$rootScope.fcmToken = registrationId;
console.log(registrationId)
alert("first time registered id -- " + registrationId)
})
} else {
$rootScope.fcmToken = PNdeviceToken;
alert("already saved registered id -- " + $rootScope.fcmToken)
}
});
$rootScope.$on('$cordovaPushV5:notificationReceived', function(event, data) {
console.log(event)
console.log(data)
})
When i tap on background push notiction then $cordovaPushV5:notificationReceived event not fire, How can I solve this problem?
How can i handle background push notification event?
I had the Same issue and got it resolved it after 2 days of research.
Handling the notification events is same whether the app is in foreground or background.
We have to set "content-available" : "1" in the data field while pushing notifications. Else it wont call notificationReceived event if app is in background.
Also note this is not possible as of now through Google Firebase Console.
We have to send our custom payload messages (data or notification or both) seperately using any one of the firebase servers.
Detailed info can be found on the plugin's GitHub Docs Page on background notifications.
Quoting from there -
On Android if you want your on('notification') event handler* to be called when your app is in the background it is relatively simple.
First the JSON you send from GCM will need to include "content-available": "1". This will tell the push plugin to call your on('notification') event handler* no matter what other data is in the push notification.
*on('notification') event handler = $cordovaPushV5:notificationReceived event in your case.
See this answer for sending custom payload messages using PHP and NodeJS

How to intercept Stacked notifications in Android

I am well familiar with the concept of stacked notification .
The mobile doesn't show non-summary notifications if there is a corresponding summary notification. But if there is no summary notification, non-summary notifications are displayed
I am listening to every notification posted by NotificationListenerService introduced in Kitkat. I intercept and display every notification text as they arrive.
Problem is when stacked notifications arrive, I get callbacks for both groupSummary and non-summary notifications. If I have to decide if a non-summary should be displayed, I have to check every other notification for a summary.
How do I replicate the behaviour of mobile without going through the list of all present notifications repeatedly, that is, in less than O(n^2) complexity? Or does Android source code also do it the same complex way?
I devised a method myself with complexity < O(n^2). Guess I didn't think about using better data structures. Here's the function . Feel free to point out mistakes if any.
private ArrayList<StatusBarNotification> cleanseNonSummary(ArrayList<StatusBarNotification> notifications) throws Exception{
Set<String> groupSet = new HashSet<>();
//first run : add all summary notification keys to unique set
for(StatusBarNotification sbn : notifications){
if(NotificationCompat.isGroupSummary(sbn.getNotification()))
groupSet.add(NotificationCompat.getGroup(sbn.getNotification()));
}
//second run : remove all non summary notifications whose key matches with set elements
for(int i=0; i<notifications.size(); i++) {
StatusBarNotification sbn = notifications.get(i);
if (!NotificationCompat.isGroupSummary(sbn.getNotification())) {
String groupId = NotificationCompat.getGroup(sbn.getNotification());
if (groupId != null && groupSet.contains(groupId))
notifications.remove(i--);
//decrement counter if an element is removed
}
}
return notifications;
}

Phonegap LocalNotification Plugin 0.7.4 notifications keep appearing every time app launches

What I want to achieve
I want to be able to send a notification to the device, daily, by a specific time. Example: user should be notified at 3pm their local time every day.
What I have done so far
receivedEvent: function(id) {
var notify = new Date();
notify.setHours(15,00,00,00);
window.plugin.notification.local.add({
id : 1,
message : "please read your first verse of the day",
title: "Verse 1",
repeat: "daily",
date: notify,
autoCancel: true
});
};
What the problem is:
The notification shows up at 3pm and every time I launch the app after that, the notification appears on launch. Furthermore, notification doesn't repeat daily.
Fixed it. No longer an issue. I just placed the code inside an if statement that allows the code inside it to be executed only the first time application loads.

Categories

Resources