我想在我的 flutter 应用程序在后台时播放铃声,并让用户停止它。
我想在用户选择的特定时间间隔(例如3分钟或58分钟)后播放铃声,然后用户应该能够停止铃声。当 flutter 应用程序位于前台时,此功能有效,但当应用程序位于后台时(例如,当屏幕关闭时)则无效。
我目前正在使用 Flutter Workmanager 插件的回调Dispatcher,它会创建一个新的 Isolate。我们称之为 isolate B,以区别于 flutter 启动我的应用程序时创建的 isolate A。
这是回调调度程序:
void callbackDispatcher() {
print('callbackDispatcher');
FlutterRingtonePlayer.play(
android: AndroidSounds.ringtone,
ios: IosSounds.glass,
looping: false,
// Android only - API >= 28
volume: 1,
// Android only - API >= 28
asAlarm: true, // Android only - all APIs
);
return Future.value(true);
});
}
问题是我可以开始播放隔离 B 中的铃声,但我不知道如何让用户停止它。
到目前为止我已经尝试过:
我不知道如何与 Workmanager 创建的 Isolate B 进行通信,而且他们的文档似乎没有指定如何与创建的新 Isolate 进行通信...
我还能尝试什么?我唯一的目标是在后台模式下播放铃声并让用户停止它。
我有同样的问题(但是,使用 android 警报管理器包而不是 workmanager - 但是,我相信这个概念仍然是相同的)。我可以按如下方式解决。
隔离就像线程,但不共享内存 - 从这个意义上说,它们类似于 Linux/Unix 进程。因此,FlutterRingtonePlayer 内部的全局/静态在两个隔离中并不相同 - 它们是两个不同的实例。因此,我们需要使用消息来在隔离体之间进行通信。
我们可以使用 ReceivePort 和 SendPort 在两个隔离区之间进行通信。我们需要在后台isolate中运行的回调中定义一个ReceivePort(dart:isolate包)。我们需要在 IsolateNameServer (dart:ui) 中注册与该接收端口 (
我能够通过使用端口通信在隔离区之间发送消息来解决此问题。
监听端口消息可能采用
main
方法
final String portName = 'myUniquePortName';
ReceivePort receiver = ReceivePort();
IsolateNameServer.registerPortWithName(receiver.sendPort, portName);
receiver.listen((message) async {
if (message == "stop") {
await FlutterRingtonePlayer.stop()
}
});
使用
stopAudio
方法向 Isolate 发送停止消息。
Future<void> stopAudio() async {
IsolateNameServer.lookupPortByName(isolateName)?.send("stop");
await FlutterRingtonePlayer.stop();
}
最初在这里回答:https://github.com/inway/flutter_ringtone_player/issues/7#issuecomment-1012971949
我也是,我也遇到了 Android 警报管理器和音频播放器的问题,但我像这样修复了它:
stopTheSound() async {
await AndroidAlarmManager.oneShot(Duration(seconds: 0), 4, stopSound,
exact: true, wakeup: true, alarmClock: true, allowWhileIdle: true);
}
static stopSound() async {
if (MyApp.isPlaying) {
var res = await audioPlugin.stop();
if (res == 1) {
MyApp.isPlaying = false;
}
}
}
我使用警报管理器来调用声音,所以我再次使用它来停止它。
要停止声音,请使用以下代码
import 'dart:developer' as developer;
import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
import 'package:flutter_ringtone_player/flutter_ringtone_player.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const AlarmManagerExampleApp());
}
class AlarmManagerExampleApp extends StatelessWidget {
const AlarmManagerExampleApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: const Color(0x9f4376f8),
),
home: const _AlarmHomePage(),
);
}
}
class _AlarmHomePage extends StatefulWidget {
const _AlarmHomePage({Key? key}) : super(key: key);
@override
_AlarmHomePageState createState() => _AlarmHomePageState();
}
class _AlarmHomePageState extends State<_AlarmHomePage> {
int alarmId = 1;
Future<void> scheduleAlarm() async {
await AndroidAlarmManager.oneShot(
const Duration(microseconds: 0),
alarmId,
callback,
rescheduleOnReboot: true,
exact: true,
wakeup: true,
);
}
Future<void> scheduleCancelAlarm() async {
await AndroidAlarmManager.oneShot(
const Duration(microseconds: 0),
alarmId,
stopcallback,
rescheduleOnReboot: true,
exact: true,
wakeup: true,
);
}
@pragma('vm:entry-point')
static Future<void> callback() async {
developer.log('Alarm fired!');
FlutterRingtonePlayer.playAlarm(
looping: true,
asAlarm: false,
volume: 1.0,
);
}
@pragma('vm:entry-point')
static Future<void> stopcallback() async {
developer.log('Alarm stop!');
AndroidAlarmManager.cancel(1);
FlutterRingtonePlayer.stop();
}
@override
Widget build(BuildContext context) {
final textStyle = Theme.of(context).textTheme.bodySmall;
return Scaffold(
appBar: AppBar(
title: const Text('Android alarm manager plus example'),
elevation: 4,
actions: [
IconButton(
onPressed: () {
scheduleCancelAlarm();
},
icon: const Icon(Icons.stop),
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Alarm fired times',
style: textStyle,
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () async {
await scheduleAlarm();
},
child: const Text('Schedule OneShot Alarm'),
),
],
),
),
);
}
}
这是完整代码
使用2插件
android_alarm_manager_plus: ^3.0.1
flutter_ringtone_player: ^3.2.0