You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中audioplayers无法在workmanager的executeTask后台任务播放音频

解决Flutter后台任务中音频无法播放的问题

核心原因

workmanager的后台任务运行在隔离的后台环境中,Android/iOS对后台音频播放有严格的权限和会话限制:

  • Android 8.0+ 禁止后台任务直接播放音频,必须通过前台服务执行
  • iOS 需要配置后台音频模式并正确初始化音频会话
  • audioplayers默认配置不满足后台播放的权限要求

步骤1:配置平台权限

Android 配置(AndroidManifest.xml)

在android/app/src/main/AndroidManifest.xml中添加以下权限和服务声明:

<!-- 前台服务权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
<!-- 唤醒锁,防止设备休眠 -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>

<!-- 注册媒体播放前台服务(如果使用自定义服务) -->
<service
    android:name=".AudioPlaybackService"
    android:foregroundServiceType="mediaPlayback" />

iOS 配置(Info.plist)

在ios/Runner/Info.plist中添加后台模式和音频权限:

<key>UIBackgroundModes</key>
<array>
    <string>audio</string> <!-- 允许后台音频播放 -->
    <string>fetch</string> <!-- 允许后台任务刷新 -->
</array>
<key>NSMicrophoneUsageDescription</key>
<string>需要音频播放权限</string> <!-- 适配部分iOS版本的权限要求 -->

步骤2:修改音频播放配置(audio.dart)

调整audioplayers的音频会话配置,适配后台播放:

import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/foundation.dart';

class Audio {
  final String path;
  late AudioPlayer _player;

  Audio(this.path) {
    _player = AudioPlayer();
    _configureAudioSession();
  }

  Future<void> _configureAudioSession() async {
    if (kIsWeb) return;

    if (defaultTargetPlatform == TargetPlatform.android) {
      // 配置Android音频属性,标记为高优先级的闹钟类型
      await _player.setAudioAttributes(const AudioAttributes(
        contentType: AudioContentType.music,
        usage: AudioUsageType.alarm,
      ));
    } else if (defaultTargetPlatform == TargetPlatform.iOS) {
      // 配置iOS音频会话,允许后台播放并混合其他音频
      await _player.setIosAudioSessionCategory(
        IosAudioSessionCategory.playback,
        options: [
          IosAudioSessionCategoryOptions.mixWithOthers,
          IosAudioSessionCategoryOptions.allowAirPlay,
        ],
      );
    }
  }

  Future<void> play() async {
    try {
      await _player.play(AssetSource(path));
      // 播放完成后释放资源
      _player.onPlayerComplete.listen((event) {
        _player.dispose();
      });
    } catch (e) {
      print("音频播放失败:$e");
    }
  }
}

步骤3:适配Workmanager后台任务

由于Android后台限制,必须通过前台服务执行音频播放,推荐使用flutter_foreground_service包简化开发:

1. 添加依赖

在pubspec.yaml中添加:

dependencies:
  flutter_foreground_service: ^0.12.0 # 版本以最新官方发布为准

2. 修改main.dart的回调函数

import 'package:early_bird/functions/audio.dart';
import 'package:early_bird/screens/home_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_foreground_service/flutter_foreground_service.dart';
import 'package:workmanager/workmanager.dart';
import 'package:flutter/foundation.dart';

@pragma('vm:entry-point')
Future<void> callBack() async {
  Workmanager().executeTask((taskName, inputData) async {
    try {
      if (defaultTargetPlatform == TargetPlatform.android) {
        // 启动前台服务,确保Android允许后台播放音频
        await FlutterForegroundService.startService(
          title: "闹钟提醒",
          description: "正在播放闹钟音频",
          iconName: "ic_launcher", // 确保res/mipmap目录下存在该图标
        );
      }

      Audio audio = Audio('audio/sound.mp3');
      print('I am running');
      await audio.play();

      // 等待音频播放完成后停止前台服务(可根据实际音频时长调整延迟)
      await Future.delayed(const Duration(seconds: 10));
      if (defaultTargetPlatform == TargetPlatform.android) {
        await FlutterForegroundService.stopService();
      }

      return Future.value(true);
    } catch (err) {
      print("任务执行失败:$err");
      if (defaultTargetPlatform == TargetPlatform.android) {
        await FlutterForegroundService.stopService();
      }
      return Future.value(false);
    }
  });
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // 初始化前台服务(仅Android需要)
  if (defaultTargetPlatform == TargetPlatform.android) {
    await FlutterForegroundService.initialize();
  }
  await Workmanager().initialize(callBack, isInDebugMode: true);
  runApp(const App());
}

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      routes: {
        HomeScreen.routeName: (_) => HomeScreen(),
      },
    );
  }
}

额外注意事项

  1. Workmanager任务类型选择:如果是精确时间的闹钟,不要使用registerPeriodicTask(Android最小间隔15分钟,iOS限制更多),建议:
    • Android:结合原生AlarmManager与前台服务实现精确触发
    • iOS:使用UNNotificationRequest配合自定义通知音频
  2. iOS后台限制:iOS后台任务执行时间通常限制在30秒内,若音频较长,可通过本地通知引导用户点击后继续播放
  3. 测试技巧:Android测试后台任务时,不要直接强制杀死应用,应通过“最近应用”列表滑动关闭,避免系统终止所有后台进程

内容的提问来源于stack exchange,提问作者Sonet Adhikary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 21:34:56