There is a scheduled notification which is supposed to show after 5 seconds. This scheduled notification is being called inside the void initState function. I'm using this package to show notifications.
The notification is being shown exactly after 5 seconds, so there is no problem there.
The problem is that there is another function that is supposed to be called when the notification is clicked. But this function is being called long before the notification even appears and I don't know how is this happening. I have tried different approaches to solve this problem but non works.
Be low is the code where all this is happening.
class _HomePageState extends State<HomePage> {
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
#override
void initState() {
super.initState();
flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
var android = new AndroidInitializationSettings('#mipmap/ic_launcher');
var initNotifSettings = new InitializationSettings(android, null);
flutterLocalNotificationsPlugin.initialize(initNotifSettings,
onSelectNotification: whenNotificationSelect);
showNotification();
}
Future whenNotificationSelect(String payload) async {
print('Payload: $payload');
Navigator.pushNamed(context, '/notifications');
}
showNotification() async {
var android = new AndroidNotificationDetails(
'channel id', 'channel name', 'channel description');
var platform = new NotificationDetails(android, null);
var scheduledNotificationDateTime =
DateTime.now().add(Duration(seconds: 2));
await flutterLocalNotificationsPlugin.schedule(
0,
'Good morning!',
'Greetings from me.',
scheduledNotificationDateTime,
platform,
payload: 'Simple App',
);
}
}
Note The function whenNotificationSelect it needs to be called when notification is being clicked, but for other reasons that I don't know this function is being called immediately when the app starts. I want whenNotificationSelect to be called only when the notification is clicked not when the app starts.
Thank you, so much Love.
Try this
onSelectNotification:(String payload) => whenNotificationSelect(String payload)
When you are not using (String payload) it means, the function will be triggered on null too. Whenever you have to pass arguments, use (arguments)=> functionName(arguments)
Related
Im struggling with this topic a few weeks. I registered on firebase console, pusher beams, everything setup as is written in documentation, I copied example project from flutter pusher_beams package so that when i send notification and app is opened, alert pop up and when is minimised, notification is shown in notification tray.
Problems:
When I tap on notification when app is minimised, i cannot check, which notification was tapped. I tried to add delay before that function but without help.
PusherBeams.instance.getInitialMessage is returning null, when i break there, but debugger dont stop on that breakpoint when i tap on notification when app is minimised.
I dont know how to handle notifications when app is killed. I found flutter_background_service, but when i set isForegroundMode to true, unhideable (if that word exists) notification is in notification tray and when i set isForegroundMode to false, when app is killed, that service is killed too. Another possibility is to use workmanager, but that can be called the fastest every 15 mins.
class _MyHomePageState extends State<MyHomePage> {
#override
initState() {
super.initState();
initPusherBeams();
}
initPusherBeams() async {
// Let's see our current interests
print(await PusherBeams.instance.getDeviceInterests());
// This is not intented to use in web
if (!kIsWeb) {
await PusherBeams.instance
.onInterestChanges((interests) => {
print('Interests: $interests')});
await PusherBeams.instance
.onMessageReceivedInTheForeground(_onMessageReceivedInTheForeground);
}
await _checkForInitialMessage();
}
Future<void> _checkForInitialMessage() async {
await Future.delayed(const Duration(seconds: 1));
final initialMessage = await PusherBeams.instance.getInitialMessage();
if (initialMessage != null) {
_showAlert('Initial Message Is:', initialMessage.toString());
}
}
void _onMessageReceivedInTheForeground(Map<Object?, Object?> data) {
_showAlert(data["title"].toString(), data["body"].toString());
}
void _showAlert(String title, String message) {
AlertDialog alert = AlertDialog(
title: Text(title), content: Text(message), actions: const []);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
is it possible to use the camera while the app is in the foreground or background?
I tried with these two packages flutter_foreground_task and flutter_background_service but i always get this error message once i start the camera stream Unhandled Exception: MissingPluginException(No implementation found for method availableCameras on channel plugins.flutter.io/camera).
class FirstTaskHandler extends TaskHandler {
void initCamera() async {
final description = await availableCameras().then(
(cameras) => cameras.firstWhere(
(camera) => camera.lensDirection == CameraLensDirection.front,
),
);
final _cameraController = CameraController(
description,
ResolutionPreset.low,
enableAudio: false,
);
await _cameraController.initialize();
await Future.delayed(const Duration(milliseconds: 500));
_cameraController.startImageStream((img) async {
log("Image captures: ${img.width} x ${img.height} -- ${img.format.raw}");
});
}
#override
Future<void> onStart(DateTime timestamp, SendPort? sendPort) async {
initCamera();
}
#override
Future<void> onEvent(DateTime timestamp, SendPort? sendPort) async { }
#override
Future<void> onDestroy(DateTime timestamp) async {
}
#override
void onButtonPressed(String id) {
}
}
I fixed this issue by editing the camera plugin and making the Livestream method work when the app is in the foreground/background.
here is the link to the edited plugin edited-flutter-camera-plugin, just note that this version can be crashed in some functionalities because I just edited some files to make it fit my purpose of making the Livestream method works in the foreground
I am trying to show a dialog in any active screen when a push notification arrives in my app. While the app is running. I can show the dialog by user interaction, like clicking a button. But I want to show it without user interaction. If there is a notification arrive, only then the dialog should be triggered. I am trying to call it with background fetch. But couldn't find any solution. So, please help and thank you in advance.
I faced same problem before, i will show my solution and I hope it suits you
The main thing with the solution : we have page is not pop from
Navigator stack when app is life like HomePage as ex, so we can use the BuildContext from this page
so by pass context of my StatefulWidget(Like Home Page) who
must be still in stack of Navigator (not pop it when app is live) to your class who handle notification data when coming you can use it to show dialog
Let write some code now:
as ex we have NotificationManger class this class used to handle notification msg with static method
class NotificationManger {
static BuildContext _context;
static init({#required BuildContext context}) {
_context = context;
}
//this method used when notification come and app is closed or in background and
// user click on it, i will left it empty for you
static handleDataMsg(Map<String, dynamic> data){
}
//this our method called when notification come and app is foreground
static handleNotificationMsg(Map<String, dynamic> message) {
debugPrint("from mangger $message");
final dynamic data = message['data'];
//as ex we have some data json for every notification to know how to handle that
//let say showDialog here so fire some action
if (data.containsKey('showDialog')) {
// Handle data message with dialog
_showDialog(data);
}
}
static _showDialog({#required Map<String, dynamic> data}) {
//you can use data map also to know what must show in MyDialog
showDialog(context: _context,builder: (_) =>MyDialog());
}
}
Now we have this callback as top level or static (must be one of them ) inside class FCM of my app inside it
class Fcm {
static final FirebaseMessaging _fcm = FirebaseMessaging();
static initConfigure() {
if (Platform.isIOS) _iosPermission();
_fcm.requestNotificationPermissions();
_fcm.autoInitEnabled();
_fcm.configure(
onMessage: (Map<String, dynamic> message) async =>
NotificationManger.handleNotificationMsg(message),
onLaunch: (Map<String, dynamic> message) async =>
NotificationManger.handleDataMsg(message['data']),
onResume: (Map<String, dynamic> message) async =>
NotificationManger.handleDataMsg(message['data']),
onBackgroundMessage: async =>
NotificationManger.handleDataMsg(message['data']);
}
static _iosPermission() {
_fcm.requestNotificationPermissions(
IosNotificationSettings(sound: true, badge: true, alert: true));
_fcm.onIosSettingsRegistered.listen((IosNotificationSettings settings) {
print("Settings registered: $settings");
});
}
}
For know more about callback fcm read this
ok now in our HomePage State well init our class inside initState method
#override
void initState() {
super.initState();
Future.delayed(Duration.zero,(){
///init Notification Manger
NotificationManger.init(context: context);
///init FCM Configure
Fcm.initConfigure();
});
}
as say before the homePage will be not pop when app is show , you can start another page but without close the homePage
i hope this help
Im using react-native-firebase for handling push notification for our React Native app (for android and iOS).
I noticed that there is only have 1 callback for a push notification that is received when the app is running (foreground or background) and not when its closed or killed.
firebase
.notifications()
.onNotification(notification => {
console.log('Notification received');
);
But if the app is closed or killed, it will just put the notification in the tray and will not execute the console.log above.
Then enter silent push notification. So when I just send data part in the payload of the notification and even if app is in foreground, the callback above wont be triggered.
I don't see other callbacks that would help on receiving silent push notifications.
So how do we handle push notification in the javascript part?
You don't need additional packages like suggested in other answers.
Use RNFirebase.io, you can handle this easily.
If you receive Notification if App is in Background, you have to handle it by your own to display this Notification. As an example see my init-Method for Push-Notifications.
import firebase from 'react-native-firebase';
const notifications = firebase.notifications();
....
notifications.onNotification((notif) => {
notif.android.setChannelId('app-infos');
notifications.displayNotification(notif);
});
You do it with displayNotification. But make sure, that you set the Notification-Channel before calling it, because else it wouldn't work on >= Android 8.0
BTW: Make sure, that you fully setup Firebase and grant all needed Permissions to be able to listen for Notifications if App is closed or in Background. (https://rnfirebase.io/docs/v5.x.x/notifications/android)
Appendix
I add this as example to show how I implemented the firebase-notification-stuff as a tiny library (remove the redux-stuff if you don't need it):
import firebase from 'react-native-firebase';
import { saveNotificationToken } from 'app/actions/firebase';
import reduxStore from './reduxStore';
import NavigationService from './NavigationService';
const messaging = firebase.messaging();
const notifications = firebase.notifications();
const crashlytics = firebase.crashlytics();
function registerNotifChannels() {
try {
// Notification-Channels is a must-have for Android >= 8
const channel = new firebase.notifications.Android.Channel(
'app-infos',
'App Infos',
firebase.notifications.Android.Importance.Max,
).setDescription('General Information');
notifications.android.createChannel(channel);
} catch (error) {
crashlytics.log(`Error while creating notification-channel \n ${error}`);
}
}
// This is the Promise object that we use to initialise the push
// notifications. It will resolve when the token was successfully retrieved. The
// token is returned as the value of the Promise.
const initPushNotifs = new Promise(async (resolve, reject) => {
try {
const isPermitted = await messaging.hasPermission();
if (isPermitted) {
registerNotifChannels();
try {
const token = await messaging.getToken();
if (token) {
resolve(token);
}
} catch (error) {
crashlytics.log(`Error: failed to get notification-token \n ${error}`);
}
}
} catch (error) {
crashlytics.log(`Error while checking notification-permission\n ${error}`);
}
// If we get this far then there was no token available (or something went
// wrong trying to get it)
reject();
});
function init() {
// Initialise the push notifications, then save the token when/if it's available
initPushNotifs.then(token => reduxStore.dispatch(saveNotificationToken(token)));
// Save the (new) token whenever it changes
messaging.onTokenRefresh(token => reduxStore.dispatch(saveNotificationToken(token)));
notifications.onNotification((notif) => {
notif.android.setChannelId('app-infos');
notifications.displayNotification(notif);
});
notifications.onNotificationOpened((notif) => {
const { notification: { _data: { chatroom: chatRoomId } } = {} } = notif;
if (chatRoomId) {
NavigationService.navigate('ChatRoom', { chatRoomId });
}
});
}
export default {
init,
};
With this, only go to your index.js file (or your root-file for your app, how ever it will be named) and call the init-Metod:
...
import LPFirebase from 'lib/LPFirebase';
LPFirebase.init();
How do I do this? I used the code below but it is not working. I still receive notification when I update my Database
exports.sendNewPostNotif = functions.database.ref('/News/{ID}').onWrite(event => {
const announce_data = event.data.val();
const announce_data_type = announce_data.categ_post;
const announce_data_title = announce_data.title_post;
const announce_data_uid = announce_data.uid; id
const announce_post_key = announce_data.postkey;
if(!event.data.val()) {
return console.log('No data');
}
if(event.data.previous.exist()) {
return;
}
Whenever I send a new content, it'll go through the onWrite event then send the notification. Mmy current issue is whenever I edit the post, it'll send a notification which I do not require. I tried the above and it works as I receive no notification when I update the news content BUT I don't receive a notification when I create a new content.
If you only want your function to run when the node is created, and not when it is updated or deleted, you can use the onCreate trigger:
exports.sendNewPostNotif = functions.database.ref('/News/{ID}').onCreate(event => {
See the Firebase documentation on database trigger types and the blog post where these are introduced.