【问题标题】:iOS App working strangely with the iBeaconiOS 应用程序与 iBeacon 的工作异常
【发布时间】:2018-04-06 23:18:04
【问题描述】:

我正在设计一个 iBeacon 设备以与 iPhone 上的应用程序配合使用。问题是与识别信标的应用程序存在非常奇怪的不一致。我主要从这份文档中了解到信标:https://developer.apple.com/ibeacon/Getting-Started-with-iBeacon.pdf 以下是对我的系统的简短介绍:

设备: - 按下设备上的按钮会以 10Hz 的频率触发 iBeacon BLE 广告约两秒钟​​。 - 设备循环通过 20 个 UUID,以便用于每个不同的按钮按下。这是为了在应用程序没有时间“超出范围”时快速按下按钮时区分按钮按下。 20 UUID 是 Apple 规定的允许应用监控的限制。

应用程序: - 应用程序搜索 20 个 UUID 中的任何一个。 - 检测时,进入和退出事件会触发一些应用程序事件,并在其简短分配的后台时间中简要使用测距来提取 Maj. Min。对值。

测试: 为了进行测试,应用程序设置为在发生输入、范围和退出事件时显示弹出窗口。测试在前台应用程序进行。我按下按钮,观察输入和范围事件,并等到它退出该区域后再按下。使用 BLE 扫描仪进行的测试表明,该设备运行良好,并且正在广播 100% 的按钮按下,正确循环通过 20 个 UUID。

问题: 在应用内测试中,问题出现并遵循一种奇怪的模式。该应用程序可以很好地识别前 9 次左右的按钮按下/UUID。之后,通常在第 10 次按下按钮时,应用程序会停止响应信标。没有弹出窗口。在我的 BLE 扫描仪上,我可以清楚地看到设备正在正确广播。当设备循环回到第一个 UUID 时,设备通常会再次开始识别信标。我说“通常”是因为它有时会在第 11 个 UUID 处停止,有时会在第 20 个 UUID 重新开始,甚至有一次我什至随机看到了第 12 个 UUID,但通常在后半部分存在这个间隙或“死区” UUID 的。如果我快速按下按钮,我可以让它工作。弹出窗口会很快出现并显示 UUID 的循环一直到 20,所以我知道 UUID 很好,并且应用程序有能力。当按钮按下之间的时间超过一分钟左右时,就会出现问题。 我可以做的另一件奇怪的事情是捣碎按钮,成功地看到应用程序弹出窗口,然后当我处于 10-20 的 UUID“死区”范围内时停止,比如列表中的 UUID 14。如果我等待一分钟并再次按下,则在按下 7 次按钮后再次到达第一个 UUID 之前它不会起作用。 其他注意事项: - 我并不总是看到区域退出弹出窗口,有时它们退出非常快,有时需要更长的时间。 - 模式不是严格一致的。它有时会有所不同。有时它会工作一个完整的周期,但它通常属于这种间隙模式。 - 我在 iOS 11 和 10 的两部手机上进行测试。

想法: 奇怪的是,它几乎总是想在第一个 UUID 处重新开始工作。所以这让我觉得这不是一个绝对的时间问题,否则差距会在时间上存在,而不是在 UUID 列表中。 奇怪的是,它在快速循环时起作用。

Apple 是否在 10 之后将另一个 UID 列入黑名单,因为它认为我正在向 UUID 发送垃圾邮件,或者扫描太多 UUID 太快? 这是我不知道的更深层次的 iOS BLE 缓存问题吗? 这是某种iOS BLE后台扫描调度程序的时间问题吗? 这听起来像是应用代码中的错误吗?

感谢任何帮助或想法!

这是我的信标事件应用代码-

func locationManager(_ manager: CLLocationManager, didRangeBeacons 信标: [CLBeacon], in region: CLBeaconRegion) {

    let knownBeacons = beacons.filter{ $0.proximity != CLProximity.unknown }

    for closestBeacon in knownBeacons
    {
        let closestBeaconFound = closestBeacon as CLBeacon
        var beaconProximity = ""

        switch (closestBeaconFound.proximity)
        {
            case CLProximity.unknown:    beaconProximity = "Unknown"
            case CLProximity.far:        beaconProximity = "Far"
            case CLProximity.near:       beaconProximity = "Near"
            case CLProximity.immediate:  beaconProximity = "Immediate"
        }

        if inDidRangeShowPopup == false{
            HelperClass.showAlert(value: "identifier and proximityUUID in did Range: \(region.identifier) \(region.proximityUUID)")
            inDidRangeShowPopup = true
            let when = DispatchTime.now() + 5 // change 2 to desired number of seconds
            DispatchQueue.main.asyncAfter(deadline: when) {
                inDidRangeShowPopup = false
            }
        }

        let status = "Ranging"
        let uuid = String(describing: region.proximityUUID)
        let major = closestBeaconFound.major as! Int
        let minor = closestBeaconFound.minor as! Int
        var pressType = ""

        print("closestBeacon",closestBeaconFound.proximityUUID, closestBeaconFound.major,closestBeaconFound.minor,closestBeaconFound.proximity.rawValue, beaconProximity, closestBeaconFound.accuracy,closestBeaconFound.rssi)

        let majorHex = String( closestBeaconFound.major as! Int, radix : 2)
        print("Hex Major : \(majorHex)")

        let paddedBits = HelperClass.paddedBinaryString(with: majorHex)
        print("paddedBits : \(paddedBits)")

        let emergencyCode = paddedBits.substring(to: 8).asBinaryInt()
        let deviceID = paddedBits.substring(from: 8).asBinaryInt()


        if emergencyCode == 0
        {
            if iBeaconOption1Done ==  false
            {
                iBeaconOption1Done = true

                let when = DispatchTime.now() + 10 // change 2 to desired number of seconds
                DispatchQueue.main.asyncAfter(deadline: when) {
                    iBeaconOption1Done = false
                }

                for addressStr in HelperClass.getMyMacAddres()
                {
                    let address = addressStr as! String
                    if address == String(deviceID!)
                    {
                        pressType = "option1"
                        self.setDeviceStatusAndSetTimer(mac_address: address , deviceId : deviceID!, status: status, uuid: uuid, major: major, minor: minor, pressType: pressType)

                        if HelperClass.getAppFlagValueForAttribute (attribute : "isHomeViewed") == true  {

                            self.option1Service(flag : "option1", deviceId: deviceID!)
                        }
                        else{
                            self.option1Service(flag : "test_option1", deviceId: deviceID!)
                        }
                    }
                }

            }
        }
        else  if emergencyCode == 1
        {
            print("Call option2")
            for addressStr in HelperClass.getMyMacAddres()
            {
                let address = addressStr as! String
                if address == String(deviceID!)
                {
                    pressType = "Option2"
                    self.setDeviceStatusAndSetTimer(mac_address: address , deviceId : deviceID!, status: status, uuid: uuid, major: major, minor: minor, pressType: pressType)
                }
            }
            if HelperClass.getAppFlagValueForAttribute (attribute : "isHomeViewed") == true  {

                self.sendOption2 (flag : "device" ,deviceId : deviceID!)
            }
        }
        else if emergencyCode == 2
        {
            print("Call Advertisement")

            if iBeaconStatusSent == false
            {
                iBeaconStatusSent = true

                let when = DispatchTime.now() + 5 // change 2 to desired number of seconds
                DispatchQueue.main.asyncAfter(deadline: when) {
                    iBeaconStatusSent = false
                }

                for addressStr in HelperClass.getMyMacAddres()
                {
                    let address = addressStr as! String
                    if address == String(deviceID!)
                    {
                        pressType = "Check in"
                        self.setDeviceStatusAndSetTimer(mac_address: address , deviceId : deviceID!, status: status, uuid: uuid, major: major, minor: minor, pressType: pressType)
                    }
                }
            }
        }

    }

}

func getDefaultBeacons() -> [CLBeaconRegion] {

    return [

        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+3)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+4)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+5)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+6)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+7)"),

        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+8)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+9)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+10)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+11)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+12)"),

        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+13)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+14)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+15)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+16)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+17)"),

        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+18)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+19)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+20)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+21)"),
        CLBeaconRegion(proximityUUID: UUID(uuidString: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")!, identifier: "Fl\(BeaconIdentifierIntValue+22)")
    ]
}

func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {

    print("iBeacon delegate:didEnterRegion called")

    DispatchQueue.main.async() {

        if let beaconRegion = region as? CLBeaconRegion {

            print("identifier and proximityUUID in didEnterRegion: \(beaconRegion.identifier) \(beaconRegion.proximityUUID)")

            HelperClass.showAlert(value: "identifier and proximityUUID in didEnterRegion: \(beaconRegion.identifier) \(beaconRegion.proximityUUID)")

        }
        else{
            print("Wrong Format in didEnterRegion")
            Answers.logCustomEvent(withName: "didEnterRegion", customAttributes: [
                "error_text":  "CLBeaconRegion Object Not Created",
                "app_version" : AppVersion,
                "app_build" : AppBuild
                ])
        }
    }

}

func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {

    print("iBeacon delegate:didExitRegion called")

    DispatchQueue.main.async() {

        if let beaconRegion = region as? CLBeaconRegion {

            print("identifier and proximityUUID in didExitRegion: \(beaconRegion.identifier) \(beaconRegion.proximityUUID)")

            HelperClass.showAlert(value: "identifier and proximityUUID in didExitRegion: \(beaconRegion.identifier) \(beaconRegion.proximityUUID)")

        }
        else{
            print("Wrong Format in didExitRegion")
            Answers.logCustomEvent(withName: "didExitRegion", customAttributes: [
                "error_text":  "CLBeaconRegion Object Not Created",
                "app_version" : AppVersion,
                "app_build" : AppBuild
                ])
        }
    }

}

【问题讨论】:

    标签: swift cllocationmanager ibeacon locationmanager beacon


    【解决方案1】:

    @davidgyoug 你的回答给了我很大的启发!好像解决了!最初您建议的代码不起作用,但后来您提到已经注册的区域让我意识到我们制作了另一个但完全不同的测试应用程序来监控信标。它已注册到相同的 Apple ID、开发人员和 Test Flight 帐户。删除该应用程序,重新启动手机,并清除 locationManager 缓存,似乎解决了它!另一个提示是,它在我们今天测试的其他从未参与开发的 iPhone 上运行良好。

    这是否意味着每个 Apple ID/开发者帐户只允许 20 个监控区域,而不是严格每个应用程序?手机上监控区域的其他第 3 方应用程序是否也会干扰该应用程序?

    感谢您的帮助!

    【讨论】:

      【解决方案2】:

      我怀疑代码在注册所有 20 个区域之前达到了 20 个区域的限制。这可能是因为 CoreLocation 缓存了之前注册的应用程序运行的区域,因此可能还有其他预先存在的区域来自早期版本代码的区域。

      您可以通过查找带有 kCLErrorRegionMonitoringFailure 错误代码的locationManager:monitoringDidFailForRegion:withError: 的回调来查看是否发生这种情况。

      如果确实如此,您可以通过调用locationManager.monitoredRegions 清除已注册的区域,然后遍历结果并为每个区域调用locationManager.stopMonitoring(region: region)。但是请注意,您不应该在每次运行代码时都执行此清除过程,因为尽早将您的区域注册到操作系统并始终取消注册和重新注册您的地区将使您排在最后。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-04
        • 2014-11-09
        • 1970-01-01
        • 2016-01-28
        • 1970-01-01
        • 2013-03-03
        相关资源
        最近更新 更多