I followed this blog to implement local notifications for an app and the block of code from it is the following:
LocalNotification n = new LocalNotification();
n.setId("demo-notification");
n.setAlertBody("It's time to take a break and look at me");
n.setAlertTitle("Break Time!");
// n.setAlertSound("/notification_sound_beep-01a.mp3");
// alert sound file name must begin with notification_sound
Display.getInstance().scheduleLocalNotification(
n,
System.currentTimeMillis() + 10 * 1000, // fire date/time
LocalNotification.REPEAT_MINUTE // Whether to repeat and what frequency
);
It shows up just fine on iOS but not on my Android 13 device
Related
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.
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.
This may be off topic , but I couldn't found anything for it.
Is there any limit on the number of notifications android app can display?I am facing issue after 100 notifications. There is no documentation which states this clearly.
Note: This is not really a good idea to show 100 notifications but It is required for certain reasons.
According to #Nirel's answer.
1) I tried to run the code in 3 different devices.
Surprisingly notifications beyond 50 are not showing in notification area.
It gives following error.
W/NotificationManager﹕ notify: id corrupted: sent 51, got back 0
The same error comes for subsequent calls.
I saw the source of NotificationManager , it gives this error if incoming and out id is not same. See below code.
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/NotificationManager.java#L233
2) After I tried to notify on intervals of 100 milliseconds.
It also Gives the same error. What I tried is removed 1 notification when code is executed.
Surprisingly , notification number 153 came in status bar.
So the conclusion is that , at most 50 notifications can be there. This may be default behaviour and may can change by manufacturer as said by #Sharp Edge.
Thnx.
In API23
package com.android.server.notification;
NotificationManagerService.java
static final int MAX_PACKAGE_NOTIFICATIONS = 50;
The limit for notifications and toasts is per app 50
this post has really helped me to do research on this topic. I have written an article on this like how can you modify your logic and keep posting notifications even if you have reached the maximum limit by compromising on the oldest notifications. https://medium.com/mindorks/the-notification-limit-per-app-in-android-94af69a6862c
The notification limit dropped from 50 to 24 per appin the Android 10 notification drawer.
Read more about it here.
run this:
// prepare intent which is triggered if the
// notification is selected
Intent intent = new Intent(this, NotificationReceiver.class);
// use System.currentTimeMillis() to have a unique ID for the pending intent
PendingIntent pIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), intent, 0);
// build notification
// the addAction re-use the same intent to keep the example short
Notification n = new Notification.Builder(this)
.setContentTitle("New mail from " + "test#gmail.com")
.setContentText("Subject")
.setSmallIcon(R.drawable.icon)
.setContentIntent(pIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
for(int i = 0;i<1000;i++)
{
Log.d("Tag", "notification number" + i "just published")
notificationManager.notify(i, n);
}
when the application will crash you will see how much notification you have..
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.
I have a problem with appcelerator, regarding to android background service.
The service starts, and when I press the home button, the service is still running, and also when I click the back button.
But when I remove my app from the recent apps list(pressing long home button) , the service stops.
This is my code for the call service:
var SECONDS = 6;
// every 10 minutes
var intent = Titanium.Android.createServiceIntent({
url : 'myservice.js'
});
intent.putExtra('interval', SECONDS * 1000);
intent.putExtra('message_to_echo', num);
//in millimeter
var service = Titanium.Android.createService(intent);
service.addEventListener('resume', function(e) {
// num++;
// alert(num);
});
service.start();
And this is the file service code:
var service = Titanium.Android.currentService;
var intent = service.intent;
var message = intent.getStringExtra("message_to_echo");
var intent = Ti.Android.createIntent({
flags : Ti.Android.FLAG_ACTIVITY_CLEAR_TOP | Ti.Android.FLAG_ACTIVITY_SINGLE_TOP,
// Substitute the correct classname for your application
className : 'com.mappa.angeli.MappaActivity',
});
intent.addCategory(Ti.Android.CATEGORY_LAUNCHER);
// Create a PendingIntent to tie together the Activity and Intent
var pending = Titanium.Android.createPendingIntent({
intent: intent,
flags: Titanium.Android.FLAG_UPDATE_CURRENT
});
// Create the notification
var notification = Titanium.Android.createNotification({
// icon is passed as an Android resource ID -- see Ti.App.Android.R.
// icon: Ti.App.Android.R.drawable.my_icon,
contentTitle: 'Something Happened',
contentText : 'Click to return to the application.',
// tickerText: 'Our app made a notification!',
defaults:Titanium.Android.NotificationManager.DEFAULT_SOUND,
contentIntent: pending
});
// Send the notification.
Titanium.Android.NotificationManager.notify(0, notification);
How can I run the service continously, such as whats app or something like that?
Please help me, it's very important.
Thanks in advance!!!
First let me give you a little perspective about your questions so that you'll be able to understand the logic behind.
My Understanding about your Question and Conclusion
What you are asking for is not possible even in the native app, specifically if you are using the background services.
Why it is doing so?
Because the application is no longer in service anymore. The app is
forcefully removed from the background and hence the OS stops all its
services running in the background to clear the Memory.
What most of the default players do to play music is the use the foreground service and show a notification that the app is running and is processing something in the background (in this case playing the songs).
Options that you could look for
I would suggest you to add up 'push notification service' to your app rather than going in for 'background service'. You will get the notification even if your app is not in the background (same as it is in WhatsApp).
You could follow the below link to implement the GCM push services for android:
http://www.tidev.io/2013/12/20/using-gcm-for-android-push-notifications-with-acs/
Hope this helps.
Good Luck, Cheers