一、功能需求
功能需求是在Android10以上设备上实现蓝牙音乐功能,细分为两个功能点:
1、手机和车载设备实现蓝牙连接 (本Demo文只做监听蓝牙连接状态,需手动到设置中连接蓝牙)
2、连接蓝牙成功后手机播放音乐时车载设备也能播放音乐,并且在车机应用上显示音乐名称,歌手,专辑名。可在车机应用中点击播放,暂停,上一曲,下一曲控制手机端的音乐播放。
二、实现效果图
Demo地址:BluetoothMediaDemo: 实现Android10以上设备蓝牙音乐功能,Demo主要实现两步: 1、监听蓝牙连接状态 2、手机播放音乐时车载设备播放手机的音乐,并且在车机应用上显示音乐名称,歌手,专辑名。可在车机应用中点击播放,暂停,上一曲,下一曲控制手机端的音乐播放 (gitee.com)
三、代码详解
3.1、实现原理:
安卓系统通过媒体浏览器服务已经为大家提供了一套完整的音乐控制解决方案,并进行了封装。所以音乐类应用通过媒体浏览器服务可以轻松实现音乐控制等功能
蓝牙音乐应用根据当前系统的安卓版本通过构建相应的 ComponentName来初始化媒体浏览器服务的客户端也即是 MediaBrowser 来连接媒体浏览器服务的服务端 MediaBrowserService,连接成功后应用获取到 MediaController 来控制音乐。
因为ComponentName指明了bind哪个服务,从而可以正确找到蓝牙服务中对应于媒体浏览器的服务。根据蓝牙服务的清单文件AndroidManifest.xml指定,应用构建相应的ComponentName,构建此变量需要提供包名package和类名class。
3.2、代码分析:
1、按照以上实现原理,首先我们需要连接媒体浏览器服务:
(1)、android-7(N版本) ~ android-9(P版本):
String package = "com.android.bluetooth"
String class = "com.android.bluetooth.a2dpsink.mbs.A2dpMediaBrowserService"
(2)、Android10以上的版本服务包名和文件名分别为:
String package = "com.android.bluetooth"
String class = "com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService"
private void connectMediaBrowser() {
//1.绑定服务,Android10以上的版本服务名称为
ComponentName componentName = new ComponentName("com.android.bluetooth", "com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService");
// 2.创建MediaBrowser
mMediaBrowser = new MediaBrowser(this, componentName, connectionCallback, null);
//3.连接MediaBrowser
mMediaBrowser.connect();
}
2、connectionCallback接口回调监听与流媒体服务是否连接成功,若连接成功则获取MediaController对象,通过MediaController 来控制音乐
private MediaBrowser.ConnectionCallback connectionCallback = new MediaBrowser.ConnectionCallback() {
public void onConnected() {
//如果服务端接受连接,就会调此方法表示连接成功,否则回调onConnectionFailed();
Log.d(TAG, "onConnected: ");
//获取配对令牌
MediaSession.Token token = mMediaBrowser.getSessionToken();
//通过token,获取MediaController,第一个参数是context,第二个参数为token
mMediaController = new MediaController(mContext, token);
Log.e(TAG, "mMediaController===" + mMediaController);
//mediaController注册回调,callback就是媒体信息改变后,服务给客户端的回调
mMediaController.registerCallback(mMediaCallBack);
}
public void onConnectionSuspended() {
Log.d(TAG, "onConnectionSuspended: ");
//与服务断开回调(可选)
}
public void onConnectionFailed() {
Log.d(TAG, "onConnectionFailed: ");
//连接失败回调(可选)
}
};
3、MediaController.Callback接口监听音乐信息和播放状态的变化,得到MediaMetadata 对象后通过MediaDescription 即可获取音乐名称,歌手,专辑名。PlaybackState获取播放状态,进度。
详细接口解释可参考Android官方文档:MediaDescription | Android Developers (google.cn)
private MediaController.Callback mMediaCallBack = new MediaController.Callback() {
@Override
public void onMetadataChanged(@Nullable MediaMetadata metadata) {
super.onMetadataChanged(metadata);
if (metadata != null) {
MediaDescription description = metadata.getDescription();
String title=description.getTitle().toString();//音乐名称
String singer=description.getSubtitle().toString();//歌手
String album=description.getDescription().toString();//专辑名称
}
}
@Override
public void onPlaybackStateChanged(@Nullable PlaybackState state) {
super.onPlaybackStateChanged(state);
//播放状态信息回调
long position = state.getPosition();//获取当前播放进度
int playState=state.getState(); //当前播放状态
}
};
4、蓝牙音乐通过 MediaController.getTransportControls()提供的音乐控制接口下发相应的指令,指令经过媒体浏览器服务转送到蓝牙服务中,通过蓝牙技术传输到远端设备执行响应的动作,最终达到控制蓝牙音乐的目的。
mMediaController.getTransportControls().skipToPrevious();//上一曲
mMediaController.getTransportControls().skipToNext();//下一曲
mMediaController.getTransportControls().play()//播放
mMediaController.getTransportControls().pause();//暂停
5、注意我们需要在AndroidManifest文件中申请权限,如果是Android 10以上设备还需要动态申请权限
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
详细有关蓝牙协议的源码分析可参考文章:
Android 控制车载蓝牙播放音乐详解流程_Android_脚本之家 (jb51.net)
创造不易,转载请标明出处!!!