蓝牙扫描启动SwiftUI后的渲染列表

时间:2019-10-04 15:53:56

标签: ios swift bluetooth swiftui

我正在尝试使用SwiftUI进行蓝牙扫描并连接应用程序。蓝牙扫描开始时,我在刷新SwiftUI中的列表视图时遇到问题,并且得到了一些带有RSSI值的外设名称。任何指导都是有用的。代码如下:

首先,我有一个SwiftUI视图,其中包含列表和其中的Horizo​​ntalView中的文本。稍后我将使用ForEach(),但现在我只用一个文本就保持了简单性。

import SwiftUI

struct ContentView: View {
    var body: some View {
        List{
            // ForEach: Loop here to list all BLE Devices in "devices" array
            // Monitor "devices" array for changes. As changes happen, Render the Body again.
            HStack{
                Text("Device-1")
                    .onTapGesture {
                        // To Do: Call Connect BLE Device
                        print("Device-1 Connected.")
                    }
                }
            }.navigationBarTitle("BLE Devices")
            .onAppear(perform: connectBLEDevice)
    }

    private func connectBLEDevice(){
        let ble = BLEConnection()
        // Start Scanning for BLE Devices
        ble.startCentralManager()
    }
}

// UIHosting Controller
var child = UIHostingController(rootView: ContentView())

这是我使用的用于扫描并连接到蓝牙设备的代码:

import Foundation
import UIKit
import CoreBluetooth

open class BLEConnection: NSObject, CBPeripheralDelegate, CBCentralManagerDelegate {

    // Properties
    private var centralManager: CBCentralManager! = nil
    private var peripheral: CBPeripheral!

    public static let bleServiceUUID = CBUUID.init(string: "XXXX")
    public static let bleCharacteristicUUID = CBUUID.init(string: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX")

    // Array to contain names of BLE devices to connect to.
    // Accessable by ContentView for Rendering the SwiftUI Body on change in this array.
    var scannedBLEDevices: [String] = []

    func startCentralManager() {
        self.centralManager = CBCentralManager(delegate: self, queue: nil)
        print("Central Manager State: \(self.centralManager.state)")
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.centralManagerDidUpdateState(self.centralManager)
        }
    }

    // Handles BT Turning On/Off
    public func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch (central.state) {
           case .unsupported:
            print("BLE is Unsupported")
            break
           case .unauthorized:
            print("BLE is Unauthorized")
            break
           case .unknown:
            print("BLE is Unknown")
            break
           case .resetting:
            print("BLE is Resetting")
            break
           case .poweredOff:
            print("BLE is Powered Off")
            break
           case .poweredOn:
            print("Central scanning for", BLEConnection.bleServiceUUID);
            self.centralManager.scanForPeripherals(withServices: [BLEConnection.bleServiceUUID],options: [CBCentralManagerScanOptionAllowDuplicatesKey : true])
            break
        }

       if(central.state != CBManagerState.poweredOn)
       {
           // In a real app, you'd deal with all the states correctly
           return;
       }
    }


    // Handles the result of the scan
    public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        print("Peripheral Name: \(String(describing: peripheral.name))  RSSI: \(String(RSSI.doubleValue))")
        // We've found it so stop scan
        self.centralManager.stopScan()
        // Copy the peripheral instance
        self.peripheral = peripheral
        self.scannedBLEDevices.append(peripheral.name!)
        self.peripheral.delegate = self
        // Connect!
        self.centralManager.connect(self.peripheral, options: nil)
    }


    // The handler if we do connect successfully
    public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        if peripheral == self.peripheral {
            print("Connected to your BLE Board")
            peripheral.discoverServices([BLEConnection.bleServiceUUID])
        }
    }


    // Handles discovery event
    public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        if let services = peripheral.services {
            for service in services {
                if service.uuid == BLEConnection.bleServiceUUID {
                    print("BLE Service found")
                    //Now kick off discovery of characteristics
                    peripheral.discoverCharacteristics([BLEConnection.bleCharacteristicUUID], for: service)
                    return
                }
            }
        }
    }

    // Handling discovery of characteristics
    public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        if let characteristics = service.characteristics {
            for characteristic in characteristics {
                if characteristic.uuid == BLEConnection.bleServiceUUID {
                    print("BLE service characteristic found")
                } else {
                    print("Characteristic not found.")
                }
            }
        }
    }
}

这里的任务是扫描外围设备,并显示它们在SwiftUI列表中的进出范围。 谢谢。

1 个答案:

答案 0 :(得分:2)

您在这里没有状态,也无法更新该状态。我可能会将BLEConnection设为ObservableObject,然后将@Publish设为设备数组:

open class BLEConnection: ..., ObservableObject {
    @Publish var scannedBLEDevices: [Device] = [] // keep as [String] for initial debugging if you want
}

然后在您的ContentView中订阅这些更改:

struct ContentView: View {
    @ObservedObject var bleConnection = BLEConnection()

    var body: some View {
        // if still `[String]` then \.self will work, otherwise make `Device` `Identifiable`
        List(bleConnection.devices, id: \.self) { device in
            Text(verbatim: device)
        }
    }
}

现在,当您的连接将设备添加/删除到scannedBLEDevices时,它将在您的ContentView中自动更新。