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 【问题描述】:我想实现FCM
和flutter_local_notifications
来处理来自background
和foreground
的通知。我已经按照这两个文档来设置插件。当我在 android 上尝试时,background
通知有效并显示通知。但是当我尝试foreground
时,FCM
可以正常工作(发送title
和body
),但通知不显示(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");
...
正如你在上面看到的,Foreground
和Background
都调用了一些函数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 不起作用的主要内容,如果未能解决你的问题,请参考以下文章
NullPointerException flutter_local_notifications 在版本更新后不起作用
Flutter Firebase如何控制通知在应用程序处于前台时不显示