Android蓝牙4.0单车锁应用实例开发
前言:
露脸 0_o 一直想开始写一些文章,一直没有机会写,犹犹豫豫了好久,现在为大家带来关于蓝牙交互的文章,一方面为了提升自己的能力,积累一点经验,一方面也是希望分享自己所遇到的一些问题以及解决方法能给正在面临这些问题的伙伴们带来一些帮助。
概述:
在如今共享的时代,共享单车已经达到了一个很庞大的数量,大到一线城市,小到二线三线城市,而共享单车的核心就是车锁,车锁开锁模式又有蓝牙,GPRS等,在我开发项目的基础下,我先总结了下蓝牙4.0开发使用的一些东西分享一下,下面先看交互流程.
-
请求蓝牙权限,打开蓝牙
-
蓝牙扫描附近设备
-
蓝牙匹配成功蓝牙的连接
-
蓝牙协议数据的通信
-
锁指令返回的数据的解析
具体知道流程之后我们直接进入蓝牙功能的一些运用与交互
蓝牙权限
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
允许搜索发现附近设备以及配对
<uses-permission android:name="android.permission.BLUETOOTH"/>
允许连接到已配对的蓝牙设备
申请完权限之后,我们先熟悉几个蓝牙开发主要使用类
BluetoothAdapter
BluetoothAdapter代表了移动设备的本地的蓝牙适配器, 通过该蓝牙适配器可以对蓝牙进行基本操作, 例如 : 启动设备发现(startDiscovery), 获取已配对设备(getBoundedDevices), 通过mac蓝牙地址获取蓝牙设备(getRemoteDevice), 从其它设备创建一个监听连接(listenUsingRfcommWithServiceRecord);
获取该适配器对象
> BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothManager
BluetoothManager在Android4.3以上支持(API level 18),高级管理者用于获得BluetoothAdapter的实例并进行整体蓝牙管理, 使用getSystemService(String)创建一个BluetoothManager BLUETOOTH_SERVICE,然后调用getAdapter()来获得theBluetoothAdapter。或者,你可以调用静态辅助getDefaultAdapter()。
获取该适配器对象
>BluetoothManager mBluetoothManager =
(BluetoothManager) getContext().getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = mBluetoothManager .getAdapter();
在了解一些主要使用类之后我们开始蓝牙4.0的开发的工作.
判断蓝牙的打开与关闭
BluetoothManager mBluetoothManager =
(BluetoothManager) getContext().getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = mBluetoothManager .getAdapter();
//如果bluetoothAdapter == null,说明设备不支持蓝牙
if (bluetoothAdapter.isEnabled()){
//已开启蓝牙,此时我们开始搜索附近设备
searchBluetooth();
}
else {
//未开启蓝牙,此时打开蓝牙
bluetoothAdapter.enable();
searchBluetooth();
}
扫描搜索附近设备
这里之后我们直接引用github封装好的蓝牙通信库,只开放连接,读写,通知等语义。简单明了.附上githb地址:https://github.com/dingjikerbo/BluetoothKit
SearchRequest request = new SearchRequest.Builder()
.searchBluetoothLeDevice(3000, 3) // 先扫BLE设备3次,每次3s
.searchBluetoothClassicDevice(5000) // 再扫经典蓝牙5s
.searchBluetoothLeDevice(2000) // 再扫BLE设备2s
.build();
bluetoothClient.search(request, new SearchResponse() {
@Override
public void onSearchStarted() {
//搜索开始
}
@Override
public void onDeviceFounded(SearchResult device) {
//搜索成功,找到设备
//一般我们都是通过蓝牙唯一的MAC地址进行匹配,我这只写一个例子,具体mac地址我们是根据后台返回的值与设备进行匹配
if (("mac").equals(device.getAddress())) {
//匹配成功时停止搜索并连接设备
bluetoothClient.stopSearch();
connect(device);
}
}
@Override
public void onSearchStopped() {
//搜索停止
}
@Override
public void onSearchCanceled() {
//搜索被取消
}
});
连接设备
BleConnectOptions options = new BleConnectOptions.Builder()
.setConnectRetry(3) // 连接如果失败重试3次
.setConnectTimeout(30000) // 连接超时30s
.setServiceDiscoverRetry(3) // 发现服务如果失败重试3次
.setServiceDiscoverTimeout(20000) // 发现服务超时20s
.build();
bluetoothClient.connect(device.getAddress(), new BleConnectResponse() {
@Override
public void onResponse(int code, BleGattProfile profile) {
if (code == REQUEST_SUCCESS) {
//当连接成功时,我们需要进行一些数据通信
}
}
});
蓝牙协议的通信
我们在与蓝牙通信的时候,发送或者接受指令,我们都需要Service UUID,该 service 下的 characteristic,(UUID是“Universally Unique Identifier”的缩写,通用唯一识别码的意思。对于蓝牙设备,每个服务都有一个与它对应的UUID(唯一的)。)我们可以简单看一个,
0788888e-8535-b5a0-7140-a11112495cba 操作类型Write 向硬件写指令
0788888e-8535-b5a0-7140-a11112495cb8 操作类型Notify 硬件返回的信息
现在我们可以开始通过UUID来进行正常的发送指令和接收指令,在发送指令通信之前我们先注册蓝牙通知.
//注册通知使用serviceUUID和如图Notifity类型的characteristicUUID
bluetoothClient.notify(mac, serviceUUID, characterUUID2, new BleNotifyResponse() {
@Override
public void onNotify(UUID service, UUID character, byte[] value) {
//这里是接收蓝牙指令的回调
}
@Override
public void onResponse(int code) {
if (code == REQUEST_SUCCESS) {
//注册成功
}
}
});
我们现在可以发送一个指令到蓝牙设备与其通信,一般我们通信都会规定一份协议,
随便举个例子
0 STX 数据头/帧头 固定值:0xFE
1 NUM 随机数
2 ID APP 端用户 ID 号
3
4
5
6 KEY 0x00
7 CMD 0x11
8 LEN 0x08
9-16 DATA 设备识别 KEY,8 字节
17 CRC CRC 之前数据经过加密后的 CRC16 校验值
18
我们根据以上拼接一个byte[]数组,(中途会有一些加密方式比如crc校验,异或等)然后发送给蓝牙设备
//发送指令使用serviceUUID和如图Write类型的characteristicUUID
bluetoothClient.write(mac, serviceUUID, characterUUID1, data, new BleWriteResponse() {
@Override
public void onResponse(int code) {
if (code == REQUEST_SUCCESS) {
//命令发送成功
}
}
});
我们还有可能会需要知道一些蓝牙的连接状况,此时我们可以注册一个蓝牙连接的监听
bluetoothClient.registerConnectStatusListener(mac, new BleConnectStatusListener() {
@Override
public void onConnectStatusChanged(String mac, int status) {
if (status == STATUS_CONNECTED) {
//连接
} else if (status == STATUS_DISCONNECTED) {
//断开
}
}
});
至此蓝牙通信就结束了,当然在IBluetoothClient 接口中 我们还有一些蓝牙的功能,比如断开连接,停止搜索,取消注册一些通知和监听,发送无返回类型指令,读取指令信息等等,其他蓝牙通信设备大部分都是这种类型,我们可以举一反三.
public interface IBluetoothClient {
void connect(String mac, BleConnectOptions options, BleConnectResponse response);
void disconnect(String mac);
void registerConnectStatusListener(String mac, BleConnectStatusListener listener);
void unregisterConnectStatusListener(String mac, BleConnectStatusListener listener);
void read(String mac, UUID service, UUID character, BleReadResponse response);
void write(String mac, UUID service, UUID character, byte[] value, BleWriteResponse response);
void readDescriptor(String mac, UUID service, UUID character, UUID descriptor, BleReadResponse response);
void writeDescriptor(String mac, UUID service, UUID character, UUID descriptor, byte[] value, BleWriteResponse response);
void writeNoRsp(String mac, UUID service, UUID character, byte[] value, BleWriteResponse response);
void notify(String mac, UUID service, UUID character, BleNotifyResponse response);
void unnotify(String mac, UUID service, UUID character, BleUnnotifyResponse response);
void indicate(String mac, UUID service, UUID character, BleNotifyResponse response);
void unindicate(String mac, UUID service, UUID character, BleUnnotifyResponse response);
void readRssi(String mac, BleReadRssiResponse response);
void search(SearchRequest request, SearchResponse response);
void stopSearch();
void registerBluetoothStateListener(BluetoothStateListener listener);
void unregisterBluetoothStateListener(BluetoothStateListener listener);
void registerBluetoothBondListener(BluetoothBondListener listener);
void unregisterBluetoothBondListener(BluetoothBondListener listener);
void clearRequest(String mac, int type);
void refreshCache(String mac);
}