在每个屏幕上的 fcm 通知上显示小吃栏

BeH*_*ppy 6 firebase snackbar flutter firebase-cloud-messaging

我想在应用程序通知到达时显示小吃店。但是当我在第一个屏幕上配置 firebase 时,snackbar 仅在用户在该屏幕上时显示。我尝试创建一个类来获取 BuildContext 并基于它显示小吃店但不起作用并且不显示小吃店。


这是我的 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,
                  ...
                );
              },
            ),
          ),
        );
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我的 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");
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我的 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);
  }
}
Run Code Online (Sandbox Code Playgroud)

main.dart

class App extends StatelessWidget {
  final Store<AppState> store;
  App(this.store);
  @override
  Widget build(BuildContext context) {
    return StoreProvider(
      store: store,
      child: MaterialApp(
        ...
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用 redux 和 bloc,所以任何使用这些工具的方法都适合我。

这是我的示例屏幕:


class Reminders extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: appBar,
      body: Center(
        child: Text('reminders'),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

解决方案:添加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'),
      ),
    );
  }
}

Run Code Online (Sandbox Code Playgroud)

解决方案 2

使用Get库只使用一个函数,不需要在所有屏幕中添加它:https : //pub.dev/packages/get

Jwi*_*ith 3

问题在于为您的NotificationManager小部件注册脚手架,因为每次将新脚手架添加到新屏幕的堆栈中时,您都需要在NotificationManager中注册该屏幕的脚手架。这是因为该行:

Scaffold.of(_context).showSnackBar(snackBar);

在您的 NoticicationManager 中,只会查找小部件树,直到找到第一个脚手架并在那里调用它。由于您调用NotificationManger.init(context: context);HomeScreen 小部件并传递 HomeScreen 的上下文,因此它只会存在于该支架内。因此,如果您从主屏幕导航到具有不同支架的新小部件,它将不会将NotificationManager作为子项。

要解决此问题,请确保您调用Fcm.initConfigure();为应用程序加载的第一个页面,以及您导航的任何页面,以调用NotificationManger.init(context: context);有状态小部件的 initState() 方法来注册该页面的当前支架,或者如果它们是无状态小部件,您可以在返回脚手架之前将其添加到构建方法中。