Звук фонового уведомления Flutter Firebase не прекращается, когда приложение неактивноAndroid

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Звук фонового уведомления Flutter Firebase не прекращается, когда приложение неактивно

Сообщение Anonymous »

Я работаю над приложением Flutter для компании по заказу еды на облачной кухне. Приложение использует Firebase Cloud Messaging (FCM) для отправки уведомлений при поступлении нового заказа. Звук воспроизводится при каждом получении уведомления независимо от того, активно ли приложение, находится в фоновом режиме или полностью неактивно.
Ожидаемое поведение:
  • Звук должен прекращаться, когда пользователь нажимает на уведомление, независимо от того, находится ли приложение на переднем плане, в фоновом режиме или неактивно.
Проблема:
  • Если приложение активно или находится в фоновом режиме, звук корректно прекращается при нажатии на уведомление.
  • Однако, если приложение неактивно (не на экране или закрыто), звук продолжает воспроизводиться бесконечно, потому что аудиоплеер не останавливается.
Похоже, что приложение не может получить доступ к аудиоплееру, когда он неактивен, и я пытаюсь реализовать решение, которое правильно обрабатывает этот сценарий.
Вот код, который я использовал для реализации уведомлений FCM и управления аудиоплеером:

main.dart

import 'dart:developer';
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:maalik/app.dart';
import 'package:maalik/services/firebase_api.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'firebase_options.dart';
import 'package:flutter/material.dart';

String? fcmToken;

void main() async {
WidgetsFlutterBinding.ensureInitialized();

await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseMessaging.instance.getInitialMessage();

await NotificationServices.initLocalNotification();

final notificationServices = NotificationServices();
fcmToken = await notificationServices.initFcmNotification();

FlutterError.onError = (errorDetails) {
FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
};
PlatformDispatcher.instance.onError = (error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true;
};
FirebaseCrashlytics.instance.app.setAutomaticDataCollectionEnabled(false);
await SharedPreferences.getInstance().then((value) {
runApp(const MyApp());
});
FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);

NotificationServices().listenNotification();

FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
log('Notification clicked: ${message.notification}');
_stopAudio(); // Stop the audio when notification is tapped
});
}

@pragma('vm:entry-point')
Future _stopAudio() async {
try {
if (player != null) {
await player!.stop();
await player!.release();
player = null;
log("Audio stopped from background notification");
}
} catch (e) {
log("Error stopping audio: $e");
}
}

@pragma('vm:entry-point')
Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
log('Raw Message Data: ${message.data}');
log('Message Origin: ${message.senderId}');
log("Handling background message: ${message.notification}");
if (message.data['channelId'] == 'order_received') {
audioPlayerStart();
}
}

firebase_api.dart

import 'dart:developer';
import 'package:audioplayers/audioplayers.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:maalik/main.dart';
import 'package:sound_mode/sound_mode.dart';
import 'package:volume_controller/volume_controller.dart';

AudioPlayer? player;

class NotificationServices {
final _firebaseMessaging = FirebaseMessaging.instance;
static final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();

static Future initLocalNotification({bool isScheduled = false}) async {
final androidInit = AndroidInitializationSettings('@mipmap/launcher_icon');
final iosInit = DarwinInitializationSettings();
final initSetting = InitializationSettings(android: androidInit, iOS: iosInit);

await _flutterLocalNotificationsPlugin.initialize(
initSetting,
onDidReceiveNotificationResponse: (NotificationResponse response) async {
log("Notification clicked: ${response.payload}");
if (player != null) {
await player!.stop();
await player!.release();
player = null;
log("Audio stopped");
}
},
onDidReceiveBackgroundNotificationResponse: _backgroundNotificationHandler,
);

log("inside initlocalNotification");
AndroidNotificationChannel orderReceiveChannel = AndroidNotificationChannel(
'order_received',
'Order Notification Channel',
description: 'Order Notification Channel',
enableVibration: true,
importance: Importance.max,
playSound: false,
sound: RawResourceAndroidNotificationSound('notification'),
);

const AndroidNotificationChannel otherNotificationChannel =
AndroidNotificationChannel(
'other_notification',
'Other Notification Channel',
description: 'Other Notification Channel',
enableVibration: true,
importance: Importance.max,
playSound: true,
);

await _flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation()
?.createNotificationChannel(orderReceiveChannel);
await _flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation()
?.createNotificationChannel(otherNotificationChannel);
}

Future initFcmNotification() async {
validateSoundFile();
try {
await _firebaseMessaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
log("inside request permission");
} catch (e) {
print(e);
}
try {
final fcmToken = await _firebaseMessaging.getToken();
log('fcmToken: $fcmToken');
return fcmToken;
} catch (e) {
print(e);
}
return '';
}

listenNotification() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
log("inside listenNotification");
if (message.data['channelId'] == 'order_received') {
audioPlayerStart();
}
if (notification != null && android != null) {
AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
message.data['channelId'] ?? 'other_notification',
'Order Notification Channel',
playSound: false,
sound: RawResourceAndroidNotificationSound('notification'),
priority: Priority.max,
);

DarwinNotificationDetails iosDetails = DarwinNotificationDetails(
sound: 'notification.wav',
);

NotificationDetails notificationDetails = NotificationDetails(
android: androidDetails,
iOS: iosDetails,
);

_flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
notificationDetails,
);
}
});
}
}

@pragma('vm:entry-point')
void audioPlayerStart() async {
try {
var ringer_mode = await SoundMode.ringerModeStatus;

if (ringer_mode.name == 'normal') {
VolumeController volumeController = VolumeController();
volumeController.maxVolume(showSystemUI: false);

if (player == null) {
player = AudioPlayer(playerId: "customNotificationPlayer");
await player?.setVolume(1.0);
}

if (player != null) {
await player!.play(AssetSource('notification.mp3'));

await Future.delayed(Duration(minutes: 2));

await player!.stop();
await player!.release();
await player!.dispose();

player = null;
}
}
} catch (e) {
print("Error playing sound: $e");
}
}

@pragma('vm:entry-point')
void _backgroundNotificationHandler(NotificationResponse response) {
log("Background notification clicked");
_stopAudio();
}


Подробнее здесь: https://stackoverflow.com/questions/793 ... s-inactive
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Android»