在每个屏幕上的 fcm 通知上显示 snackbar
show snackbar on fcm notification on every screen
我想在应用内通知到达时显示快餐栏。
但是当我在第一个屏幕上配置 firebase 时,只有当用户在该屏幕上时才会显示 snackbar。
我尝试创建一个 class 来获取 BuildContext 并基于它显示 snackbar 但不起作用并且不显示 snackbar。
这是我的 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,
...
);
},
),
),
);
},
);
}
}
这是我的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");
});
}
}
这是我的 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(
...
),
);
}
}
我正在使用 redux 和 bloc,所以使用这些工具的任何方法对我来说都可以。
这是我的示例屏幕:
class Reminders extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBar,
body: Center(
child: Text('reminders'),
),
);
}
}
解决方案:
添加NotificationManger.init(globalKey: _scaffoldKey);
到所有屏幕解决问题。
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'),
),
);
}
}
解决方案 2
使用Get 库只使用一个函数,无需在所有屏幕中添加它:https://pub.dev/packages/get
问题在于为 NotificationManager 小部件注册脚手架,因为每次将新脚手架添加到新屏幕的堆栈时,您都需要在 NotificationManager 中注册该屏幕的脚手架。这是因为行:
Scaffold.of(_context).showSnackBar(snackBar);
在您的 NoticicationManager 中,只会查找小部件树,直到它找到第一个脚手架并在那里调用它。由于您在 HomeScreen 小部件中调用 NotificationManger.init(context: context);
并传递 HomeScreen 的上下文,因此它只会存在于该脚手架内。因此,如果您从 HomeScreen 导航到具有不同支架的新小部件,它将不会将 NotificationManager 作为子项。
要解决此问题,请确保您在为应用程序加载的第一个页面中调用 Fcm.initConfigure();
,并且对于您导航的任何页面在有状态的 initState() 方法中调用 NotificationManger.init(context: context);
小部件注册该页面的当前脚手架,或者如果它们是无状态小部件,您可以在返回脚手架之前在构建方法中添加它。
我想在应用内通知到达时显示快餐栏。 但是当我在第一个屏幕上配置 firebase 时,只有当用户在该屏幕上时才会显示 snackbar。 我尝试创建一个 class 来获取 BuildContext 并基于它显示 snackbar 但不起作用并且不显示 snackbar。
这是我的 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,
...
);
},
),
),
);
},
);
}
}
这是我的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");
});
}
}
这是我的 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(
...
),
);
}
}
我正在使用 redux 和 bloc,所以使用这些工具的任何方法对我来说都可以。
这是我的示例屏幕:
class Reminders extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBar,
body: Center(
child: Text('reminders'),
),
);
}
}
解决方案:
添加NotificationManger.init(globalKey: _scaffoldKey);
到所有屏幕解决问题。
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'),
),
);
}
}
解决方案 2
使用Get 库只使用一个函数,无需在所有屏幕中添加它:https://pub.dev/packages/get
问题在于为 NotificationManager 小部件注册脚手架,因为每次将新脚手架添加到新屏幕的堆栈时,您都需要在 NotificationManager 中注册该屏幕的脚手架。这是因为行:
Scaffold.of(_context).showSnackBar(snackBar);
在您的 NoticicationManager 中,只会查找小部件树,直到它找到第一个脚手架并在那里调用它。由于您在 HomeScreen 小部件中调用 NotificationManger.init(context: context);
并传递 HomeScreen 的上下文,因此它只会存在于该脚手架内。因此,如果您从 HomeScreen 导航到具有不同支架的新小部件,它将不会将 NotificationManager 作为子项。
要解决此问题,请确保您在为应用程序加载的第一个页面中调用 Fcm.initConfigure();
,并且对于您导航的任何页面在有状态的 initState() 方法中调用 NotificationManger.init(context: context);
小部件注册该页面的当前脚手架,或者如果它们是无状态小部件,您可以在返回脚手架之前在构建方法中添加它。