安卓低功耗蓝牙BLE开发--服务端
最近忙着折腾智能手表Android Wear2.0的开发,由于国内用不了play服务,所以谷歌为wear提供的一套和手机通信的API都不能用。为了在手机和手表之间传递数据,我不得不考虑使用蓝牙来建立手机和手表之间的通讯。在这个过程中被坑了许多次,所以记录下来方便自己查阅。
(PS: 国内有的教程使用的API已被弃用,许多东西是我自己看着官方文档总结出来的,如有不对的地方请帮我指出来。)
1.准备工作
工欲善其事,必先利其器。Android Wear2.0时的目标SDK版本已经在23以上了,安卓在6.0的时候加入了运行时权限系统,所以想开发蓝牙客户端的第一步,就是拿到应用所需要的必要权限。
需要的权限如下:
- android.permission.BLUETOOTH
- android.permission.BLUETOOTH_ADMIN
- android.permission.ACCESS_COARSE_LOCATION
对于前两个权限,比较好理解,一个用于连接蓝牙设备,一个用于搜索蓝牙设备。可是这最后一个模糊地理位置权限是什么鬼?原来谷歌认为扫描周围蓝牙4.0设备可以获取用户的大概位置,所以要求开发者申请模糊位置权限。没有这个权限的话虽然能正常开始扫描蓝牙BLE设备,但是一个结果都不会返回,一点儿用都没有。
首先在AndroidManifest.xml之中声明权限:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
接着,需要在运行时申请权限:
//首先判断是否是安卓6.0以上,然后申请权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
this.requestPermissions(new String[]{
Manifest.permission.BLUETOOTH_ADMIN,
Manifest.permission.BLUETOOTH,
Manifest.permission.ACCESS_COARSE_LOCATION
},0);
}
之后在onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults) 回调方法中确认用户是否同意了权限。
2.开启蓝牙BLE服务监听
开启蓝牙服务的步骤比较多,相比于客户端复杂了不少,感谢谷歌提供的全套文档,自己慢慢折腾也写出来了。
蓝牙服务端需要分别配置以下的类:
- BluetoothGattCharacteristic 特性,最小的部分
- BluetoothGattService 服务,里面包含特性
- BluetoothGattServer 服务器,里面包含服务
- BluetoothGattServerCallback 服务器回调,负责收发数据的方法写在里面
建立一个BLE服务器,需要设置好Service以及Service所包含的Characteristic。
这里只演示建立Service,通过Service的addCharacteristic方法可以添加Characteristic。
//服务的UUID
UUID SERVICE_UUID = UUID.fromString("…………自己的UUID…………");
//用UUID创建一个主服务
BluetoothGattService service =
new BluetoothGattService(SERVICE_UUID,BluetoothGattService.SERVICE_TYPE_PRIMARY);
//创建服务的特性(characteristic)
characteristic = new BluetoothGattCharacteristic(
CHARACTERISTIC_UUID,
BluetoothGattCharacteristic.PROPERTY_WRITE |
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_WRITE
);
//为服务添加特性
gattService.addCharacteristic(characteristic);
接着创建服务器Server
//bm为BluetoothManager的实例。gattsCallback为服务器回调
BluetoothGattServer gattServer = bm.openGattServer(this,gattsCallback);
//添加服务
gattServer.addService(service);
这样就得到了一个gattServer对象,并且已经开始监听了,里面包含一个服务。
3.开启蓝牙BLE广播
单单开启服务监听并没有用,别人不知道你的设备是哪一个,所以需要开启广播,BLR服务端才能被别人发现。
开启BLE服务端广播需要以下几个类:
- BluetoothLeAdvertiser 广播器,用于开始广播和停止广播。
- AdvertiseSettings 广播的相关设置
- AdvertiseData 广播的数据
- AdvertiseCallback 广播的回调,用于通知开启广播是成功了还是失败了
首先创建AdvertiseSettings对象,这里用AdvertiseSettings.Builder来创建新的实例:
AdvertiseSettings.Builder settingBuilder = new AdvertiseSettings.Builder();
settingBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
//^这里将功率设置为最大,请根据需要选择合适的模式^
.setConnectable(true)
//^广播出来自然是可连接的了,除非真是要根据周围蓝牙来确定用户模糊位置= =……^
.setTimeout(0)
//^设置永不超时,直到手动停止广播^
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
//^同第一条,这里设置为最大功率方便查找^
AdvertiseSettings setting = settingBuilder.build();
然后设置AdvertiseData对象,用AdvertiseData.Builder来创建:
//bm: BluetootnManager实例
bm.getAdapter().setName("WATCH BLE");//设置设备名,用于广播识别
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
dataBuilder.setIncludeDeviceName(true)
//^包含设备名称,adapter.setName()方法才能起作用^
.setIncludeTxPowerLevel(false);
//^由于数据大小限制,不要广播无用数据,所以false^
AdvertiseData data = dataBuilder.build();
最后开始广播:
BluetoothLeAdvertiser advertiser = bm.getAdapter().getBluetoothLeAdvertiser();
//advertiseCallback是广播回调
advertiser.startAdvertising(setting,data,advertiseCallback);
这样就开启了BLE服务广播,可以被扫描到了,记得在BluetoothGattServerCallback回调连接成功之后,关闭广播。
评论已关闭