字节笔记本

2026年3月22日

Flutter Music Player - 开源 Material Design 音乐播放器

本文介绍 Flutter Music Player,第一个基于 Flutter 开源的美观 Material Design 音乐播放器,支持播放本地音乐文件。

项目简介

Flutter Music Player 是由开发者 Pawan Kumar(@imthepk)创建的开源项目,旨在打造一个基于 Flutter 框架的精美音乐播放器应用。该项目采用 Material Design 设计语言,提供了完整的音乐播放体验,是 Flutter 社区中较早出现的音乐播放器参考实现之一。项目不仅包含一个完整可运行的播放器应用,还附带了一个可复用的音乐播放插件,方便开发者在自己的项目中集成音乐播放功能。

该项目以完整的功能示例展示了如何在 Flutter 中实现音频播放、本地歌曲获取、专辑封面展示等常见需求,对于学习 Flutter 多媒体开发的开发者来说具有较高的参考价值。项目已在 Google Play Store 上发布了 Beta 版本,供用户体验测试。

核心特性

  • 本地音乐获取:内置权限管理,自动扫描并获取设备中的本地音乐文件
  • 完整播放控制:支持播放、暂停、停止、快进(seek)、随机播放(shuffle)等操作
  • 专辑封面显示:自动解析并展示音乐文件的专辑封面图片
  • 播放状态监听:提供完整的回调事件支持,包括 onComplete(播放完成)、onDuration(总时长)和 onCurrentPosition(当前播放位置)
  • 精美 UI 设计:采用 Material Design 设计规范,界面美观流畅
  • 动画效果:丰富的页面过渡和交互动画
  • 完整功能示例:提供完整的代码实现,可作为学习参考
  • 可复用插件:项目附带独立的音乐播放插件,可集成到其他 Flutter 项目中
  • 多格式支持:Android 平台支持主流音频格式

注意:该项目目前仅支持 Android 平台,iOS 版本尚在开发中。同时也计划在未来加入在线电台功能。

技术栈

  • Flutter:跨平台 UI 框架,基于 Dart 语言开发
  • Dart:项目主要开发语言
  • Material Design:Google 的设计语言规范,用于 UI 设计
  • Flutter Audio Plugin:音频播放核心插件
  • Android Permissions:用于获取本地文件读取权限

安装指南

环境要求

  • Flutter SDK(建议使用与项目兼容的稳定版本)
  • Android SDK(最低 API 级别根据项目配置)
  • Android Studio 或 VS Code 作为开发工具

克隆项目

通过 Git 克隆项目到本地:

bash
git clone https://github.com/iampawan/Flutter-Music-Player.git

安装依赖

进入项目目录并安装所需的依赖包:

bash
cd Flutter-Music-Player
flutter pub get

配置权限

确保项目已正确配置 Android 存储读取权限。检查 android/app/src/main/AndroidManifest.xml 文件中是否包含必要的权限声明:

xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

对于 Android 13(API 33)及以上版本,可能需要额外添加媒体权限:

xml
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

运行项目

连接 Android 设备或启动模拟器,然后运行项目:

bash
flutter run

快速开始

使用附带的 Flute 插件

Flutter Music Player 项目包含一个名为 Flute 的音乐播放插件,可以在你自己的 Flutter 项目中独立使用。该插件封装了音频播放、歌曲获取等核心功能,简化了音乐播放功能的集成过程。

基本播放流程

以下是在 Flutter 项目中实现音乐播放的基本流程:

  1. 请求存储权限以访问设备中的音乐文件
  2. 扫描设备获取本地音乐列表
  3. 使用音频播放器加载并播放选中的音乐
  4. 监听播放状态更新 UI

使用示例

音乐播放器核心逻辑

以下是一个简化的音乐播放器实现示例,展示了如何使用音频插件播放本地音乐文件:

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

class MusicPlayerPage extends StatefulWidget {
  @override
  _MusicPlayerPageState createState() => _MusicPlayerPageState();
}

class _MusicPlayerPageState extends State<MusicPlayerPage> {
  AudioPlayer _audioPlayer = AudioPlayer();
  bool _isPlaying = false;
  Duration _duration = Duration.zero;
  Duration _position = Duration.zero;

  @override
  void initState() {
    super.initState();

    // 监听音频时长
    _audioPlayer.onDurationChanged.listen((Duration d) {
      setState(() {
        _duration = d;
      });
    });

    // 监听播放位置变化
    _audioPlayer.onPositionChanged.listen((Duration p) {
      setState(() {
        _position = p;
      });
    });

    // 监听播放完成事件
    _audioPlayer.onPlayerComplete.listen((event) {
      setState(() {
        _isPlaying = false;
        _position = Duration.zero;
      });
    });
  }

  @override
  void dispose() {
    _audioPlayer.dispose();
    super.dispose();
  }

  Future<void> _playMusic(String filePath) async {
    await _audioPlayer.play(DeviceFileSource(filePath));
    setState(() {
      _isPlaying = true;
    });
  }

  Future<void> _pauseMusic() async {
    await _audioPlayer.pause();
    setState(() {
      _isPlaying = false;
    });
  }

  Future<void> _seekToPosition(Duration position) async {
    await _audioPlayer.seek(position);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Flutter Music Player')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 播放/暂停按钮
            IconButton(
              icon: Icon(
                _isPlaying ? Icons.pause_circle_filled : Icons.play_circle_filled,
                size: 64,
              ),
              onPressed: _isPlaying ? _pauseMusic : () => _playMusic('/path/to/music.mp3'),
            ),
            // 进度条
            Slider(
              value: _position.inSeconds.toDouble(),
              min: 0,
              max: _duration.inSeconds.toDouble(),
              onChanged: (double value) {
                _seekToPosition(Duration(seconds: value.toInt()));
              },
            ),
            Text(
              '${_position.inMinutes}:${(_position.inSeconds % 60).toString().padLeft(2, '0')} '
              '/ ${_duration.inMinutes}:${(_duration.inSeconds % 60).toString().padLeft(2, '0')}',
            ),
          ],
        ),
      ),
    );
  }
}

播放控制功能

该项目的播放控制涵盖了音乐播放器的核心功能需求:

dart
// 播放指定文件
await _audioPlayer.play(filePath);

// 暂停播放
await _audioPlayer.pause();

// 停止播放
await _audioPlayer.stop();

// 恢复播放
await _audioPlayer.resume();

// 跳转到指定位置(单位:毫秒)
await _audioPlayer.seek(Duration(milliseconds: 30000));

// 设置随机播放模式
_audioPlayer.setReleaseMode(ReleaseMode.loop);

使用 Flute 插件

项目附带的 Flute 插件提供了更简洁的 API 来处理音乐播放功能。开发者可以将该插件集成到自己的项目中,无需从头实现音频播放逻辑。具体使用方式可以参考项目源代码中的插件目录。

项目链接

参考资源

贡献指南

项目欢迎社区贡献,遵循以下规范:

  1. Pull Request 必须提交到 develop 分支
  2. 保持代码风格一致(使用 IDE 的 Reformat Code 功能)
  3. PR 标题需清晰描述变更内容
  4. 先检查是否已有相关 Issue
  5. 遵循项目既定的代码标准
分享: