单击通知行为仅在应用程序在后台运行时才有效?

Posted

技术标签:

【中文标题】单击通知行为仅在应用程序在后台运行时才有效?【英文标题】:Clicking notification behavior only works when the app is in the background in flutter? 【发布时间】:2021-11-02 21:48:21 【问题描述】:

我正在尝试使用 firebase 云功能向所有订阅自定义主题的用户推送通知,但在后台通知场景中,当单击通知时,它仅在应用程序处于后台时导航到所需的屏幕,但在终止应用程序和有一个通知它打开主屏幕不是通知主题

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

const androidNotificationChannel channel = AndroidNotificationChannel(
    'high_importance_channel', // id
    'High Importance Notifications', // title
    'This channel is used for important notifications.', // description
    importance: Importance.high,
    playSound: true);

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async 
  await Firebase.initializeApp();
  print('A bg message just showed up :  $message.messageId');


void subscribeToTopic() async 
  try 
    await FirebaseMessaging.instance.subscribeToTopic('notifications');
    print('subscribed to topic');
   catch (e) 
    print('error is $e');
  


Future<void> main() async 
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<
          AndroidFlutterLocalNotificationsPlugin>()
      ?.createNotificationChannel(channel);

  await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
    alert: true,
    badge: true,
    sound: true,
  );
  runApp(MyApp());


class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  


class MyHomePage extends StatefulWidget 
  MyHomePage(Key? key, this.title) : super(key: key);

  final String? title;

  @override
  _MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State<MyHomePage> 
  int _counter = 0;
  
  @override
  void initState() 
    super.initState();
    subscribeToTopic();

    FirebaseMessaging.onMessage.listen((RemoteMessage message) 
      print('onMessage data is $message.data');
      print('onMessage notification is $message.notification');

      RemoteNotification? notification = message.notification;
      AndroidNotification? android = message.notification?.android;
      if (notification != null && android != null) 
        flutterLocalNotificationsPlugin.show(
            notification.hashCode,
            notification.title,
            notification.body,
            NotificationDetails(
              android: AndroidNotificationDetails(
                channel.id,
                channel.name,
                channel.description,
                color: Colors.blue,
                playSound: true,
                icon: '@mipmap/ic_launcher',
              ),
            ));
      
    );

 FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) 
      print('A new onMessageOpenedApp event was published!');
    
      Navigator.pushNamed(context, '/productsScreen');
    
    );
    
  

  void showNotification() async 
    setState(() 
      _counter++;
    );
    flutterLocalNotificationsPlugin.show(
        0,
        "Testing $_counter",
        "How you doin ?",
        NotificationDetails(
            android: AndroidNotificationDetails(
                channel.id, channel.name, channel.description,
                importance: Importance.high,
                color: Colors.blue,
                playSound: true,
                icon: '@mipmap/ic_launcher')));
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title!),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: showNotification,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  

【问题讨论】:

【参考方案1】:

在您的应用从终止(已终止)状态打开后,您可以使用FirebaseMessaging.getInitialMessage()。见documentation

FirebaseMessaging.onMessageOpenedApp 仅在应用程序处于后台状态但仍在运行时有效。所以在一天结束时,你的 main 看起来就像这样:

RemoteMessage? initialMessage;

Future<void> main() async 
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  // We add this additional line to get the initial message
  initialMessage =  FirebaseMessaging.instance.getInitialMessage();

  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<
          AndroidFlutterLocalNotificationsPlugin>()
      ?.createNotificationChannel(channel);

  await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
    alert: true,
    badge: true,
    sound: true,
  );
  runApp(MyApp());

如果initialMessage 不为空,您将知道用户点击了通知并且应用程序随即打开。在此之后,您可以根据需要处理 initialMessage 中的数据,最好在调用 runApp() 之后处理,因为您希望在用户打开应用程序后导航到不同的屏幕。

【讨论】:

以上是关于单击通知行为仅在应用程序在后台运行时才有效?的主要内容,如果未能解决你的问题,请参考以下文章

ios 应用未运行时推送通知单击处理程序

文件上传进度的通知观察者模式仅在文件很大时才有效 - swift?

实现 iOS 推送通知的问题

Cordova,onResume() 仅在我包含 alert() 时才有效

Facebook SDK 3.2 登录仅在应用程序未终止时才有效

在后台推送 iOS 通知