如何监控多个 iBeacon 并根据每个信标更改 UILabel?

Posted

技术标签:

【中文标题】如何监控多个 iBeacon 并根据每个信标更改 UILabel?【英文标题】:How can I monitor multiple iBeacons and change a UILabel based on each beacon? 【发布时间】:2019-07-10 18:24:39 【问题描述】:

我在同时监控多个信标时遇到了问题。我的代码只使用一个就可以正常工作,但我似乎无法弄清楚如何监控多个信标并更新 UILabel。

当我打开信标时,它们都被监控和识别,但我的手机无法在视图中显示正确的标签。它在 distanceReading.text 中不断显示“UNKOWN”,除非它是函数中的最后一个信标(Estimote)。

我还遇到了一些其他问题,即更新信标的名称。我不确定如何调用信标标识符,这将是理想的方式(类似于 beacon.identifier)。我尝试创建另一个变量并通过每次信标扫描更新名称,但它只扫描最后一个并且不会更改。我希望它会在检测到它时对其进行扫描,从而允许我在检测到新信标时更改变量。

我尝试将所有信标放在一个 startScanning() 函数中,为每个单独的信标提供它所在的唯一 UUID 并使用 locationManager.startMonitoring() 和 locationManager.startRangingBeacon()。然后我尝试使用每个 UUID、主要、次要和标识符的参数创建一个 startScanning() 函数,然后为每个信标调用该函数。

class ViewController: UIViewController, CLLocationManagerDelegate 

    @IBOutlet var distanceReading: UILabel!
    @IBOutlet var nameLabel: UILabel!
    var locationManager: CLLocationManager?
    var beaconDict: [String: String]?
    var labelName: String?

    override func viewDidLoad() 
        super.viewDidLoad()

        locationManager = CLLocationManager()
        locationManager?.delegate = self
        locationManager?.requestAlwaysAuthorization()

        alertShown = false

        view.backgroundColor = .gray  // default is in "unknown mode"

    

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) 
        if status == .authorizedAlways 
            // Can we monitor beacons or not?
            if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) 
                //  Can we detect the distance of a beacon?
                if CLLocationManager.isRangingAvailable() 
                    startScanning(uuid: UUID(uuidString: "5A4BCFCE-174E-4BAC-A814-092E77F6B7E5")!, major: 123, minor: 456, identifier: "Apple Beacon", name: "Apple")
                    startScanning(uuid: UUID(uuidString: "2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6")!, major: 123, minor: 456, identifier: "Radius Beacon", name: "Radius")
                    startScanning(uuid: UUID(uuidString: "5AFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")!, major: 123, minor: 456, identifier: "Red Bear Beacon", name: "Red Bear")
                    startScanning(uuid: UUID(uuidString: "B9407F30-F5F8-466E-AFF9-25556B57FE6D")!, major: 123, minor: 456, identifier: "Estimote", name: "Estimote")
                
            
        
    

    func startScanning(uuid: UUID, major: UInt16, minor: UInt16, identifier: String, name: String) 
        let uuidApple = uuid
        let beaconRegion1 = CLBeaconRegion(proximityUUID: uuidApple, major: major, minor: minor, identifier: identifier)
        locationManager?.startMonitoring(for: beaconRegion1)
        locationManager?.startRangingBeacons(in: beaconRegion1)
        labelName = name
    

    func update(distance: CLProximity) 
        UIView.animate(withDuration: 1) 
            switch distance 
            case .far:
                self.view.backgroundColor = .blue
                self.distanceReading.text = "FAR"
            case .near:
                self.view.backgroundColor = .orange
                self.distanceReading.text = "NEAR"
            case .immediate:
                self.view.backgroundColor = .red
                self.distanceReading.text = "RIGHT HERE"
            default:
                self.view.backgroundColor = .gray
                self.distanceReading.text = "UNKNOWN"
            
        
    

    func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) 
        if let beacon = beacons.first 
            nameLabel.text = labelName
            update(distance: beacon.proximity)
         else 
            update(distance: .unknown)
        
    

我希望每次检测到新的信标时,我的标签都会相应更改。这适用于称为 LAST 的信标,但不是前三个。颜色改变了,但标签拒绝改变。我还想找到一种方法来调用我在 CLBeaconRegion 中设置的信标标识符。

【问题讨论】:

【参考方案1】:

尝试像 for beacon in beacons 那样遍历所有远程信标,而不是像 beacons.first 那样只使用数组中的第一个。

【讨论】:

所以我想到了这个,但我不知道如何测试它。现在我正在使用信标应用程序来测试这一点,所以我一次只能激活一个信标(只有一个额外的设备)。但是,我仍然不知道它是否会解决问题,因为当我在检查 beacon == beacon.first 后打印(信标)时,它总是会打印正确的信标信息。它只是无法在我的 switch 语句中正确更新 distanceReading.text (除非它是最后一个信标)。如果它是前三个信标中的任何一个,它只会显示“未知”【参考方案2】:

您对信标名称的问题是labelName 是一个字符串,而您在startScanning 中设置了它的值。每次调用时,startScanning 都会覆盖之前的 labelName 值。自从您最后一次调用startScanning 以来,您提供了名称​​Estimote,这是您将始终在nameLabel 中看到的值。

您有一个beaconDict 属性,表明您可能一直在考虑这个问题,但没有继续。

我要做的是创建一个Beacon 结构来保存信标的所有属性,包括它的name,创建此结构的实例以传递给startScanning,并将这些实例存储在[String:Beacon] 中字典。使用 UUID 的字符串作为键。然后,我们你得到一个回调,你可以使用信标标识符从字典中找到对应的Beacon,并得到它的name

为什么距离总是未知的,大卫是对的;您将在 didRangeBeacons 回调中收到 4 个信标。由于您只有一个物理信标,因此您当前激活的信标以外的所有信标都是未知的,但您只查看第一个。

您可能会发现使用每个信标一行的表格视图比使用单个标签更容易。

【讨论】:

对于 nameLabel 问题,我确实得出了与您相同的结论。你是对的,我尝试了字典并失败了。我还没有尝试过自定义结构,我应该想到的!然后它可能会使我的字典更容易并解决标识符问题。我确实认为信标列表的问题还有更多。我一次只有一个信标处于活动状态,因此只有“第一个”信标始终是唯一的信标。距离确实有效,或者至少是颜色部分。只是标签不会从未知更新,虽然,也许上面的解决方案仍然可以解决它! 当您收到有关非活动信标的更新时,您会更改文本但不会更改颜色,这就是您总是看到“未知”的原因。显示了活动信标的信标距离,但很快被非活动信标覆盖。设置距离文本时添加打印语句,您将看到发生了什么。同样,tableview 将使这更简单 好吧,我想我明白了。我会尝试一下,看看会发生什么!感谢您的建议!我会告诉你它是否有效! 感谢您的帮助。我让它工作了。我不知道这是否是“最好的”方式,但我仍在学习。我创建了一个 Beacon 结构来保存所有信标属性,创建了一个数组 [Beacon](我的结构),然后在它们上循环 startScanning()。我删除了位置管理器中的 else 语句(以停止更新 .unknown),然后将我的名称标签与结构标识符匹配。将来我可能会为此研究表格视图,但我只是想完成本教程而暂时不做太多更改!感谢您和大卫的所有帮助!

以上是关于如何监控多个 iBeacon 并根据每个信标更改 UILabel?的主要内容,如果未能解决你的问题,请参考以下文章

信标区域的 iBeacon 监控模式接近度

基于 UUID 监控 iBeacon 区域时,何时收到通知?

Swift iBeacon 只有一个信标被监控

cordova-plugin-ibeacon:当监控发现信标时,主要/次要不可用

从 Appdelegate 设置 iBeacon 操作和监控

更改 iBeacon 的 Minor 和 Major 值会阻止我找到信标。 (iBeacon/Xcode)