Flutter推送通知的声音会重复播放
我正在为我的推送通知实现自定义声音。问题在于,当推送通知发送时,声音会重复播放,直到我点击通知图标才会停止。
我只想让声音只播放一次,但我仍然不知道为什么会重复。
我在不同设备上进行了测试,但情况仍然一样。我不知道自己哪里做错了。
class NotificationController {
static Future<void> initializeNotification() async {
await AwesomeNotifications().removeChannel(moneyInChannelId);
await AwesomeNotifications().removeChannel(normalTransactionChannelId);
await AwesomeNotifications().removeChannel(actionNotificationId);
await AwesomeNotifications().initialize(
'resource://drawable/res_logo_white_bg',
[
NotificationChannel(
channelKey: moneyInChannelId,
channelName: 'Money Received',
channelDescription: 'Alerts when money enters your account',
playSound: true,
soundSource: 'resource://raw/notification',
enableVibration: true,
vibrationPattern: Int64List.fromList([0, 300, 200, 300, 200, 600]),
importance: NotificationImportance.Max,
defaultPrivacy: NotificationPrivacy.Private,
defaultColor: AppColor.kColor700,
ledColor: AppColor.kColor700,
onlyAlertOnce: false,
groupAlertBehavior: GroupAlertBehavior.Children,
),
NotificationChannel(
channelKey: normalTransactionChannelId,
channelName: transactionNotifyChannelName,
channelDescription: channelDescription,
playSound: true,
soundSource: 'resource://raw/notification',
importance: NotificationImportance.High,
defaultPrivacy: NotificationPrivacy.Private,
defaultColor: AppColor.kColor700,
ledColor: AppColor.kColor700,
onlyAlertOnce: false,
groupAlertBehavior: GroupAlertBehavior.Children,
),
NotificationChannel(
channelKey: actionNotificationId,
channelName: notificationWithActionChannelName,
channelDescription: channelDescription,
playSound: true,
soundSource: 'resource://raw/notification',
importance: NotificationImportance.High,
defaultPrivacy: NotificationPrivacy.Private,
defaultColor: AppColor.kColor700,
ledColor: AppColor.kColor700,
onlyAlertOnce: false,
groupAlertBehavior: GroupAlertBehavior.Children,
),
],
debug: true,
);
}
static Future<void> requestPermissionToSendNotification() async {
await AwesomeNotifications().requestPermissionToSendNotifications();
}
static Future<bool> _areNotificationsAllowed() async {
return await AwesomeNotifications().isNotificationAllowed();
}
static Future<void> createTransactionNotification({
required bool isMoneyIn,
String? title,
String? body,
}) async {
final isAllowed = await _areNotificationsAllowed();
if (!isAllowed) return;
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: DateTime.now().millisecondsSinceEpoch.remainder(100000),
channelKey: isMoneyIn ? moneyInChannelId : normalTransactionChannelId,
title: title,
body: body,
summary: transactionNotifySummary,
notificationLayout: NotificationLayout.BigText,
fullScreenIntent: isMoneyIn,
wakeUpScreen: isMoneyIn,
category: isMoneyIn ? NotificationCategory.Alarm : null,
),
);
}
static Future<void> createNewNotification({
String? title,
String? body,
}) async {
await createTransactionNotification(
isMoneyIn: false,
title: title,
body: body,
);
}
static Future<void> createNotificationWithAction({
String? title,
String? body,
String? bigPicture,
String? largeIcon,
}) async {
final isAllowed = await _areNotificationsAllowed();
if (!isAllowed) return;
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: DateTime.now().millisecondsSinceEpoch.remainder(100000),
channelKey: actionNotificationId,
title: title,
body: body,
summary: actionNotifySummary,
notificationLayout: NotificationLayout.BigText,
fullScreenIntent: true,
largeIcon: largeIcon,
bigPicture: bigPicture,
),
actionButtons: [
NotificationActionButton(
key: actionNotificationId,
label: 'View',
color: AppColor.kColor700,
),
],
);
}
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver;
//Listen to foreground notification
FirebaseMessaging.onMessage.listen(_firebaseMessagingForegroundHandler);
//Registering a background function.
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
//set a notification listener
AwesomeNotifications().setListeners(
onActionReceivedMethod: onActionReceivedMethod,
);
}
@override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: const Size(720, 1280),
builder: (context, child) {
return MaterialApp(
navigatorKey: PageCatholicPay.navigatorKey,
navigatorObservers: [routeObserver],
debugShowCheckedModeBanner: env == Environment.live ? false : true,
theme: AppTheme.light(),
initialRoute: AppRoutes.splashPath,
// routes: {
// AppRoutes.notificationPath: (context) => const PageNotification(),
// AppRoutes.transactionsPath: (context) =>
// const PageTransactionsHistory(),
// },
onGenerateRoute: onGenerateRoute,
);
},
);
}
Route<dynamic> onGenerateRoute(RouteSettings settings) {
//routes to history
switch (settings.name) {
case AppRoutes.notificationPath:
return CustomRoute(
child: const PageNotification(
poppable: true,
),
animationStyle: PageAnimationStyle.fade,
);
default:
return CustomRoute(
child: const PageSplash(),
animationStyle: PageAnimationStyle.fade,
);
}
}
Future<void> _firebaseMessagingForegroundHandler(
RemoteMessage message,) async {
pp('foreground Notification was triggered');
pp(message.data.toString());
final data = message.data;
final String? type = data['type'];
final bool isMoneyIn = (type == 'Inflow') ||
(type == 'Funding');
NotificationController.createTransactionNotification(
isMoneyIn: isMoneyIn,
title: message.notification?.title ?? data['title'] ?? '',
body: message.notification?.body ?? data['body'] ?? '',
);
pp(type);
pp(isMoneyIn);
// Refresh account
sl<HomeRepository>().getAccount(const GetAccountParams());
}
}
//triggered in the background
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
pp('background Notification was triggered');
final data = message.data;
final String? type = data['type'];
final bool isMoneyIn = (type == 'Transaction') ||
(type == 'Funding');
NotificationController.createTransactionNotification(
isMoneyIn: isMoneyIn,
title: data['title'] ?? '',
body: data['body'] ?? '',
);
pp(type);
pp(isMoneyIn);
sl<HomeRepository>().getAccount(const GetAccountParams());
}
// /// Use this method to detect when the user taps on a notification or action button
@pragma("vm:entry-point")
Future<void> onActionReceivedMethod(ReceivedAction receivedAction) async {
if (receivedAction.channelKey == actionNotificationId) {
pp('---------------Am been called int e onAction method');
// Navigate to notifications
PageCatholicPay.navigatorKey.currentState?.push(
CustomRoute(
child: const PageNotification(),
animationStyle: PageAnimationStyle.fade,
),
);
}
}
解决方案
你使用了 NotificationCategory.Alarm 搭配 fullScreenIntent: true。
在Android上,将 Alarm 分类分配给推送通知,会指示移动操作系统将传入的推送通知像晨间闹钟或来电一样处理,从而使系统无限循环自定义音频资源,直到用户进行交互为止。
将分类从 NotificationCategory.Alarm 更改为诸如 NotificationCategory.Status 或 NotificationCategory.Notification 之类的标准分类类型(或完全省略它)。
看看是否有效。
在你的 NotificationController 中更新你的 createTransactionNotification 方法:
static Future<void> createTransactionNotification({
required bool isMoneyIn,
String? title,
String? body,
}) async {
final isAllowed = await _areNotificationsAllowed();
if (!isAllowed) return;
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: DateTime.now().millisecondsSinceEpoch.remainder(100000),
channelKey: isMoneyIn ? moneyInChannelId : normalTransactionChannelId,
title: title,
body: body,
summary: transactionNotifySummary,
notificationLayout: NotificationLayout.BigText,
// 1. If you don't need a full screen takeover, turn this off
fullScreenIntent: false,
wakeUpScreen: isMoneyIn,
// 2. Change the category here to stop the looping behavior
category: isMoneyIn ? NotificationCategory.Status : null,
),
);
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。