I want to show snackbar when in app notification arrive. But when I configure firebase on first screen, snackbar shows only when user is on that screen. I try to create a class to get BuildContext and show snackbar based on it but doesn't work and not show snackbar.
This is my HomeScreen.dart:
class _HomeScreenState extends State<HomeScreen> {
@override
void initState() {
super.initState();
Future.delayed(Duration.zero, () {
NotificationManger.init(context: context);
Fcm.initConfigure();
});
}
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, Store<AppState>>(
converter: (store) => store,
onInit: (store) => initApp(store),
builder: (context, store) {
return BlocProvider<HomeBloc>(
create: (context) {
return HomeBloc(homeRepository: homeRepository)..add(ScreenOpened());
},
child: BlocListener<HomeBloc, HomeState>(
listener: (context, state) async {},
child: BlocBuilder<HomeBloc, HomeState>(
builder: (context, state) {
return Scaffold(
key: _scaffoldKey,
...
);
},
),
),
);
},
);
}
}
This is my Fcm.dart
Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) {
if (message.containsKey('data')) {
final dynamic data = message['data'];
}
if (message.containsKey('notification')) {
final dynamic notification = message['notification'];
}
}
class Fcm {
static final FirebaseRepository repository = FirebaseRepository();
static final FirebaseMessaging _fcm = FirebaseMessaging();
static initConfigure() {
if (Platform.isIOS) _iosPermission();
_fcm.requestNotificationPermissions();
_fcm.autoInitEnabled();
_fcm.configure(
onMessage: (Map<String, dynamic> message) async => NotificationManger.onMessage(message),
onLaunch: (Map<String, dynamic> message) async => NotificationManger.onLaunch(message),
onResume: (Map<String, dynamic> message) async => NotificationManger.onResume(message),
onBackgroundMessage: myBackgroundMessageHandler,
);
_fcm.getToken().then((String token) {
print('token: $token');
repository.setUserNotifToken(token);
});
}
static _iosPermission() {
_fcm.requestNotificationPermissions(IosNotificationSettings(sound: true, badge: true, alert: true));
_fcm.onIosSettingsRegistered.listen((IosNotificationSettings settings) {
print("Settings registered: $settings");
});
}
}
and this is my NotificationManager.dart:
class NotificationManger {
static BuildContext _context;
static init({@required BuildContext context}) {
_context = context;
}
static onMessage(Map<String, dynamic> message) {
print(message);
_showSnackbar(data: message);
}
static onLaunch(Map<String, dynamic> message) {
print(message);
}
static onResume(Map<String, dynamic> message) {
print(message);
}
static _showSnackbar({@required Map<String, dynamic> data}) {
// showDialog(context: _context, builder: (_) => );
SnackBar snackBar = SnackBar(
content: Text(
data['data']['title'],
style: TextStyle(
fontFamily: 'Vazir',
fontSize: 16.0,
),
),
backgroundColor: ColorPalette.primary,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(45.0),
),
elevation: 3.0,
);
Scaffold.of(_context).showSnackBar(snackBar);
}
}
main.dart
class App extends StatelessWidget {
final Store<AppState> store;
App(this.store);
@override
Widget build(BuildContext context) {
return StoreProvider(
store: store,
child: MaterialApp(
...
),
);
}
}
I am using redux and bloc, so any approach with these tools is ok for me.
This is my sample screen:
class Reminders extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBar,
body: Center(
child: Text('reminders'),
),
);
}
}
SOLUTION:
Add NotificationManger.init(globalKey: _scaffoldKey);
to all screens solve the problem.
class Reminders extends StatelessWidget {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
NotificationManger.init(globalKey: _scaffoldKey);
return Scaffold(
key: _scaffoldKey,
appBar: appBar,
body: Center(
child: Text('reminders'),
),
);
}
}
SOLUTION 2
UsingGet library to using only one function and no need to add it in all screen: https://pub.dev/packages/get
Building, displaying, and customizing the SnackBarLaunch Android Studio or another IDE of your choice. Start a new Flutter project. Select Flutter Application and name the project something like “snackbardemo”
Stay organized with collections Save and categorize content based on your preferences. The FCM HTTP v1 API and the Notifications composer support sending image links in the payload of a display notification, for image download to the device after delivery.
then you can simply call the Get. snackbar() to show the snackbar where you want it to be displayed. You can use this package when you don't have the context too. Save this answer.
The problem is with registering scaffolds for your NotificationManager widget since every time a new scaffold is added to the stack for a new screen, you need to register that screen's scaffold in the NotificationManager. This is because the line:
Scaffold.of(_context).showSnackBar(snackBar);
in your NoticicationManager will only look up the widget tree until the first scaffold it finds and call it there. Since you call NotificationManger.init(context: context);
in your HomeScreen widget and pass the context of the HomeScreen, it will only live inside that scaffold. So, if you navigate away from the HomeScreen to a new widget with a different scaffold it will not have the NotificationManager as a child.
To fix the issue be sure you call Fcm.initConfigure();
in the first page that loads for the app, and for any pages you navigate to call NotificationManger.init(context: context);
in either the initState() method for stateful widgets to register the current scaffold of that page or if they are stateless widgets, you can add it in the build method before returning the scaffold.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With