前言部分
最近因为需要开始蓝牙相关开发,所以在网上搜索了很多内容,并且结合自己的开发过程做了一个总结,先储备上,也许可能帮到正在做蓝牙开发的同学。
蓝牙很早就是android设备上基本通讯功能了,只是以前的没有那么多蓝牙设备,现在蓝牙设备种类繁多,所以经常会有人遇到蓝牙相关的开发。
内容部分
以下部分内容都是比较常规的,很多博客都已经写过了,但是为了记录一个完整的开发流程,这里还是按部就班的都写出来。
1.首先是第一步,打开手机的蓝牙开关。
//获取蓝牙适配器
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
//通过适配器判断蓝牙是否可用
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
2.打开蓝牙后就可以获取已经配对的设备列表。
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
mList.clear();
mArrayAdapter.notifyDataSetChanged();
}
//这里是做了一个数据交换,将Set里面的数据copy到List中,主要是为了根据角标来取出数据。
Iterator<BluetoothDevice> iterator = pairedDevices.iterator();
while (iterator.hasNext()) {
mList.add(iterator.next());
}
//另外一种方式。
// mList.addAll(pairedDevices);
listView.setVisibility(View.VISIBLE);
mArrayAdapter.notifyDataSetChanged();
}
3.下面就可以扫描附近的设备了,这里要注意一下权限的问题,因为在6.0以后的版本需要添加一个位置权限,如下:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
动态权限申请,就不介绍了,网上例子很多,也有很多库。扫描比较简单只需要调用一个方法就可以了,但是应该要控制一下扫描停止的时间,因为扫描蓝牙设备是很耗费资源的。
if (!mBluetoothAdapter.isDiscovering()) {
if (mBluetoothAdapter.startDiscovery()) {
Toast.makeText(getApplicationContext(), "启动扫描中", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "启动扫描中失败", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getApplicationContext(), "扫描中,请勿重复点击", Toast.LENGTH_SHORT).show();
}
开启扫描后,当有新的蓝牙设备被发现,系统会发送广播,我们只需要监听相应的官博即可。下面是需要监听的action,官方例子没有这么多,你可以按需要添加减少。
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);//搜索发现设备
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//状态改变
filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);//行动扫描模式改变了
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//动作状态发生了变化
filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED);
下面是扫描到新设备后接受的action事件,我们需要在这里更新我们界面上的蓝牙设备类表。
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(final Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a ListView
mList.clear();
pairedDevices.add(device);
Iterator<BluetoothDevice> iterator = pairedDevices.iterator();
while (iterator.hasNext()) {
mList.add(iterator.next());
}
connectBluetoothAdapter.notifyDataSetChanged();
//这里我是扫描到需要的设备就停止扫描动作了。
if (!TextUtils.isEmpty(device.getName())) {
if (device.getName().contains("BestSolo")) {
stopDiscovery();
}
}
}
};
4.关键的一步,到拿到扫描设备后,我们就可以连接到设备上了,但是因为蓝牙2.0并没有提供连接的方法,这里连接需要反射调用系统方法。
//connect是隐藏的方法,只能通过反射机制来调用
private void connect(BluetoothA2dp mBluetoothA2dp) {
if (mBluetoothA2dp == null) {
LogUtil.d("mBluetoothA2dp==null" + device.getName());
return;
}
if (device == null) {
return;
}
try {
LogUtil.d("connect" + device.getName());
Method connect = mBluetoothA2dp.getClass().getDeclaredMethod("connect", BluetoothDevice.class);
connect.setAccessible(true);
connect.invoke(mBluetoothA2dp, device);
} catch (Exception e) {
LogUtil.e("connect exception:" + e);
e.printStackTrace();
}
}
因为是通过反射调用,所以调用连接后的效果和系统蓝牙连接效果一致,举个例子:
我用demo连接了我的蓝牙耳机,实际的效果是手机连接了耳机,就是所有的音频都通过蓝牙输出至耳机。 所以这个还是和4.0的蓝牙很不一致的。
上面连接方法需要一个蓝牙的代理BluetoothA2dp,下面是对该类的解释。
/**
* This class provides the public APIs to control the Bluetooth A2DP
* profile.
*
* <p>BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
* Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
* the BluetoothA2dp proxy object.
*
* <p> Android only supports one connected Bluetooth A2dp device at a time.
* Each method is protected with its appropriate permission.
*/
获取BluetoothA2dp的方法是通过蓝牙适配器来获取的。
private BluetoothA2dp mBluetoothA2dp;
private void getBluetoothA2DP() {
mBluetoothAdapter.getProfileProxy(getBaseContext(), mListener, BluetoothProfile.A2DP);
}
private BluetoothProfile.ServiceListener mListener = new BluetoothProfile.ServiceListener() {
@Override
public void onServiceDisconnected(int profile) {
if (profile == BluetoothProfile.A2DP) {
mBluetoothA2dp = null;
LogUtil.e("onServiceDisconnected :" + profile);
}
}
@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.A2DP) {
mBluetoothA2dp = (BluetoothA2dp) proxy; //转换
LogUtil.e("onServiceConnected :" + mBluetoothA2dp.toString());
connect(mBluetoothA2dp);
}
}
};
- 上面的方法都走完,基本上蓝牙已经连接成功了,然后你就做一些操作数据的动作了,如我连接的蓝牙耳机,现在就可以在demo 中播放音频文件了,是可以正常听到的。
结尾
基本上这个流程上完整的,不过现在蓝牙开发基本上还是用BLE低功耗蓝牙的多,新的蓝牙版本提供了新的扫描方法,也提供了连接设备方法,可以通过UUID来连接指定的蓝牙设备。
下篇继续写新的蓝牙版本开发文章。