要开发一个 Android 音乐播放器,相信各位 Android 开发者首先想到的是 MediaSession 框架。但 MediaSession 框架仅对基础功能进行了封装,要使用它开发一个音乐播放器,开发者还需要编写大量的代码。例如,响应媒体按钮、请求和管理音频焦点、在输出设备改变时暂停播放。此外,由于音乐播放器需要在后台运行,因此还得维护一个 Notification,以便在后台运行时,用户可以通过这个 Notification 对播放器进行控制。如果你的播放器还需要支持播放列表、线控播放、音质切换、睡眠定时器等一系列功能,那么接下来就有的忙了。不过不用担心,
snow
框架已经为您做好了其中的大部分工作。
snow 框架简介
snow
是一个 Android 音乐播放器框架,基于 MediaSession 框架构建,并提供了对 MediaSession 框架的兼容
。
snow
框架已经为开发者处理好了大部分繁琐的事情,例如,响应媒体按钮、请求和管理音频焦点、在输出设备改变时暂停播放、播放列表,线控播放等...
仓库地址
:
https://github.com/jrfeng/snow
支持的功能:
build.gradle
文件中:
allprojects {
repositories {
maven { url 'https://jitpack.io' }
将以下代码添加到模块的依赖中:
dependencies {
implementation 'com.github.jrfeng.snow:player:1.0.9'
申请权限:
<!-- 用于启动前台 Service -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- 用于后台播放 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- 用于播放本地音乐 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 用于播放网络音乐 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
注意!从 Android 6.0(API Level 23)
开始,需要在运行时动态申请存储器访问权限:"android.permission.READ_EXTERNAL_STORAGE"
。
创建 PlayerService
创建一个类并让其继承 snow.player.PlayerService
类,并且使用 @PersistenceId
注解对其进行标注。你不需要重写这个类的任何方法。
@PersistenId("MyPlayerService")
public MyPlayerService extends PlayerService {
@PersistenceId
注解用于为当前 PlayerService
设置一个持久化 ID
(请保证该 ID
值的唯一性),该 ID
将用于 PlayerService
状态的持久化。如果你没有使用 @PersistenceId
注解设置持久化 ID
,则持久化 ID
默认为你的 PlayerService
的完整类名(例如 snow.demo.MyPlayerService
)。建议为你的 PlayerService
设置一个持久化 ID
,这样即使重命名类也不会导致状态丢失。
注册 PlayerService
<service android:name="snow.demo.MyPlayerService">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
<receiver android:name="androidx.media.session.MediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
连接到 PlayerService
:
// 创建一个 PlayerClient 对象
PlayerClient playerClient = PlayerClient.newInstance(context, MyPlayerService.class);
// 连接到 PlayerService
playerClient.connect(new PlayerClient.OnConnectCallback() {
@Override
public void onConnected(boolean success) {
// DEBUG
Log.d("App", "connect: " + success);
创建一个播放列表
private Playlist createPlaylist() {
MusicItem song1 = new MusicItem.Builder()
.setTitle("太阳照常升起")
.setArtist("久石让")
.setAlbum("太阳照常升起 电影原声大碟")
.setDuration(224013)
.setUri("http://music.163.com/song/media/outer/url?id=441722")
.setIconUri("http://p2.music.126.net/drqGdK7zgW7B7IFl4lWpoQ==/109951163369835547.jpg")
.build();
MusicItem song2 = new MusicItem.Builder()
.setTitle("钢铁洪流进行曲")
.setArtist("李旭昊")
.setAlbum("国庆70周年阅兵BGM")
.setDuration(186154)
.setUri("http://music.163.com/song/media/outer/url?id=1394369908")
.setIconUri("http://p2.music.126.net/KnC_YJjnRTNvCF82_2leCg==/109951164930615683.jpg")
.build();
MusicItem song3 = new MusicItem.Builder()
.setTitle("国际歌-钢琴")
.setArtist("曹伟健")
.setAlbum("音迹")
.setDuration(141369)
.setUri("http://music.163.com/song/media/outer/url?id=1857796913")
.build();
MusicItem song4 = new MusicItem.Builder()
.setTitle("我爱你中国[Forbid Seek]")
.setDuration(136000)
// cross-protocol redirects
.setUri("https://music.163.com/song/media/outer/url?id=174451")
.setIconUri("http://p2.music.126.net/x6pVwc6ysKZ9S01jYlYiAw==/97856534887060.jpg")
// forbid seek
.setForbidSeek(true)
.build();
return new Playlist.Builder()
.append(song1)
.append(song2)
.append(song3)
.append(song4)
.build();
设置播放列表并播放音乐
// 创建播放列表
Playlist playlist = createPlaylist();
// 设置播放列表,并播放音乐
playerClient.setPlaylist(playlist, true);
为了演示 snow
框架的部分功能,我们特意开发了一个示例程序,如下图所示(网盘下载,提取码:7mye):
提示:示例程序是一个本地音乐播放器,可以在项目的 app
模块中找到该示例程序的源代码。
如果您对 snow
框架感兴趣,并且希望深入了解,可以查看项目的 Wiki
:
自定义 PlayerService
自定义 Notification
使用 ExoPlayer
EqualizerActivity
jrfeng
android