Flutter:在前台运行时,flutter_local_notifications 不起作用

Posted

技术标签:

【中文标题】Flutter:在前台运行时,flutter_local_notifications 不起作用【英文标题】:Flutter: flutter_local_notifications not work when running in Foreground 【发布时间】:2022-01-14 12:08:50 【问题描述】:

我想实现FCMflutter_local_notifications 来处理来自backgroundforeground 的通知。我已经按照这两个文档来设置插件。当我在 android 上尝试时,background 通知有效并显示通知。但是当我尝试foreground 时,FCM 可以正常工作(发送titlebody),但通知不显示(get error)。详细错误如下:

D/FLTFireMsgReceiver(26448): broadcast received for message
W/roonapp.stagin(26448): Accessing hidden method Landroid/os/WorkSource;->add(I)Z (greylist, reflection, allowed)
W/roonapp.stagin(26448): Accessing hidden method Landroid/os/WorkSource;->add(ILjava/lang/String;)Z (greylist, reflection, allowed)
W/roonapp.stagin(26448): Accessing hidden method Landroid/os/WorkSource;->size()I (greylist, reflection, allowed)
W/roonapp.stagin(26448): Accessing hidden method Landroid/os/WorkSource;->get(I)I (greylist, reflection, allowed)
W/roonapp.stagin(26448): Accessing hidden method Landroid/os/WorkSource;->getName(I)Ljava/lang/String; (greylist, reflection, allowed)
[log] [32m——————————————————————————————————————————————————————————————————————
                DEBUG
——————————————————————————————————————————————————————————————————————
            2021-12-09T22:05:18.792141
——————————————————————————————————————————————————————————————————————
Show Notification:
Title -> test0
Body -> test0
Payload -> null

——————————————————————————————————————————————————————————————————————[0m
E/MethodChannel#dexterous.com/flutter/local_notifications(26448): Failed to handle method call
E/MethodChannel#dexterous.com/flutter/local_notifications(26448): java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Intent android.content.Intent.setAction(java.lang.String)' on a null object reference
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.createNotification(FlutterLocalNotificationsPlugin.java:187)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.showNotification(FlutterLocalNotificationsPlugin.java:1023)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.show(FlutterLocalNotificationsPlugin.java:1358)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.onMethodCall(FlutterLocalNotificationsPlugin.java:1240)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:84)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:865)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at android.os.MessageQueue.next(MessageQueue.java:336)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at android.os.Looper.loop(Looper.java:197)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at android.app.ActivityThread.main(ActivityThread.java:7948)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
E/MethodChannel#dexterous.com/flutter/local_notifications(26448):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
E/flutter (26448): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: PlatformException(error, Attempt to invoke virtual method 'android.content.Intent android.content.Intent.setAction(java.lang.String)' on a null object reference, null, java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Intent android.content.Intent.setAction(java.lang.String)' on a null object reference
E/flutter (26448):  at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.createNotification(FlutterLocalNotificationsPlugin.java:187)
E/flutter (26448):  at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.showNotification(FlutterLocalNotificationsPlugin.java:1023)
E/flutter (26448):  at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.show(FlutterLocalNotificationsPlugin.java:1358)
E/flutter (26448):  at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.onMethodCall(FlutterLocalNotificationsPlugin.java:1240)
E/flutter (26448):  at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/flutter (26448):  at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:84)
E/flutter (26448):  at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:865)
E/flutter (26448):  at android.os.MessageQueue.nativePollOnce(Native Method)
E/flutter (26448):  at android.os.MessageQueue.next(MessageQueue.java:336)
E/flutter (26448):  at android.os.Looper.loop(Looper.java:197)
E/flutter (26448):  at android.app.ActivityThread.main(ActivityThread.java:7948)
E/flutter (26448):  at java.lang.reflect.Method.invoke(Native Method)
E/flutter (26448):  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
E/flutter (26448):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
E/flutter (26448): )
E/flutter (26448): #0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:607:7)
E/flutter (26448): #1      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:156:18)
E/flutter (26448): <asynchronous suspension>
E/flutter (26448): #2      FlutterLocalNotificationsPlugin.show (package:flutter_local_notifications/src/flutter_local_notifications_plugin.dart:194:7)
E/flutter (26448): <asynchronous suspension>
E/flutter (26448): #3      NotificationHelper.showNormalNotification (package:notification/notification/notifications_helper.dart:85:5)
E/flutter (26448): <asynchronous suspension>
E/flutter (26448): 

图书馆版本

firebase_core: ^1.10.0
firebase_messaging: ^11.2.3
firebase_analytics: ^9.0.2
flutter_local_notifications: ^9.1.4

AndroidManifest.xml


    <application
        ...>
        <activity
            android:showWhenLocked="true"
            android:turnScreenOn="true">
            ...
        </activity>
        
        ...
        
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="channel_id_app" />
    </application>

main.dart

void main() async 
  WidgetsFlutterBinding.ensureInitialized();

  await Firebase.initializeApp();

  ...

  await NotificationConfig.init();

  runApp(App());

通知配置

class NotificationConfig 
  static init() async 
    final notificationHelper = NotificationHelper();

    try 
      FirebaseMessaging.onBackgroundMessage(fcmBackgroundHandler); //This work fine
     catch (e, trace) 
      Logger.e('Error Running Notification in Background: $e',
          ex: e, stacktrace: trace);
    

    //TODO: Foreground not work (the notification)
    try 
      FirebaseMessaging.onMessage.listen((RemoteMessage message) 
        final notification = message.notification;
        if (notification != null) 
          final body = ReceivedNotification(
            title: notification.title,
            body: notification.body,
          );
          notificationHelper.showNormalNotification(body); //TODO: This is error when from `foreground`
        
      );
     catch (e, trace) 
      Logger.e('Error Running Notification in Foreground: $e',
          ex: e, stacktrace: trace);
    
  

通知助手

Future<void> fcmBackgroundHandler(RemoteMessage message) async 
  final notificationHelper = NotificationHelper(); 

  final body = ReceivedNotification(
    title: message.notification?.title,
    body: message.notification?.body,
  );

  await notificationHelper.showNormalNotification(body); //TODO: This is not error when from `background`


class NotificationHelper 
  /// Singleton pattern
  static NotificationHelper? _instance;

  NotificationHelper._internal() 
    _instance = this;
    _init();
  

  factory NotificationHelper() =>
      _instance ?? NotificationHelper._internal();

  final _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

  Future<void> _init() async 
    await _setupLocalNotification();
    await _setupFcm();
  

Future<void> _setupLocalNotification() async 
    const channel = AndroidNotificationChannel(
      NotificationChannel.channelId,
      NotificationChannel.channelName,
      description: NotificationChannel.channelDesc,
      importance: Importance.max,
    );

    /// Initialization Settings for Android
    const initializationSettingsAndroid =
        AndroidInitializationSettings('@mipmap/ic_launcher');

    /// Initialization Settings for ios
    const initializationSettingsIOS = IOSInitializationSettings(
      requestSoundPermission: false,
      requestBadgePermission: false,
      requestAlertPermission: false,
    );

    /// InitializationSettings for initializing settings for both platforms
    const initializationSettings = InitializationSettings(
      android: initializationSettingsAndroid,
      iOS: initializationSettingsIOS,
    );

    await _flutterLocalNotificationsPlugin.initialize(
      initializationSettings,
    );

    /// Create an Android Notification Channel.
    ///
    /// We use this channel in the `AndroidManifest.xml` file to override the
    /// default FCM channel to enable heads up notifications.
    await _flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin>()
        ?.createNotificationChannel(channel);
  

  Future<void> showNormalNotification(
    ReceivedNotification? notification,
  ) async 
    Logger.d(
      'Show Notification:\n'
      'Title -> $notification?.title\n'
      'Body -> $notification?.body\n'
      'Payload -> $notification?.payload\n',
    );

    await _flutterLocalNotificationsPlugin.show(
      NotificationType.normal,
      notification?.title,
      notification?.body,
      const NotificationDetails(
        android: AndroidNotificationDetails(
          NotificationChannel.channelId,
          NotificationChannel.channelName,
          channelDescription: NotificationChannel.channelDesc,
          priority: Priority.high,
          importance: Importance.max,
        ),
      ),
      payload: notification?.payload,
    );
  

Future<void> _setupFcm() async 
    final fcm = FirebaseMessaging.instance;

    await fcm.setForegroundNotificationPresentationOptions(
      alert: true,
      badge: true,
      sound: true,
    );

    final token = await fcm.getToken();
    Logger.d("Token FCM: $token");

    ...
  


正如你在上面看到的,ForegroundBackground 都调用了一些函数notificationHelper.showNormalNotification(body)。但是,当它来自Foreground 时,会出现上述 logcat 中的错误,而当来自 Background 时,它就可以工作了。

Foreground 中运行时,我想将flutter_local_notifications 设置为工作吗?

【问题讨论】:

我认为您缺少一些有关 Android 中前台通知处理的初始化步骤。 Check this out. 我已经添加了,请参见上面的示例代码 (_setupLocalNotification()) 我明白了。还有通知图标呢,资源里面有没有,AndroidManifest.xml里有default_notification_icon设置吗? 我认为通知的设置已经完成,因为在background 上运行时,通知显示,但仅在foreground 上出现错误 【参考方案1】:

终于,经过 2 天的工作,我找到了解决方案。

当应用程序在foreground 中打开或运行时,通知不会显示,这是因为在我的AndroidManifest.xml 中有intent service 用于deeplink

<intent-filter>
    ....

        <data android:scheme="$deeplink_schema" />
</intent-filter>

【讨论】:

以上是关于Flutter:在前台运行时,flutter_local_notifications 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 中的 Agora 视频通话问题

NullPointerException flutter_local_notifications 在版本更新后不起作用

Flutter Firebase如何控制通知在应用程序处于前台时不显示

Flutter 应用程序可以在后台运行吗?

Flutter:当我的应用不在前台时如何显示横幅(如地图/谷歌地图)?

如何在 Flutter 和 Firebase 的前台打印(message.data)