Flutter音频播放插件assets_audio_player_plus的使用
Flutter音频播放插件assets_audio_player_plus的使用
🎧 assets_audio_player_plus 🔊
注意:这是一个资产音频播放器的fork版本,主要目的是更新uuid包。可以从Flutter直接播放存储在assets文件中的音乐/音频(适用于Android、iOS、web、macOS)。
你还可以通过URL播放网络音频文件、直播流/电台以及本地文件。
通知可以在Android和iOS上显示,并且支持蓝牙操作。
flutter:
assets:
- assets/audios/
AssetsAudioPlayer.newPlayer().open(
Audio("assets/audios/song1.mp3"),
autoStart: true,
showNotification: true,
);
📥 导入
dependencies:
assets_audio_player_plus: ^3.0.8
适用于 flutter: ">=3.3.0"
,请确保升级SDK。
如果你喜欢这个包,请支持一下:
音频来源 | Android | iOS | Web | MacOS |
---|---|---|---|---|
🗄️ 资产文件路径 | ✅ | ✅ | ✅ | ✅ |
🌐 网络文件路径 | ✅ | ✅ | ✅ | ✅ |
📁 本地文件路径 | ✅ | ✅ | ✅ | ✅ |
📻 直播流/电台 | ✅ | ✅ | ✅ | ✅ |
功能 | Android | iOS | Web | MacOS |
---|---|---|---|---|
🎶 多个播放器 | ✅ | ✅ | ✅ | ✅ |
📀 播放列表 | ✅ | ✅ | ✅ | ✅ |
💬 系统通知 | ✅ | ✅ | 🚫 | 🚫 |
🎧 蓝牙操作 | ✅ | ✅ | 🚫 | 🚫 |
🔕 尊重静音模式 | ✅ | ✅ | 🚫 | 🚫 |
📞 电话中断暂停 | ✅ | ✅ | 🚫 | 🚫 |
命令 | Android | iOS | Web | MacOS |
---|---|---|---|---|
▶ 播放 | ✅ | ✅ | ✅ | ✅ |
⏸ 暂停 | ✅ | ✅ | ✅ | ✅ |
⏹ 停止 | ✅ | ✅ | ✅ | ✅ |
⏩ 快进(位置) | ✅ | ✅ | ✅ | ✅ |
⏪⏩ 快进快退 | ✅ | ✅ | ✅ | ✅ |
⏩ 加速播放 | ✅ | ✅ | ✅ | ✅ |
⏪ 减速播放 | ✅ | ✅ | ✅ | ✅ |
⏭ 下一首 | ✅ | ✅ | ✅ | ✅ |
⏮ 上一首 | ✅ | ✅ | ✅ | ✅ |
小部件 | Android | iOS | Web | MacOS |
---|---|---|---|---|
🐦 音频小部件 | ✅ | ✅ | ✅ | ✅ |
🐦 小部件构建器 | ✅ | ✅ | ✅ | ✅ |
🐦 音频播放器构建扩展 | ✅ | ✅ | ✅ | ✅ |
属性 | Android | iOS | Web | MacOS |
---|---|---|---|---|
🔁 循环播放 | ✅ | ✅ | ✅ | ✅ |
🔀 混洗播放 | ✅ | ✅ | ✅ | ✅ |
🎤 设置/获取音量 | ✅ | ✅ | ✅ | ✅ |
⏩ 设置/获取播放速度 | ✅ | ✅ | ✅ | ✅ |
⏩ 设置/获取音调 | ✅ | 🚫 | 🚫 | 🚫 |
监听器 | Android | iOS | Web | MacOS |
---|---|---|---|---|
🦻 准备完成监听 | ✅ | ✅ | ✅ | ✅ |
🦻 当前位置监听 | ✅ | ✅ | ✅ | ✅ |
🦻 播放结束监听 | ✅ | ✅ | ✅ | ✅ |
🦻 缓冲监听 | ✅ | ✅ | ✅ | ✅ |
🦻 音量监听 | ✅ | ✅ | ✅ | ✅ |
🦻 播放速度监听 | ✅ | ✅ | ✅ | ✅ |
🦻 音调监听 | ✅ | 🚫 | 🚫 | 🚫 |
📁 导入assets文件
无需将歌曲复制到媒体缓存中,通过assets_audio_player可以直接从assets目录打开它们。
- 在你的assets目录下创建一个音频文件夹(名称不限于“audios”)。
- 在
pubspec.yaml
中声明它:
flutter:
assets:
- assets/audios/
🛠️ 开始使用
final assetsAudioPlayer = AssetsAudioPlayer();
assetsAudioPlayer.open(
Audio("assets/audios/song1.mp3"),
);
你也可以播放来自URL的网络歌曲:
final assetsAudioPlayer = AssetsAudioPlayer();
try {
await assetsAudioPlayer.open(
Audio.network("http://www.mysite.com/myMp3file.mp3"),
);
} catch (t) {
// mp3不可达
}
播放来自URL的直播流/电台: 注意:与网络不同,如果暂停/播放,直播流会继续播放到当前时间点。
final assetsAudioPlayer = AssetsAudioPlayer();
try {
await assetsAudioPlayer.open(
Audio.liveStream(MY_LIVESTREAM_URL),
);
} catch (t) {
// 流不可达
}
播放来自文件的歌曲:
final assetsAudioPlayer = AssetsAudioPlayer();
assetsAudioPlayer.open(
Audio.file(FILE_URI),
);
对于文件URI,请参考 https://pub.dev/packages/path_provider。
assetsAudioPlayer.playOrPause();
assetsAudioPlayer.play();
assetsAudioPlayer.pause();
assetsAudioPlayer.seek(Duration to);
assetsAudioPlayer.seekBy(Duration by);
assetsAudioPlayer.forwardRewind(double speed);
// 如果正值,则快进;如果是负值,则快退
assetsAudioPlayer.stop();
通知
在iOS上,它会使用MPNowPlayingInfoCenter
。
- 在音频中添加元数据:
final audio = Audio.network("/assets/audio/country.mp3",
metas: Metas(
title: "Country",
artist: "Florent Champigny",
album: "CountryAlbum",
image: MetasImage.asset("assets/images/country.jpg"), // 可以是MetasImage.network
),
);
- 打开时设置
showNotification: true
:
_player.open(audio, showNotification: true)
自定义通知
自定义图标(仅限Android)
通过资源名称:
确保你已经将这些图标添加到android/res/drawable
目录下(不是Flutter assets!)。
await _assetsAudioPlayer.open(
myAudio,
showNotification: true,
notificationSettings: NotificationSettings(
customStopIcon: AndroidResDrawable(name: "ic_stop_custom"),
customPauseIcon: AndroidResDrawable(name:"ic_pause_custom"),
customPlayIcon: AndroidResDrawable(name:"ic_play_custom"),
customPrevIcon: AndroidResDrawable(name:"ic_prev_custom"),
customNextIcon: AndroidResDrawable(name:"ic_next_custom"),
)
);
不要忘记在发布模式下告诉ProGuard保留这些资源:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@drawable/ic_next_custom, @drawable/ic_prev_custom, @drawable/ic_pause_custom, @drawable/ic_play_custom, @drawable/ic_stop_custom"/>
通过清单文件:
- 将图标添加到Android的
res
目录(android/app/src/main/res)。 - 在
AndroidManifest.xml
中引用该图标:
<meta-data
android:name="assets.audio.player.notification.icon"
android:resource="@drawable/ic_music_custom"/>
你还可以更改动作图标:
<meta-data
android:name="assets.audio.player.notification.icon.play"
android:resource="@drawable/ic_play_custom"/>
<meta-data
android:name="assets.audio.player.notification.icon.pause"
android:resource="@drawable/ic_pause_custom"/>
<meta-data
android:name="assets.audio.player.notification.icon.stop"
android:resource="@drawable/ic_stop_custom"/>
<meta-data
android:name="assets.audio.player.notification.icon.next"
android:resource="@drawable/ic_next_custom"/>
<meta-data
android:name="assets.audio.player.notification.icon.prev"
android:resource="@drawable/ic_prev_custom"/>
处理通知点击(仅限Android)
在主程序中添加:
AssetsAudioPlayer.setupNotificationsOpenAction((notification) {
// 自定义操作
return true; // true:已处理,不通知其他监听器
// false:启用其他监听器处理
});
如果想在小部件中添加自定义操作:
AssetsAudioPlayer.addNotificationOpenAction((notification) {
// 自定义操作
return false; // true:已处理,不通知其他监听器
// false:启用其他监听器处理
});
自定义操作
你可以启用或禁用通知操作:
open(AUDIO,
showNotification: true,
notificationSettings: NotificationSettings(
prevEnabled: false, // 禁用上一首按钮
// 具有自定义下一首操作(禁用默认操作)
customNextAction: (player) {
print("next");
}
)
)
更新音频元数据/通知内容
在音频创建后,只需调用以下方法:
audio.updateMetas(
player: _assetsAudioPlayer, // 添加正在播放的播放器
title: "我的新标题",
artist: "我的新艺术家",
// 如果不提供新专辑,则保留旧专辑
image: MetasImage.network(
// 我的新图片URL
),
);
蓝牙操作
必须启用通知才能使其工作。
可用远程命令:
- 播放/暂停
- 下一首
- 上一首
- 停止
耳机策略
(目前仅适用于Android)
在打开歌曲/播放列表时添加策略:
assetsAudioPlayer.open(
...
headPhoneStrategy: HeadPhoneStrategy.pauseOnUnplug,
// headPhoneStrategy: HeadPhoneStrategy.none, // 默认
// headPhoneStrategy: HeadPhoneStrategy.pauseOnUnplugPlayOnPlug,
)
如果要在蓝牙上也启用此功能,你需要在AndroidManifest.xml
中添加BLUETOOTH权限:
<uses-permission android:name="android.permission.BLUETOOTH" />
连接多个播放器
你可以通过AssetsAudioPlayer.newPlayer()
创建新的播放器,这将在不同的原生MediaPlayer中播放歌曲。
这样可以实现同时播放多首歌曲:
/// 并行播放3首歌曲
AssetsAudioPlayer.newPlayer().open(
Audio("assets/audios/song1.mp3")
);
AssetsAudioPlayer.newPlayer().open(
Audio("assets/audios/song2.mp3")
);
// 另一种方式,创建、打开、播放并销毁播放器
AssetsAudioPlayer.playAndForget(
Audio("assets/audios/song3.mp3")
);
每个播放器都有一个唯一生成的id
,你可以通过以下方式检索或手动创建:
final player = AssetsAudioPlayer.withId(id: "MY_UNIQUE_ID");
播放列表
assetsAudioPlayer.open(
Playlist(
audios: [
Audio("assets/audios/song1.mp3"),
Audio("assets/audios/song2.mp3")
]
),
loopMode: LoopMode.playlist // 循环整个播放列表
);
assetsAudioPlayer.next();
assetsAudioPlayer.prev();
assetsAudioPlayer.playlistPlayAtIndex(1);
音频小部件
如果你想用更Flutter的方式来播放音频,可以尝试AudioWidget
!
// 在StatefulWidget中
bool _play = false;
@override
Widget build(BuildContext context) {
return AudioWidget.assets(
path: "assets/audios/country.mp3",
play: _play,
child: RaisedButton(
child: Text(
_play ? "pause" : "play",
),
onPressed: () {
setState(() {
_play = !_play;
});
}
),
onReadyToPlay: (duration) {
// onReadyToPlay
},
onPositionChanged: (current, duration) {
// onPositionChanged
},
);
}
如何停止AudioWidget
?
只需从树中移除音频组件!或者简单地保持play: false
。
监听器
所有监听器都暴露为Streams。
使用RxDart,AssetsAudioPlayer
将某些监听器作为ValueObservable
(可同步访问上次发出项的Observable)公开。
当前歌曲
// 当前播放的音频,包含总歌曲时长
assetsAudioPlayer.current // ValueObservable<PlayingAudio>
// 直接获取当前播放的资产
final PlayingAudio playing = assetsAudioPlayer.current.value;
// 监听当前播放的歌曲
assetsAudioPlayer.current.listen((playingAudio){
final asset = playingAudio.assetAudio;
final songDuration = playingAudio.duration;
})
当前歌曲时长
// 监听当前播放的歌曲
final duration = assetsAudioPlayer.current.value.duration;
当前位置(秒)
assetsAudioPlayer.currentPosition // ValueObservable<Duration>
// 直接获取当前歌曲位置
final Duration position = assetsAudioPlayer.currentPosition.value;
return StreamBuilder(
stream: assetsAudioPlayer.currentPosition,
builder: (context, asyncSnapshot) {
final Duration duration = asyncSnapshot.data;
return Text(duration.toString());
}),
或者使用PlayerBuilder
:
PlayerBuilder.currentPosition(
player: _assetsAudioPlayer,
builder: (context, duration) {
return Text(duration.toString());
}
)
或者Player Builder Extension
:
_assetsAudioPlayer.builderCurrentPosition(
builder: (context, duration) {
return Text(duration.toString());
}
)
是否正在播放
// 表示当前MediaPlayer播放状态的布尔值观察者
assetsAudioPlayer.isPlaying // ValueObservable<bool>
// 直接获取当前播放器状态
final bool playing = assetsAudioPlayer.isPlaying.value;
// 将跟随`AssetsAudioPlayer`的播放状态
return StreamBuilder(
stream: assetsAudioPlayer.isPlaying,
builder: (context, asyncSnapshot) {
final bool isPlaying = asyncSnapshot.data;
return Text(isPlaying ? "Pause" : "Play");
}),
或者使用PlayerBuilder
:
PlayerBuilder.isPlaying(
player: _assetsAudioPlayer,
builder: (context, isPlaying) {
return Text(isPlaying ? "Pause" : "Play");
}
)
或者Player Builder Extension
:
_assetsAudioPlayer.builderIsPlaying(
builder: (context, isPlaying) {
return Text(isPlaying ? "Pause" : "Play");
}
)
音量
// 更改音量(0.0至1.0之间)
assetsAudioPlayer.setVolume(0.5);
媒体播放器可以遵循系统的“静音模式”(振动、静音、正常)。只需将respectSilentMode
可选参数设置为true
即可:
_player.open(PLAYABLE, respectSilentMode: true);
监听音量:
return StreamBuilder(
stream: assetsAudioPlayer.volume,
builder: (context, asyncSnapshot) {
final double volume = asyncSnapshot.data;
return Text("volume : $volume");
}),
或者使用PlayerBuilder
:
PlayerBuilder.volume(
player: _assetsAudioPlayer,
builder: (context, volume) {
return Text("volume : $volume");
}
)
播放完成
当当前歌曲播放完毕时触发:
assetsAudioPlayer.playlistAudioFinished // ValueObservable<Playing>
assetsAudioPlayer.playlistAudioFinished.listen((Playing playing){
})
当整个播放列表播放完毕时触发:
assetsAudioPlayer.playlistFinished // ValueObservable<bool>
assetsAudioPlayer.playlistFinished.listen((finished){
})
循环模式
final LoopMode loopMode = assetsAudioPlayer.loop;
// 可能的值
// LoopMode.none : 不循环
// LoopMode.single : 循环单个音频
// LoopMode.playlist : 循环整个播放列表
assetsAudioPlayer.setLoopMode(LoopMode.single);
assetsAudioPlayer.loopMode.listen((loopMode){
// 监听循环模式
})
assetsAudioPlayer.toggleLoop(); // 切换循环模式
播放速度
assetsAudioPlayer.setPlaySpeed(1.5);
assetsAudioPlayer.playSpeed.listen((playSpeed){
// 监听播放速度
})
// 为特定音频更改播放速度
Audio audio = Audio.network(
url,
playSpeed: 1.5
);
assetsAudioPlayer.open(audio);
音调
assetsAudioPlayer.setPitch(1.2);
assetsAudioPlayer.pitch.listen((pitch){
// 监听音调
})
// 为特定音频更改音调
Audio audio = Audio.network(
url,
pitch: 1.2
);
assetsAudioPlayer.open(audio);
错误处理
默认情况下,播放错误时会停止音频。
但你可以添加自定义行为:
_player.onErrorDo = (handler){
handler.player.stop();
};
打开另一首音频:
_player.onErrorDo = (handler){
handler.player.open(ANOTHER_AUDIO);
};
尝试在同一位置重新打开:
_player.onErrorDo = (handler){
handler.player.open(
handler.playlist.copyWith(
startIndex: handler.playlistIndex
),
seek: handler.currentPosition
);
};
网络策略(Android/iOS/macOS)
Android只允许HTTPS调用,如果使用HTTP会报错,请记得添加INTERNET权限并在AndroidManifest.xml
中设置usesCleartextTraffic="true"
:
<uses-permission android:name="android.permission.INTERNET" />
<application
...
android:usesCleartextTraffic="true"
...>
...
</application>
iOS只允许HTTPS调用,如果使用HTTP会报错,请编辑info.plist
并设置NSAppTransportSecurity
为NSAllowsArbitraryLoads
:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
在macOS上启用HTTP调用,需要在info.plist
中添加输入/输出调用能力:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
<string>fetch</string>
</array>
<key>com.apple.security.network.client</key>
<true/>
并在Runner/DebugProfile.entitlements
中添加:
<key>com.apple.security.network.client</key>
<true/>
完整的Runner/DebugProfile.entitlements
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>
更多关于Flutter音频播放插件assets_audio_player_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
assets_audio_player_plus
是一个用于在 Flutter 应用中播放音频文件的插件,特别适合播放存储在应用 assets
目录中的音频文件。它提供了简单的 API 来控制音频的播放、暂停、停止、音量调节等功能。
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 assets_audio_player_plus
依赖:
dependencies:
flutter:
sdk: flutter
assets_audio_player_plus: ^3.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
2. 添加音频文件到 assets
在 pubspec.yaml
文件中,确保你已经将音频文件添加到 assets
目录中:
flutter:
assets:
- assets/audio/sample.mp3
3. 使用 AssetsAudioPlayer
播放音频
以下是一个简单的示例,展示如何使用 assets_audio_player_plus
播放音频文件:
import 'package:flutter/material.dart';
import 'package:assets_audio_player_plus/assets_audio_player_plus.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: AudioPlayerScreen(),
);
}
}
class AudioPlayerScreen extends StatefulWidget {
[@override](/user/override)
_AudioPlayerScreenState createState() => _AudioPlayerScreenState();
}
class _AudioPlayerScreenState extends State<AudioPlayerScreen> {
final AssetsAudioPlayer _assetsAudioPlayer = AssetsAudioPlayer();
[@override](/user/override)
void initState() {
super.initState();
_initAudioPlayer();
}
void _initAudioPlayer() async {
await _assetsAudioPlayer.open(
Audio("assets/audio/sample.mp3"),
autoStart: false,
showNotification: true,
);
}
[@override](/user/override)
void dispose() {
_assetsAudioPlayer.dispose();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Audio Player'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
StreamBuilder<bool>(
stream: _assetsAudioPlayer.isPlaying,
builder: (context, snapshot) {
final isPlaying = snapshot.data ?? false;
return IconButton(
icon: Icon(isPlaying ? Icons.pause : Icons.play_arrow),
onPressed: () {
if (isPlaying) {
_assetsAudioPlayer.pause();
} else {
_assetsAudioPlayer.play();
}
},
);
},
),
StreamBuilder<Duration>(
stream: _assetsAudioPlayer.currentPosition,
builder: (context, snapshot) {
final position = snapshot.data ?? Duration.zero;
return Text('Position: ${position.inSeconds} seconds');
},
),
StreamBuilder<Duration>(
stream: _assetsAudioPlayer.currentDuration,
builder: (context, snapshot) {
final duration = snapshot.data ?? Duration.zero;
return Text('Duration: ${duration.inSeconds} seconds');
},
),
],
),
),
);
}
}