您的位置:首页 > 其它

三步走--低功耗蓝牙BLE开发实战

2016-01-26 11:56 441 查看
BLE是Android4.3以上加入的新功能,他可以很大程度上节省了设备的功耗,他会在激活的时候进入一个快速的广播段,这时候周围的设备可以搜索到BLE设备,当匹配成功的时候就会建立一个长连接,如果没有匹配成功,他就会在一段时间后自动进入相对慢速的广播段,给周围设备发送的广播频率也会大大减少,直到没有设备与他匹配成功的时候,会自动停止发送广播,处于关闭状态,周围的设备也无法搜索到此BLE设备。

1.开始扫描

BluetoothAdapter.getDefaultAdapter().startLeScan(null, leScanCallback);//开始扫描,就可以一直搜索周围的蓝牙

2.扫描的结果在callback里,new一个callback,回调里的信息都在device里,比如name,mac等等,一般我在这里会去过滤一些mac地址来指定连接哪个BLE设备

//扫描的回调
BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (isConnecting || isConnected() || TextUtils.isEmpty(device.getName()) || TextUtils.isEmpty(device.getAddress()) ) {
return;
}
if (!nameList.contains(device.getName())) {
nameList.add(device.getName());
UIUtils.sendBleMes("DEVICENAME", device.getName());
}

if(!TextUtils.isEmpty(last_DeviceName)&&last_DeviceName.equals(device.getName())){//如果扫描到上次保存到sp的设备,就直接连接
tryConnect(device);
return;
}

if(tryconnect){
if(device.getName().equals(connectingName)){
connectingName = "";
tryconnect = false;
tryConnect(device);
}
}
}
};

3.如果上一步中的device经过一系列判断是我们自己的device,那么就执行下一步连接的操作

//尝试连接
private void tryConnect(BluetoothDevice device) {
isConnecting = true;//正在尝试连接
device.connectGatt(context, false, bluetoothGattCallback);
}

跟上一步一样,连接这个BLE设备的结果依然在一个callback中,也是最重要的一个callback,如下:

1.onConnectionStateChange,名字就是意思,即连接状态的回调,可以通过与BluetoothProfile下的状态值进行判断来知晓设备的连接状态,记住,不要以为连接了设备就完了,在BLE连接到设备的时候我们并不认为是真正意义上的连接,BLE里面有很多个service,只有service判断是我们自己定义的时候才能真正确定为是我们自己的设备了

所以下面我在判断连接设备状态ok的时候,还会discovewServices(),这个方法会回调在同样的这个callback的OnServiceDiscovered方法中

2.OnServiceDiscovered,即判断service的回调,如果在这里判断服务状态OK,并且service的uuid跟我们自己BLE设备service定义的uuid相同,此时恭喜你,你已经找到了自己的设备了,找到自己的设备后你还有两步非常重要的事,1)停止扫描,因为BLE即使成功连接了设备依然会不停的扫描周围的设备,2)我们要打开这个service下的Characteristic,为什么要打开?你可以把他想象成是一个开关,他打开了,你的BLE设备发出的指令(实际上就是一些Characteristic中包括的value和Descriptor)才能传送到连接的设备上

4.onCharacteristicChanged,当上一步你打开了开关后,以后你的BLE设备发送的指令都会在这个方法中回调给你,你可一定一个map集合,装载你的键值对,更好管理

代码如下:

//连接的回调
BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {

@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
LogUtils.i("BluetoothGattCallback" + "--onConnectionStateChange()--" + gatt.getDevice().getName() + "," + newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
LogUtils.i("onConnectionStateChange:已连接到设备" + gatt.getDevice().getName() + ",正在搜索服务");
isConnecting = false;//从未连接的集合中去掉
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
LogUtils.i("onConnectionStateChange:设备断开连接:" + gatt.getDevice().getName());
isConnecting = false;
isConnected = false;
ShowToast.show(UIUtils.getContext(), "设备断开连接:" + gatt.getDevice().getName());
if (Values.whoistop[0]) {
UIUtils.sendBleMes("FOUND_DEVICES", "UNFOUNDED");
}
//context.sendBroadcast(new Intent(BROADCAST_ACTION_CONNECTED_CHANGED));//发送一个连接改变的广播
/*if(BluetoothAdapter.getDefaultAdapter().getState() == BluetoothAdapter.STATE_ON){
close();
startScan();
}*/
}
}

@Override
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
LogUtils.i("onServicesDiscovered:" + gatt.getDevice().getName()
+ ", status:" + status + ", isConnected = " + isConnected());
if (isConnected()) {
return;
}
isConnected = false;
//connectingAddress.remove(getDevieNameAndAddress(gatt.getDevice()));
if (status == BluetoothGatt.GATT_SUCCESS) {//A GATT operation completed successfully
for (final BluetoothGattService server : gatt.getServices()) {
if (!isConnected) {
isConnected = isOwnerUUID(server.getUuid().toString());//判断这个server是不是用户定义的uuid,如果是就为真,只有这里isConnected才为真
LogUtils.i("onServicesDiscovered:服务UUID匹配状况:" + server.getUuid().toString() + ":连接状况:" + isConnected);
if (isConnected) {
bluetoothGatt = gatt;//费劲千辛万苦找到了gatt
stopScan();
LogUtils.i("onServicesDiscovered:停止扫描,已连接到到设备:" + gatt.getDevice().getName());
ShowToast.show(UIUtils.getContext(), "找到设备:" + gatt.getDevice().getName());
if (Values.whoistop[0]) {
UIUtils.sendBleMes("FOUND_DEVICES", gatt.getDevice().getName());
}
setCharacteristicNotification(gatt, server, User_Definition_Characteristic_UUID);
}
//context.sendBroadcast(new Intent(BROADCAST_ACTION_CONNECTED_CHANGED));//也发送一个连接改变的广播
}
//setCharacteristicNotification(gatt, server, Battery_Service_UUID);//设置电池
}
} else {
isConnected = false;
//context.sendBroadcast(new Intent(BROADCAST_ACTION_CONNECTED_CHANGED));
LogUtils.i("onServicesDiscovered:Gatt未连接成功");
}
}

@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
LogUtils.i("onCharacteristicChanged:" + characteristic.getUuid() + ", value=" + bytesToHexString(characteristic.getValue()));
/*if (characteristic.getService().getUuid().toString().equals(Battery_Service_UUID)) {
LogUtils.i("onCharacteristicChanged:Battery_Service_UUID:" + Battery_Service_UUID);
//此处可以处理电池service信息
return;
}*/
//如果发过来的指令不包含在我们定义的keymap里面,就不处理
if (uiHander == null || !KEY_MAP.containsKey(bytesToHexString(characteristic.getValue()))) {
LogUtils.i("发送的Characteristic指令不存在或者uiHander为空");
return;
}
//走到这里说明是我们自己的键值对
Integer what = KEY_MAP.get(bytesToHexString(characteristic.getValue()));
uiHander.removeMessages(what);
uiHander.sendEmptyMessageDelayed(what, 100);
}
};

//打开Notification,才能接受发过来的Characteristic数据
private void setCharacteristicNotification(BluetoothGatt gatt, BluetoothGattService server, String uuid) {
BluetoothGattCharacteristic characteristic = server.getCharacteristic(UUID.fromString(uuid));//根据一个UUID,获得一个服务下的Characteristic
if (characteristic != null) {
LogUtils.i("进入到setCharacteristicNotification() + " + uuid);
gatt.setCharacteristicNotification(characteristic, true);
}
}

//停止扫描
public void stopScan() {
BluetoothAdapter.getDefaultAdapter().stopLeScan(leScanCallback);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: