Требование
При получении заказа:
- Воспроизводить непрерывный повторяющийся звук
- Включить повторяющуюся вибрацию
- Должно работать, даже если приложение полностью закрыто.
- Останавливаться только при взаимодействии пользователя (принять/отклонить)
Я использую:
Код: Выделить всё
firebase_messagingКод: Выделить всё
flutter_local_notifications- Встроенный Android ForegroundService (Kotlin)
- с USAGE_ALARM
Код: Выделить всё
MediaPlayer Код: Выделить всё
WakeLock- форма волны
Код: Выделить всё
Vibrator
Когда приложение закрыто:
- Приходит уведомление
- срабатывает
Код: Выделить всё
onMessageReceived() - Служба переднего плана запускается
- Но непрерывный звук НЕ воспроизводится
Код: Выделить всё
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
val data = remoteMessage.data
val sellerScreen = data["sellerScreen"]
val driverScreen = data["driverScreen"]
val orderId = data["orderId"]
val shouldPlaySound =
sellerScreen == "5" || driverScreen == "1"
if (shouldPlaySound) {
playNotificationSound(orderId)
}
}
private fun playNotificationSound(orderId: String?) {
val intent = Intent(this, OrderAlertForegroundService::class.java).apply {
action = OrderAlertForegroundService.ACTION_START
putExtra(OrderAlertForegroundService.EXTRA_ORDER_ID, orderId)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
}
}
Код: Выделить всё
class OrderAlertForegroundService : Service() {
private var mediaPlayer: MediaPlayer? = null
private var vibrator: Vibrator? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
startForeground(9999, createNotification())
startContinuousSound("order")
return START_NOT_STICKY
}
private fun startContinuousSound(soundFileName: String) {
val resourceId = resources.getIdentifier(
soundFileName,
"raw",
packageName
)
mediaPlayer = MediaPlayer.create(this, resourceId)?.apply {
setAudioAttributes(
AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ALARM)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build()
)
isLooping = true
start()
}
vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
val pattern = longArrayOf(0, 1000, 500)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator?.vibrate(
VibrationEffect.createWaveform(pattern, 0)
)
} else {
vibrator?.vibrate(pattern, 0)
}
}
override fun onDestroy() {
mediaPlayer?.stop()
mediaPlayer?.release()
vibrator?.cancel()
super.onDestroy()
}
}
Код: Выделить всё
FirebaseMessaging.onMessage.listen(_handleForeground);
FirebaseMessaging.onMessageOpenedApp.listen(_handleBackground);
FirebaseMessaging.instance.getInitialMessage().then(_handleInitial);
Код: Выделить всё
Future firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await OrderAlertChannel.startOrderAlert(
alertType: 'background_fcm',
orderId: message.data['orderId'] ?? 'unknown',
);
}
- Полезная нагрузка — это сообщение, содержащее только данные
Код: Выделить всё
priority: highКод: Выделить всё
content_available: true- Протестировано на Android 13.
- Уведомление службы переднего плана использует:
Код: Выделить всё
IMPORTANCE_HIGH Код: Выделить всё
CATEGORY_ALARMКод: Выделить всё
setOngoing(true)
Вопросы
- Ограничивает ли Android воспроизведение звука при полном закрытии приложения?
- Может ли служба переднего плана надежно запускаться из FirebaseMessagingService отключена состояние?
- Существует ли более правильный подход к реализации непрерывных уведомлений в стиле будильника, например Swiggy/Zomato?
- Следует ли это реализовать с использованием полноэкранного намерения + категории будильника вместо этого?
Я хочу, чтобы уведомление работало как настоящее оповещение о входящем заказе в стиле будильника, даже если:
- Приложение закрыто
- Экран выключен
- Устройство заблокировано
Подробнее здесь: https://stackoverflow.com/questions/798 ... -but-not-w
Мобильная версия