蓝牙扫描启动 SwiftUI 后渲染列表
Posted
技术标签:
【中文标题】蓝牙扫描启动 SwiftUI 后渲染列表【英文标题】:Render List after Bluetooth Scanning starts SwiftUI 【发布时间】:2020-02-02 23:43:05 【问题描述】:我正在尝试使用 SwiftUI 制作蓝牙扫描和连接应用程序。当蓝牙扫描开始时,我在刷新 SwiftUI 中的列表视图时遇到问题,并且我得到了一些带有 RSSI 值的外围设备名称。任何指导都会很有用。代码如下:
首先,我有一个 SwiftUI 视图,其中包含一个列表和 HorizontalView 中的文本。稍后我将使用 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 列表的范围内进出时显示它们。 谢谢。
【问题讨论】:
您愿意分享您的完整(完成)代码吗?原因是您似乎使用 SwiftUI 和 BLE 创建了一个更新的示例。 如果你还有代码的话,还要找一个 SwiftUI 和 BLE 的例子 您介意分享您已完成(已解决)的项目并提供链接吗? @Anuj 大家好。我无法共享代码,因为它与公司代码混杂在一起,需要一些时间和精力来清理它。但是,您可以在这里查看类似的方法:novelbits.io/intro-ble-mobile-development-ios-part-2 【参考方案1】:您在这里没有状态,也无法更新该状态。我可能会将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
中更新。
【讨论】:
感谢分享!正是我想要的! 我认为@Publish
应该是@Published
我需要完整的代码?以上是关于蓝牙扫描启动 SwiftUI 后渲染列表的主要内容,如果未能解决你的问题,请参考以下文章
您如何在 Swift Playgrounds 中的 iPad 上的 SwiftUI 中渲染 Text("Content") 与 Mac 上的 Xcode?
SwiftUI - 从 Swift 类启动的可观察对象不会更新 ContentView() 上的 @ObservedObject