一、寫在前面的話
本文主要介紹在Flutter環境下開發BLE應用。主要包含以下內容:判斷藍牙是否開啓、判斷是否有位置權限、掃描設備、
連接設備、監聽設備上報的數據(Notify)、向設備發送數據、監聽設備的斷開等。內容雖然簡單,但是很詳細。
二、開始
1、使用到的庫
flutter_blue: ^0.7.1+1
permission_handler: "^3.2.0" # 權限
衆所周知,Flutter要使用原生的能力,就需要有原生庫的支持,這裏我們使用了flutter_blue來開發跟BLE相關的功能,permission_handler來開發權限檢測以及申請權限的功能。在使用flutter_blue開啓掃描的時候,插件會彈出系統的權限申請窗口,但是點擊授權以後報了一個空指針,可能是插件存在的一個BUG,所以這裏我們用permission_handler插件來處理權限相關的問題。(友情提示:在Android上掃描Ble需要位置權限)
2、flutter_blue的用法
import 'package:flutter_blue/flutter_blue.dart';
FlutterBlue flutterBlue = FlutterBlue.instance;
導包和初始化。
3、判斷藍牙是否開啓
@override
void initState() {
super.initState();
flutterBlue.state.listen((state){
if(state == BluetoothState.on){
print('藍牙狀態爲開啓');
isBleOn = true;
}else if(state == BluetoothState.off){
print('藍牙狀態爲關閉');
isBleOn = false;
}
});
}
在路由初始化的時候開啓對藍牙狀態的監聽。
if(!isBleOn){
ToastUtils.toast(context, "手機藍牙未打開,請打開後再掃描設備");
return;
}
在開始之前對藍牙開啓狀態進行判斷。
4、判斷位置權限
PermissionUtils.checkPermissions(PermissionGroup.location).then((v) {
if (v) {
Navigator.pushNamed(context, "/device_page");
} else {
PermissionUtils.showDialog(context, "提示", "掃描藍牙需要位置權限", () async {
Navigator.pop(context);
await PermissionHandler()
.requestPermissions([PermissionGroup.location]);
PermissionStatus permission = await PermissionHandler()
.checkPermissionStatus(PermissionGroup.location);
if (permission == PermissionStatus.granted) {
Navigator.pushNamed(context, "/device_page");
} else {
print("no Permission to scan ble");
ToastUtils.toast(context, "權限開啓失敗,請在系統設置中開啓!");
}
}, () {
Navigator.pop(context);
});
}
});
以上是對位置權限的處理,如果有,就進入掃描設備頁面,沒有的話申請權限,申請完之後在對其進行判斷。因爲本文的重點是ble,這裏不對權限申請插件做過多的介紹。(PermissionUtils,dialog的源碼會在文末附上)
5、掃描設備
flutterBlue.scan().listen((scanResult) {
// do something with scan result
var device = scanResult.device;
if (device.name.length > 10) {
if (deviceSet.indexOf(device) == -1) {
setState(() {
deviceSet.add(device);
});
}
print(
'${device.name} found! rssi: ${scanResult.rssi},address:${device.id}');
}
});
使用api進行ble掃描,我對藍牙名進行了過濾,記得要存起來哦,連接的時候要用的。
6、連接設備
await device.connect(autoConnect: false, timeout: Duration(seconds: 10));
這裏的連接參數可以根據需要自己進行設置,我這裏設置了10秒連接超時。這裏我們一般還不能認爲連接成功,還需要找到對應的讀寫服務和特徵值。
BluetoothCharacteristic mCharacteristic;
List<BluetoothService> services = await device.discoverServices();
services.forEach((service) {
if (service.uuid.toString() == GattAttributes.BLE_SPP_SERVICE_READ) {
List<BluetoothCharacteristic> characteristics =
service.characteristics;
characteristics.forEach((characteristic) {
if (characteristic.uuid.toString() ==
GattAttributes.BLE_SPP_NOTIFY_CHARACTERISTIC) {
mCharacteristic = characteristic;
}
});
}
// do something with service
});
以上便是根據uuid在對應的讀寫服務中找到對應Characteristic,至此,連接過程便已經完成了,可以進行頁面跳轉了。
7、讀取設備的心跳
if (mNotifyCharacteristic != null) {
mNotifyCharacteristic.setNotifyValue(true);
mNotifyCharacteristic.value
.listen((value) => {print("device is online: " + value.toString())});
}
通過第6點的方法,找到可以notify的Characteristic,開啓notify,然後監聽其值。這裏的setNotifyValue可能會有異常,具體請
參考我的前篇文章點我點我。下圖是藍牙設備傳回的心跳。
8、向設備發送數據
Future<Null> write(List<int> value, {bool withoutResponse = false})
我先查看源碼可知write方法的參數是一個int型的list,那麼我們只需把我們需要發送的數據放進這個list中就行了。
mWriteCharacteristic.write([0x00,0x01]);
同樣,獲取mWriteCharacteristic的方法如上第6點所示。
9、監聽設備的斷開
device.state.listen((state){
if(state == BluetoothDeviceState.disconnected){
DialogUtils.showOneDialog(context, "提示", "設備已斷開連接", (){
//do something
});
}
});
10、在不用頁面獲取device
await flutterBlue.connectedDevices.then((list) => {
if (list.length == 0) {Navigator.pop(context)} else {device = list[0]}
});
在不同的頁面(路由)需要對設備進行讀寫操作,在設備的連接池中獲取。
三、總結
本文歸納了flutter下使用ble對設備進行讀寫的詳細步驟以及一些基本方法和注意事項,如果有問題的同學歡迎留言,博主會一一解答的。技術在於分享,開源的樂趣也在於此,如果本文有不夠嚴謹的地方還望大佬支持。