1.前言
蓝牙在我们生活中扮演者许多重要的角色,蓝牙耳机、蓝牙音箱、蓝牙灯泡、蓝牙智能硬件等等!可见,蓝牙无处不在,而且也是物联网的基础纽带,它改变了我们的许多生活方式,给我们带来了许多益处。
前段时间我也简单地使用了小程序的蓝牙api操作,接下来我也要开始重新认识下Android蓝牙开发,蓝牙又分为经典蓝牙和BLE(低功耗蓝牙),这次我主要学习蓝牙BLE,所以我第一时间找了谷歌给我们提供了官方源码demo:
https://github.com/googlesamples/android-BluetoothLeGatt
2.权限
配置文件需要先声明蓝牙权限:
<!--蓝牙必须的权限-->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
除了蓝牙权限外,还有如下权限是声明程序是否可用于支持BLE或者支持出BLE外的设备;如果required=true,则应用只能在支持BLE的Android设备上安装运行,不支持BLE的设备将finish。
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
此外还有一个很关键的问题,不知道你们在开发中有没有遇到过呢?官方demo没有适配到这里。Android6.0以上的手机仅仅是添加如上蓝牙权限是不行的,这将会造成无法扫描到其他设备,针对这问题,果断查了资料,需要添加位置权限;
<!--android6.0以上使用蓝牙需要的权限,否则在Android6.0以上的手机扫描不到蓝牙设备-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
在Android6.0以上 位置相关的权限属于运行时权限,所以代码同时也要请求一下 让用户确认,这个就不多说了。
3.是否支持蓝牙BLE
在前面的权限也说了如果required=true,则应用只能在支持BLE的Android设备上安装运行,不支持BLE的设备将finish;
如果想在java代码上实现上面的逻辑也是可以的,官方demo如下:
/**使用此检查确定设备是否支持BLE。 然后你可以有选择地禁用与BLE相关的功能。*/
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
4.初始化蓝牙适配器
初始化蓝牙适配器。 对于API级别18及更高级别,请通过BluetoothManager获取对BluetoothAdapter的引用。最后这里记得要判空!
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
5.当前设备是否已开启蓝牙
要想操作蓝牙,必须确保在设备上启用蓝牙。如果当前未启用蓝牙,因此我们可以触发Intent调用系统显示一个对话框,要求用户授予启用蓝牙的权限。
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
6.初始化listview列表适配器
这里目的就是将扫描到的蓝牙设备显示到listview列表上,然后用户就可以点击对应的item,程序就可以进行下一步操作。这一步骤可根据需要定制。
7.扫描
官方demo的扫描方法如下,如果要扫描的话就要传入true执行scanLeDvice(true)方法,然后蓝牙适配器就调用startLeScan()方法进行扫描,mLeScanCallback是扫描回调,下面会说到;执行扫描的同时开启了一个延时操作,时间到了就调用stopLeScan()方法停止扫描。
我觉得这里设置了一个延时停止扫描操作是非常友好的,因为扫描非常耗资源。
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
invalidateOptionsMenu();
}
接下来就看看扫描的Callback回调吧,这个回调里面有个onLeScan方法,蓝牙扫描成功后的结果会返回此方法中,然后就可以处理BluetoothDevice拿到设备信息 最后展示到前面初始化的listview列表中,大概流程就是这样。
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
接着再看看这个onLeScan方法中的值吧!
第一个参数device,表示一个远程蓝牙设备,里面有它独有的蓝牙地址Address和Name等,所以后续需要进行连接蓝牙操作也需要用到这里获取的蓝牙Address;
第二个参数rssi表示扫描到的设备信号强度,这里应该可以用来判断距离的远近。
第三个参数scanRecord表示远程设备提供的广告记录的内容。
至此已经完成初始化配置、一些设备的判断逻辑和扫描操作了,如果能成功地扫描到设备并展示到界面上的话,下一步如果用户点击了列表,将进行蓝牙连接和相关的读写操作!
所以下一篇文章不出意外的话,就是继续学习Android蓝牙的连接和读写操作:
Android 蓝牙BLE开发从官方源码demo开始(二)