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,
);

sample1

📥 导入

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目录打开它们。

  1. 在你的assets目录下创建一个音频文件夹(名称不限于“audios”)。
  2. 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

  1. 在音频中添加元数据:
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
          ),
   );
  1. 打开时设置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"/>

通过清单文件:

  1. 将图标添加到Android的res目录(android/app/src/main/res)。
  2. 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并设置NSAppTransportSecurityNSAllowsArbitraryLoads

<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>
1 回复

更多关于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');
              },
            ),
          ],
        ),
      ),
    );
  }
}
回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!