在每个屏幕上的 fcm 通知上显示小吃栏
Posted
技术标签:
【中文标题】在每个屏幕上的 fcm 通知上显示小吃栏【英文标题】:show snackbar on fcm notification on every screen 【发布时间】:2020-07-14 21:02:32 【问题描述】:我想在应用通知到达时显示小吃栏。 但是当我在第一个屏幕上配置 firebase 时,小吃栏仅在用户在该屏幕上时显示。 我尝试创建一个类来获取 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
【问题讨论】:
【参考方案1】:问题在于为 NotificationManager 小部件注册脚手架,因为每次将新脚手架添加到新屏幕的堆栈中时,您都需要在 NotificationManager 中注册该屏幕的脚手架。这是因为行:
Scaffold.of(_context).showSnackBar(snackBar);
在 NoticicationManager 中只会查找小部件树,直到它找到第一个脚手架并在那里调用它。由于您在 HomeScreen 小部件中调用 NotificationManger.init(context: context);
并传递 HomeScreen 的上下文,因此它将仅存在于该脚手架内。因此,如果您从 HomeScreen 导航到具有不同脚手架的新小部件,它将不会有 NotificationManager 作为子级。
要解决此问题,请确保在为应用加载的第一页中调用 Fcm.initConfigure();
,对于您导航到的任何页面,请在有状态小部件的 initState() 方法中调用 NotificationManger.init(context: context);
以注册当前脚手架或者如果它们是无状态小部件,则可以在返回脚手架之前将其添加到 build 方法中。
【讨论】:
我已经更新了我的答案,提供了关于如何操作的建议,看看它是否有效,如果您还有其他问题,请尝试添加您的 main.dart 或明确您是如何离开 HomeScreen 的跨度> 您是否尝试将Fcm.initConfigure();
移动到您的main.dart,因为它是构建方法中的一个无状态小部件,并将NotificationManger.init(context: context);
添加到您的每个页面的initState 方法中?
我想在用户登录时配置 fcm。所以我的 homeScreen 是用户登录时的根屏幕。并且我的 homeScreen 的构建方法在导航时运行。
好的,那么该页面可以保持不变,您能告诉我您如何导航到不同页面的示例以及该页面的代码吗?
让我们continue this discussion in chat。【参考方案2】:
在所有屏幕上复制相同的代码可能并不理想。如果你必须改变某些东西,你将不得不改变一切,否则你会看到不一致的地方。 对于小吃店,您可以使用这个库并在 1 行代码中解决您的问题:
关于你的 onMessage 方法:
onMessage(message)
Get.snackbar("message", message); // this line
是的,无论用户在哪个屏幕上,都会显示snackbar,你不需要脚手架的上下文,也不需要任何上下文,只需调用库方法就可以了。
库:https://pub.dev/packages/get
【讨论】:
以上是关于在每个屏幕上的 fcm 通知上显示小吃栏的主要内容,如果未能解决你的问题,请参考以下文章
在 Android Q 的锁定屏幕上收到 fcm 通知后开始活动