Android BLE基礎操作框架,基於回撥,操作簡單。包含掃描、多連線、廣播包解析、服務讀寫及通知等功能。
專案依賴:
compile 'com.vise.xiaoyaoyou:baseble:2.0.0'
功能
支援多裝置連線管理;
支援廣播包解析;
支援自定義掃描過濾條件;
支援根據裝置名稱正規表示式過濾掃描裝置;
支援根據裝置訊號最小值過濾掃描裝置;
支援根據裝置名稱或 MAC 地址列表過濾掃描裝置;
支援根據裝置 UUID 過濾掃描裝置;
支援根據指定裝置名稱或 MAC 地址搜尋指定裝置;
支援連線裝置失敗重試;
支援操作裝置資料失敗重試;
支援繫結資料收發通道,同一種能力可繫結多個通道;
支援註冊和取消通知監聽;
支援配置最大連線數,超過最大連線數時會依據 Lru 演算法自動斷開最近最久未使用裝置;
支援配置掃描、連線和運算元據超時時間;
支援配置連線和運算元據重試次數以及重試間隔時間。
簡介
打造該庫的目的是為了簡化藍芽裝置接入的流程。該庫是 BLE 操作的基礎框架,只處理 BLE 裝置通訊邏輯,不包含具體的資料處理,如資料的分包與組包等。該庫提供了多裝置連線管理,可配置最大連線數量,並在超過最大連線數時會依據 Lru 演算法自動斷開最近最久未使用裝置。該庫還定製了常用的掃描裝置過濾規則,也支援自定義過濾規則。該庫所有操作都採用回撥機制告知上層呼叫的結果,操作簡單,接入方便。
效果展示
使用介紹
許可權配置
6.0 以下系統不需要配置許可權,庫中已經配置瞭如下許可權:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>複製程式碼
而如果手機系統在 6.0 以上則需要配置如下許可權:
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>複製程式碼
因為藍芽在 6.0 以上手機使用了模糊定位功能,所以需要新增模糊定位許可權。
引入 SDK
在工程 module 的 build.gradle 檔案中的 dependencies 中新增如下依賴:
compile 'com.vise.xiaoyaoyou:baseble:2.0.0'複製程式碼
構建完後就可以直接使用該庫的功能了。
初始化
在使用該庫前需要進行初始化,初始化程式碼如下所示:
//藍芽相關配置修改
ViseBle.config()
.setScanTimeout(-1)//掃描超時時間,這裡設定為永久掃描
.setConnectTimeout(10 * 1000)//連線超時時間
.setOperateTimeout(5 * 1000)//設定資料操作超時時間
.setConnectRetryCount(3)//設定連線失敗重試次數
.setConnectRetryInterval(1000)//設定連線失敗重試間隔時間
.setOperateRetryCount(3)//設定資料操作失敗重試次數
.setOperateRetryInterval(1000)//設定資料操作失敗重試間隔時間
.setMaxConnectCount(3);//設定最大連線裝置數量
//藍芽資訊初始化,全域性唯一,必須在應用初始化時呼叫
ViseBle.getInstance().init(this);複製程式碼
初始化可以是在 Application 中也可以是在 MainActivity 中,只需要是在使用藍芽功能前就行。還有需要注意的是,藍芽配置必須在藍芽初始化前進行修改,如果預設配置滿足要求也可以不修改配置。
裝置掃描
庫中針對裝置掃描定義了幾種常用過濾規則,如果不滿足要求也可以自己定義過濾規則,下面針對庫中提供的過濾規則使用方式一一介紹:
掃描所有裝置
ViseBle.getInstance().startScan(new ScanCallback(new IScanCallback() { @Override public void onDeviceFound(BluetoothLeDeviceStore bluetoothLeDeviceStore) { } @Override public void onScanFinish(BluetoothLeDeviceStore bluetoothLeDeviceStore) { } @Override public void onScanTimeout() { } }));複製程式碼
掃描指定裝置 MAC 的裝置
//該方式是掃到指定裝置就停止掃描 ViseBle.getInstance().startScan(new SingleFilterScanCallback(new IScanCallback() { @Override public void onDeviceFound(BluetoothLeDeviceStore bluetoothLeDeviceStore) { } @Override public void onScanFinish(BluetoothLeDeviceStore bluetoothLeDeviceStore) { } @Override public void onScanTimeout() { } }).setDeviceMac(deviceMac));複製程式碼
掃描指定裝置名稱的裝置
//該方式是掃到指定裝置就停止掃描 ViseBle.getInstance().startScan(new SingleFilterScanCallback(new IScanCallback() { @Override public void onDeviceFound(BluetoothLeDeviceStore bluetoothLeDeviceStore) { } @Override public void onScanFinish(BluetoothLeDeviceStore bluetoothLeDeviceStore) { } @Override public void onScanTimeout() { } }).setDeviceName(deviceName));複製程式碼
掃描指定 UUID 的裝置
ViseBle.getInstance().startScan(new UuidFilterScanCallback(new IScanCallback() { @Override public void onDeviceFound(BluetoothLeDeviceStore bluetoothLeDeviceStore) { } @Override public void onScanFinish(BluetoothLeDeviceStore bluetoothLeDeviceStore) { } @Override public void onScanTimeout() { } }).setUuid(uuid));複製程式碼
掃描指定裝置 MAC 或名稱集合的裝置
ViseBle.getInstance().startScan(new ListFilterScanCallback(new IScanCallback() { @Override public void onDeviceFound(BluetoothLeDeviceStore bluetoothLeDeviceStore) { } @Override public void onScanFinish(BluetoothLeDeviceStore bluetoothLeDeviceStore) { } @Override public void onScanTimeout() { } }).setDeviceMacList(deviceMacList).setDeviceNameList(deviceNameList));複製程式碼
掃描指定訊號範圍或裝置正則名稱的裝置
ViseBle.getInstance().startScan(new RegularFilterScanCallback(new IScanCallback() { @Override public void onDeviceFound(BluetoothLeDeviceStore bluetoothLeDeviceStore) { } @Override public void onScanFinish(BluetoothLeDeviceStore bluetoothLeDeviceStore) { } @Override public void onScanTimeout() { } }).setDeviceRssi(rssi).setRegularDeviceName(regularDeviceName));複製程式碼
其中掃描到的裝置列表由 BluetoothLeDeviceStore
管理,而單個裝置資訊都統一放到BluetoothLeDevice
中,其中包含了裝置的所有資訊,如裝置名稱、裝置地址、廣播包解析資訊等,裝置的相關資訊會在裝置詳情中進行介紹。
裝置連線
裝置連線有三種方式,一種是根據裝置資訊直接進行連線,另外兩種是在沒掃描的情況下直接通過裝置名稱或裝置 MAC 進行掃描連線。三種連線方式使用如下:
根據裝置資訊連線裝置
ViseBle.getInstance().connect(bluetoothLeDevice, new IConnectCallback() { @Override public void onConnectSuccess(DeviceMirror deviceMirror) { } @Override public void onConnectFailure(BleException exception) { } @Override public void onDisconnect(boolean isActive) { } });複製程式碼
根據裝置 MAC 直接掃描並連線
ViseBle.getInstance().connectByMac(deviceMac, new IConnectCallback() { @Override public void onConnectSuccess(DeviceMirror deviceMirror) { } @Override public void onConnectFailure(BleException exception) { } @Override public void onDisconnect(boolean isActive) { } });複製程式碼
根據裝置名稱直接掃描並連線
ViseBle.getInstance().connectByName(deviceName, new IConnectCallback() { @Override public void onConnectSuccess(DeviceMirror deviceMirror) { } @Override public void onConnectFailure(BleException exception) { } @Override public void onDisconnect(boolean isActive) { } });複製程式碼
裝置詳情
DEVICE INFO(裝置資訊)
- 獲取裝置名稱(Device Name):
bluetoothLeDevice.getName()
; - 獲取裝置地址(Device Address):
bluetoothLeDevice.getAddress()
; - 獲取裝置類別(Device Class):
bluetoothLeDevice.getBluetoothDeviceClassName()
; - 獲取主要裝置類別(Major Class):
bluetoothLeDevice.getBluetoothDeviceMajorClassName()
; - 獲取服務類別(Service Class):
bluetoothLeDevice.getBluetoothDeviceKnownSupportedServices()
; - 獲取配對狀態(Bonding State):
bluetoothLeDevice.getBluetoothDeviceBondState()
;
RSSI INFO(訊號資訊)
- 獲取第一次訊號時間戳(First Timestamp):
bluetoothLeDevice.getFirstTimestamp()
; - 獲取第一次訊號強度(First RSSI):
bluetoothLeDevice.getFirstRssi()
; - 獲取最後一次訊號時間戳(Last Timestamp):
bluetoothLeDevice.getTimestamp()
; - 獲取最後一次訊號強度(Last RSSI):
bluetoothLeDevice.getRssi()
; - 獲取平均訊號強度(Running Average RSSI):
bluetoothLeDevice.getRunningAverageRssi()
;
SCAN RECORD INFO(廣播資訊)
根據掃描到的廣播包AdRecordStore
獲取某個廣播資料單元AdRecord
的型別編號record.getType()
,再根據編號獲取廣播資料單元的型別描述record.getHumanReadableType()
以及該廣播資料單元的長度及資料內容,最後通過AdRecordUtil.getRecordDataAsString(record)
將資料內容轉換成具體字串。更多關於廣播包解析可以參考Android BLE學習筆記中資料解析部分。
傳送資料
在傳送資料前需要先繫結寫入資料通道,繫結通道的同時需要設定寫入資料的回撥監聽,具體程式碼示例如下:
BluetoothGattChannel bluetoothGattChannel = new BluetoothGattChannel.Builder()
.setBluetoothGatt(deviceMirror.getBluetoothGatt())
.setPropertyType(PropertyType.PROPERTY_WRITE)
.setServiceUUID(serviceUUID)
.setCharacteristicUUID(characteristicUUID)
.setDescriptorUUID(descriptorUUID)
.builder();
deviceMirror.bindChannel(new IBleCallback() {
@Override
public void onSuccess(byte[] data, BluetoothGattChannel bluetoothGattChannel, BluetoothLeDevice bluetoothLeDevice) {
}
@Override
public void onFailure(BleException exception) {
}
}, bluetoothGattChannel);
deviceMirror.writeData(data);複製程式碼
這裡的 deviceMirror 在裝置連線成功後就可以獲取到,需要注意的是,服務一樣的情況下寫入資料的通道只需要註冊一次,如果寫入資料的通道有多個則可以繫結多個。寫入資料必須要在繫結寫入資料通道後進行,可以在不同的地方多次寫入。
接收資料
與傳送資料一樣,接收裝置傳送的資料也需要繫結接收資料通道,這裡有兩種方式,一種是可通知方式、一種是指示器方式,使用方式如下:
可通知方式
BluetoothGattChannel bluetoothGattChannel = new BluetoothGattChannel.Builder() .setBluetoothGatt(deviceMirror.getBluetoothGatt()) .setPropertyType(PropertyType.PROPERTY_NOTIFY) .setServiceUUID(serviceUUID) .setCharacteristicUUID(characteristicUUID) .setDescriptorUUID(descriptorUUID) .builder(); deviceMirror.bindChannel(new IBleCallback() { @Override public void onSuccess(byte[] data, BluetoothGattChannel bluetoothGattChannel, BluetoothLeDevice bluetoothLeDevice) { } @Override public void onFailure(BleException exception) { } }, bluetoothGattChannel); deviceMirror.registerNotify(false);複製程式碼
指示器方式
BluetoothGattChannel bluetoothGattChannel = new BluetoothGattChannel.Builder() .setBluetoothGatt(deviceMirror.getBluetoothGatt()) .setPropertyType(PropertyType.PROPERTY_INDICATE) .setServiceUUID(serviceUUID) .setCharacteristicUUID(characteristicUUID) .setDescriptorUUID(descriptorUUID) .builder(); deviceMirror.bindChannel(new IBleCallback() { @Override public void onSuccess(byte[] data, BluetoothGattChannel bluetoothGattChannel, BluetoothLeDevice bluetoothLeDevice) { } @Override public void onFailure(BleException exception) { } }, bluetoothGattChannel); deviceMirror.registerNotify(true);複製程式碼
在繫結通道後需要註冊通知,並需要在收到註冊成功的回撥時呼叫如下程式碼設定監聽:
deviceMirror.setNotifyListener(bluetoothGattInfo.getGattInfoKey(), new IBleCallback() { @Override public void onSuccess(byte[] data, BluetoothGattChannel bluetoothGattChannel, BluetoothLeDevice bluetoothLeDevice) { } @Override public void onFailure(BleException exception) { } });複製程式碼
所有裝置傳送過來的資料都會通過上面的監聽得到,如果不想監聽也可以取消註冊,使用方式如下:
deviceMirror.unregisterNotify(isIndicate);複製程式碼
isIndicate 表示是否是指示器方式。
讀取資料
由於讀取裝置資訊基本每次的通道都不一樣,所以這裡與上面收發資料有點不一樣,每次讀取資料都需要繫結一次通道,使用示例如下:
BluetoothGattChannel bluetoothGattChannel = new BluetoothGattChannel.Builder()
.setBluetoothGatt(deviceMirror.getBluetoothGatt())
.setPropertyType(PropertyType.PROPERTY_READ)
.setServiceUUID(serviceUUID)
.setCharacteristicUUID(characteristicUUID)
.setDescriptorUUID(descriptorUUID)
.builder();
deviceMirror.bindChannel(new IBleCallback() {
@Override
public void onSuccess(byte[] data, BluetoothGattChannel bluetoothGattChannel, BluetoothLeDevice bluetoothLeDevice) {
}
@Override
public void onFailure(BleException exception) {
}
}, bluetoothGattChannel);
deviceMirror.readData();複製程式碼
總結
從以上的描述中可以知道,裝置相關的所有操作都統一交給 ViseBle
進行處理,並且該類是單例模式,全域性只有一個,管理很方便。使用該庫提供的功能前必須要呼叫 ViseBle.getInstance().init(context);
進行初始化。每連線成功一款裝置都會在裝置映象池中新增一款裝置映象,該裝置映象是維護裝置連線成功後所有操作的核心類,在斷開連線時會將該裝置映象從映象池中移除,如果連線裝置數量超過配置的最大連線數,那麼裝置映象池會依據 Lru 演算法自動移除最近最久未使用裝置並斷開連線。ViseBle
中封裝了幾個常用的 API,如:開始掃描與停止掃描、連線與斷開連線、清除資源等,該庫提供的功能儘量簡單易用,這也正是該專案的宗旨。