Flutter:手把手教你進行BLE應用的開發-flutter_blue

一、寫在前面的話

本文主要介紹在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對設備進行讀寫的詳細步驟以及一些基本方法和注意事項,如果有問題的同學歡迎留言,博主會一一解答的。技術在於分享,開源的樂趣也在於此,如果本文有不夠嚴謹的地方還望大佬支持。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章