? assets_audio_player ?
直接从 Flutter 播放 assets 文件中存储的音乐/音频(同时播放)(android / ios / web / macos)。
您还可以使用 URL 播放网络音频文件、**广播/直播流** 和 **本地文件**。
可以在 Android 和 iOS 上显示通知,并处理蓝牙操作。
flutter:
assets:
- assets/audios/
AssetsAudioPlayer.newPlayer().open(
Audio("assets/audios/song1.mp3"),
autoPlay: true,
showNotification: true,
);
? 导入
dependencies:
assets_audio_player: ^3.0.6
or
assets_audio_player:
git:
url: https://github.com/florent37/Flutter-AssetsAudioPlayer.git
ref: master
ref can be latest commit id.
兼容 `flutter: ">=1.12.13+hotfix.6 <2.0.0"`,请确保升级您的 SDK。
喜欢这个插件?请我喝杯咖啡?
| 音频来源 | Android | iOS | Web | MacOS |
|---|---|---|---|---|
| ?️ 资源文件 (资源路径) | ✅ | ✅ | ✅ | ✅ |
| ? 网络文件 (URL) | ✅ | ✅ | ✅ | ✅ |
| ? 本地文件 (路径) | ✅ | ✅ | ✅ | ✅ |
| ? 网络直播流 / 广播 (URL) (默认, HLS, Dash, SmoothStream) | ✅ | ✅ | ✅ | ✅ |
| 功能 | Android | iOS | Web | MacOS |
|---|---|---|---|---|
| ? 多个播放器 | ✅ | ✅ | ✅ | ✅ |
| ? 打开播放列表 | ✅ | ✅ | ✅ | ✅ |
| ? 系统通知 | ✅ | ✅ | ? | ? |
| ? 蓝牙操作 | ✅ | ✅ | ? | ? |
| ? 尊重系统静音模式 | ✅ | ✅ | ? | ? |
| ? 来电时暂停 | ✅ | ✅ | ? | ? |
| 命令 | Android | iOS | Web | MacOS |
|---|---|---|---|---|
| ▶ 播放 | ✅ | ✅ | ✅ | ✅ |
| ⏸ 暂停 | ✅ | ✅ | ✅ | ✅ |
| ⏹ 停止 | ✅ | ✅ | ✅ | ✅ |
| ⏩ 跳转(位置) | ✅ | ✅ | ✅ | ✅ |
| ⏪⏩ 按增量跳转(位置) | ✅ | ✅ | ✅ | ✅ |
| ⏩ 快进(速度) | ✅ | ✅ | ✅ | ✅ |
| ⏪ 快退(速度) | ✅ | ✅ | ✅ | ✅ |
| ⏭ 下一首 | ✅ | ✅ | ✅ | ✅ |
| ⏮ 上一首 | ✅ | ✅ | ✅ | ✅ |
| 小部件 | Android | iOS | Web | MacOS |
|---|---|---|---|---|
| ? 音频小部件 | ✅ | ✅ | ✅ | ✅ |
| ? 小部件构建器 | ✅ | ✅ | ✅ | ✅ |
| ? AudioPlayer 构建器扩展 | ✅ | ✅ | ✅ | ✅ |
| 属性 | Android | iOS | Web | MacOS |
|---|---|---|---|---|
| ? 循环 | ✅ | ✅ | ✅ | ✅ |
| ? 随机播放 | ✅ | ✅ | ✅ | ✅ |
| ? 获取/设置音量 | ✅ | ✅ | ✅ | ✅ |
| ⏩ 获取/设置播放速度 | ✅ | ✅ | ✅ | ✅ |
| ⏩ 获取/设置音高 | ✅ | ? | ? | ? |
| 监听器 | Android | iOS | Web | MacOS |
|---|---|---|---|---|
| ? 准备就绪监听器(完成时长) | ✅ | ✅ | ✅ | ✅ |
| ? 当前位置监听器 | ✅ | ✅ | ✅ | ✅ |
| ? 完成监听器 | ✅ | ✅ | ✅ | ✅ |
| ? 缓冲监听器 | ✅ | ✅ | ✅ | ✅ |
| ? 音量监听器 | ✅ | ✅ | ✅ | ✅ |
| ? 播放速度监听器 | ✅ | ✅ | ✅ | ✅ |
| ? 音高监听器 | ✅ | ? | ? | ? |
? 导入资源文件
无需将歌曲复制到媒体缓存,使用 `assets_audio_player`,您可以直接从资源中打开它们。
- 在您的资源中创建一个音频目录(不一定是“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 unreachable
}
通过 URL 播放**直播流 / 广播**。
与网络音频的主要区别在于,如果您暂停/播放,直播流将恢复到当前时长。
final assetsAudioPlayer = AssetsAudioPlayer();
try {
await assetsAudioPlayer.open(
Audio.liveStream(MY_LIVESTREAM_URL),
);
} catch (t) {
//stream unreachable
}
以及播放**本地文件歌曲**。
//create a new player
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);
//if positive, forward, if negative, rewind
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"), //can be MetasImage.network
),
);
- 使用 `showNotification: true` 打开。
_player.open(audio, showNotification: true)
自定义通知
自定义图标(仅限 Android)
通过资源名称
确保您已将这些图标添加到 `android/res/drawable` 目录中,**而不是 Flutter 资源中!!!!**
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 在发布模式下保留这些资源。
(保留资源部分)
https://sites.google.com/a/android.com/tools/tech-docs/new-build-system/resource-shrinking
<?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(android/app/src/main/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)
在 main 中添加。
AssetsAudioPlayer.setupNotificationsOpenAction((notification) {
//custom action
return true; //true : handled, does not notify others listeners
//false : enable others listeners to handle it
});
然后,如果您想要一个自定义的小部件操作。
AssetsAudioPlayer.addNotificationOpenAction((notification) {
//custom action
return false; //true : handled, does not notify others listeners
//false : enable others listeners to handle it
});
自定义操作
您可以启用/禁用通知操作。
open(AUDIO,
showNotification: true,
notificationSettings: NotificationSettings(
prevEnabled: false, //disable the previous button
//and have a custom next action (will disable the default action)
customNextAction: (player) {
print("next");
}
)
)
更新音频的元数据 / 通知内容
在创建音频后,只需调用。
audio.updateMetas(
player: _assetsAudioPlayer, //add the player if the audio is actually played
title: "My new title",
artist: "My new artist",
//if I not provide a new album, it keep the old one
image: MetasImage.network(
//my new image url
),
);
蓝牙操作
您必须启用通知才能使其正常工作。
可用的远程命令
- 播放 / 暂停
- 下一步
- 上一首
- 停止
耳机策略
(目前仅适用于 Android)
在打开歌曲/播放列表时,添加一个策略。
assetsAudioPlayer.open(
...
headPhoneStrategy: HeadPhoneStrategy.pauseOnUnplug,
//headPhoneStrategy: HeadPhoneStrategy.none, //default
//headPhoneStrategy: HeadPhoneStrategy.pauseOnUnplugPlayOnPlug,
)
如果要使其也能在蓝牙上工作,您需要在 AndroidManifest.xml 中添加 BLUETOOTH 权限。
<uses-permission android:name="android.permission.BLUETOOTH" />
⛓ 并行 / 同时播放
您可以使用 `AssetsAudioPlayer.newPlayer()` 创建新的 `AssetsAudioPlayer`,它将在不同的原生媒体播放器中播放歌曲。
这将使您可以同时播放两首歌曲。
您可以拥有任意数量的播放器!
///play 3 songs in parallel
AssetsAudioPlayer.newPlayer().open(
Audio("assets/audios/song1.mp3")
);
AssetsAudioPlayer.newPlayer().open(
Audio("assets/audios/song2.mp3")
);
//another way, with create, open, play & dispose the player on finish
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 //loop the full playlist
);
assetsAudioPlayer.next();
assetsAudioPlayer.prev();
assetsAudioPlayer.playlistPlayAtIndex(1);
音频小部件
如果您想要一种更 Flutter 的方式来播放音频,请尝试 `AudioWidget`!
//inside a stateful widget
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`?
只需从树中移除 AudioWidget!或者简单地保持 `play: false`。
? 监听器
所有监听器都通过 RxDart 公开 Streams,`AssetsAudioPlayer` 将一些监听器公开为 `ValueObservable`(提供对最后一个发出项目的同步访问的可观察对象);
? 当前歌曲
//The current playing audio, filled with the total song duration
assetsAudioPlayer.current //ValueObservable<PlayingAudio>
//Retrieve directly the current played asset
final PlayingAudio playing = assetsAudioPlayer.current.value;
//Listen to the current playing song
assetsAudioPlayer.current.listen((playingAudio){
final asset = playingAudio.assetAudio;
final songDuration = playingAudio.duration;
})
⌛ 当前歌曲时长
//Listen to the current playing song
final duration = assetsAudioPlayer.current.value.duration;
⏳ 当前位置(秒)
assetsAudioPlayer.currentPosition //ValueObservable<Duration>
//retrieve directly the current song position
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());
}
)
▶ 正在播放
一个布尔型可观察对象,表示当前的媒体播放器播放状态。
assetsAudioPlayer.isPlaying // ValueObservable<bool>
//retrieve directly the current player state
final bool playing = assetsAudioPlayer.isPlaying.value;
//will follow the AssetsAudioPlayer playing state
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);
https://developer.android.com.cn/reference/android/media/AudioManager.html?hl=fr
https://developer.apple.com/documentation/avfoundation/avaudiosessioncategorysoloambient
监听音量。
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;
// possible values
// LoopMode.none : not looping
// LoopMode.single : looping a single audio
// LoopMode.playlist : looping the fyll playlist
assetsAudioPlayer.setLoopMode(LoopMode.single);
assetsAudioPlayer.loopMode.listen((loopMode){
//listen to loop
})
assetsAudioPlayer.toggleLoop(); //toggle the value of looping
? 播放速度
assetsAudioPlayer.setPlaySpeed(1.5);
assetsAudioPlayer.playSpeed.listen((playSpeed){
//listen to playSpeed
})
//change play speed for a particular Audio
Audio audio = Audio.network(
url,
playSpeed: 1.5
);
assetsAudioPlayer.open(audio);
?️ 音高
assetsAudioPlayer.setPitch(1.2);
assetsAudioPlayer.pitch.listen((pitch){
//listen to pitch
})
//change pitch for a particular Audio
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"`。
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<uses-permission android:name="android.permission.INTERNET" />
<application
...
android:usesCleartextTraffic="true"
...>
...
</application>
</manifest>
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
add
<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>
? 音乐
示例中使用的所有音乐均来自 https://www.freemusicarchive.org/。




