CLLocationManager不监视区域

时间:2018-02-25 01:48:18

标签: ios swift location core-location ibeacon

我很困惑......我今天有这个工作,现在我不知道发生了什么。它不是我的iBeacon,因为我可以使用Locate iOS应用找到它。我正在创建自己的位置管理器,不确定你是否会将其称为子类,因为我是NASSbject的子类。这是:

//
//  LocationManager.swift
//  onebeacon
//
//  Created by Eamon White on 2/24/18.
//  Copyright © 2018 EamonWhite. All rights reserved.
//

import Foundation
import CoreLocation

protocol LocationManagerDelegate: class {
    func locationManagerDidUpdateLocation(_ locationManager: LocationManager, location: CLLocation)
    func locationManagerDidUpdateHeading(_ locationManager: LocationManager, heading: CLHeading, accuracy: CLLocationDirection)
    func locationManagerDidEnterRegion(_ locationManager: LocationManager, didEnterRegion region: CLRegion)
    func locationManagerDidExitRegion(_ locationManager: LocationManager, didExitRegion region: CLRegion)
    func locationManagerDidDetermineState(_ locationManager: LocationManager, didDetermineState state: CLRegionState, region: CLRegion)
    func locationManagerDidRangeBeacons(_ locationManager: LocationManager, beacons: [CLBeacon], region: CLBeaconRegion)
}


class LocationManager: NSObject, CLLocationManagerDelegate {
    private var locationManager: CLLocationManager!
    weak var delegate: LocationManagerDelegate?
    var beaconsToRange: [CLBeaconRegion]
    var currentLocation: CLLocation!

    override init() {
        self.beaconsToRange = []
        super.init()

        self.locationManager = CLLocationManager()
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
        self.locationManager.distanceFilter = kCLDistanceFilterNone
        self.locationManager.headingFilter = kCLHeadingFilterNone
        self.locationManager.pausesLocationUpdatesAutomatically = false
        self.locationManager.delegate = self

        self.enableLocationServices()
    }

    func enableLocationServices() {
        self.checkStatus(status: CLLocationManager.authorizationStatus())
    }

    func checkStatus(status: CLAuthorizationStatus) {
        switch status {
        case .notDetermined:
            // Request when-in-use authorization initially
            locationManager.requestAlwaysAuthorization()
            break

        case .restricted, .denied:
            // Disable location features
            print("send an alert that the app will not function")
            break

        case .authorizedWhenInUse:
            locationManager.requestAlwaysAuthorization()
            // Enable basic location features
            break

        case .authorizedAlways:
            locationManager.startUpdatingLocation()
            locationManager.startUpdatingHeading()
            self.monitorBeacons()
            // Enable any of your app's location features
            break
        }
    }

    func monitorBeacons() {
        print("monitorBeacons()")
        if CLLocationManager.isMonitoringAvailable(for:
            CLBeaconRegion.self) {
            print("monitorBeacons().monitoringIsAvailable")
            // Match all beacons with the specified UUID
            let proximityUUID = UUID(uuidString:
                "12345678-B644-4520-8F0C-720EAF059935")

            let beaconRegion = CLBeaconRegion(
                proximityUUID: proximityUUID!,
                major: 0x0001,
                minor: 0x0002,
                identifier: "iBeacon")

            beaconRegion.notifyEntryStateOnDisplay = true;

            self.locationManager?.startMonitoring(for: beaconRegion)
            print("\(String(describing: self.locationManager?.monitoredRegions)) + monitoredRegions")
        }
    }

    //MARK: - CLLocationManagerDelegate

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        for location in locations {
            self.delegate?.locationManagerDidUpdateLocation(self, location: location)
        }

        self.currentLocation = manager.location
    }

    func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
        self.delegate?.locationManagerDidUpdateHeading(self, heading: newHeading, accuracy: newHeading.headingAccuracy)
    }

    func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
        if region is CLBeaconRegion {
            // Start ranging only if the feature is available.
            if CLLocationManager.isRangingAvailable() {
                locationManager?.startRangingBeacons(in: region as! CLBeaconRegion)

                // Store the beacon so that ranging can be stopped on demand.
                beaconsToRange.append(region as! CLBeaconRegion)
            }
        }
        self.delegate?.locationManagerDidEnterRegion(self, didEnterRegion: region)
    }

    func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
        self.delegate?.locationManagerDidExitRegion(self, didExitRegion: region)
    }

    func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
        if region is CLBeaconRegion {
            print("determined state of beacon")
            // Start ranging only if the feature is available.
            if CLLocationManager.isRangingAvailable() {
                print("determined state of beacon and started ranging")
                locationManager?.startRangingBeacons(in: region as! CLBeaconRegion)
                // Store the beacon so that ranging can be stopped on demand.
                beaconsToRange.append(region as! CLBeaconRegion)
            }
        }

        self.delegate?.locationManagerDidDetermineState(self, didDetermineState: state, region: region)
    }

    func locationManager(_ manager: CLLocationManager,
                         didRangeBeacons beacons: [CLBeacon],
                         in region: CLBeaconRegion) {
        self.delegate?.locationManagerDidRangeBeacons(self, beacons: beacons, region: region)
    }

    func locationManagerShouldDisplayHeadingCalibration(_ manager: CLLocationManager) -> Bool {
        return true
    }

    func locationManager(_ manager: CLLocationManager,
                         didChangeAuthorization status: CLAuthorizationStatus) {
        self.checkStatus(status: status)
    }
}

在我的ViewController中,我以一种非常直接的方式使用它(在顶部:委托方法......对于问题有点无关紧要,在底部:实例化):

import UIKit
import SceneKit
import ARKit
import CoreLocation

class ViewController: UIViewController, ARSCNViewDelegate, LocationManagerDelegate {

    func locationManagerDidUpdateLocation(_ locationManager: LocationManager, location: CLLocation) {

    }

    func locationManagerDidUpdateHeading(_ locationManager: LocationManager, heading: CLHeading, accuracy: CLLocationDirection) {

    }

    func locationManagerDidEnterRegion(_ locationManager: LocationManager, didEnterRegion region: CLRegion) {

    }

    func locationManagerDidExitRegion(_ locationManager: LocationManager, didExitRegion region: CLRegion) {

    }

    func locationManagerDidDetermineState(_ locationManager: LocationManager, didDetermineState state: CLRegionState, region: CLRegion) {

    }

    func locationManagerDidRangeBeacons(_ locationManager: LocationManager, beacons: [CLBeacon], region: CLBeaconRegion) {
        print("\(beacons) + beacons for ranging")
        if beacons.count > 0 {
            let nearestBeacon = beacons.first!
            let major = CLBeaconMajorValue(truncating: nearestBeacon.major)
            let minor = CLBeaconMinorValue(truncating: nearestBeacon.minor)

            print("major: \(major)")
            print("minor: \(minor)")
            print("accuracy: \(nearestBeacon.accuracy)")

            switch nearestBeacon.proximity {
            case .immediate:
                print("--- immediate ---")
            case .near:
                print("--- near ---")
            case .far:
                print("--- far ---")
            case .unknown:
                print("--- proximity unknown ---")
            }
        }
    }


    var sceneView: ARSCNView!
    var locationManager: LocationManager!

    override func viewDidLoad() {
        super.viewDidLoad()
        sceneView = ARSCNView()

        locationManager = LocationManager()
        locationManager.delegate = self

        ...

我的控制台输出是:

2018-02-24 20:40:30.927542-0500 onebeacon[1275:423523] [DYMTLInitPlatform] platform initialization successful
2018-02-24 20:40:32.799470-0500 onebeacon[1275:423484] Metal GPU Frame Capture Enabled
2018-02-24 20:40:32.801237-0500 onebeacon[1275:423484] Metal API Validation Enabled
monitorBeacons()
monitorBeacons().monitoringIsAvailable
Optional(Set([CLBeaconRegion (identifier:'iBeacon', uuid:12345678-B644-4520-8F0C-720EAF059935, major:1, minor:2)])) + monitoredRegions

所有的iBeacon详细信息都是正确的,因为它一直插入并且未被访问,所以它们今天无法改变。问题总结如下:它似乎将区域添加到"要监控的区域"列表,但监视似乎永远不会开始,因为我没有中继iBeacon信息的控制台消息。

更新

我会留下我提供的答案,因为它可能是它的一部分(也许不是)......但现在它似乎开始了两次:

2018-02-24 21:35:13.341162-0500 onebeacon[1345:444027] [DYMTLInitPlatform] platform initialization successful
2018-02-24 21:35:16.504017-0500 onebeacon[1345:443977] Metal GPU Frame Capture Enabled
2018-02-24 21:35:16.505384-0500 onebeacon[1345:443977] Metal API Validation Enabled
monitorBeacons()
monitorBeacons().monitoringIsAvailable
Optional(Set([CLBeaconRegion (identifier:'iBeacon', uuid:12345678-B644-4520-8F0C-720EAF059935, major:1, minor:2)])) + monitoredRegions
2018-02-24 21:35:16.747004-0500 onebeacon[1345:443977] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2018-02-24 21:35:16.747969-0500 onebeacon[1345:443977] [MC] Reading from public effective user settings.
monitorBeacons()
monitorBeacons().monitoringIsAvailable
Optional(Set([CLBeaconRegion (identifier:'iBeacon', uuid:12345678-B644-4520-8F0C-720EAF059935, major:1, minor:2)])) + monitoredRegions

正如您所看到monitorBeacons()...行发生两次,我检查确保没有其他的LocationManager实例化,并且没有。

更新

我把它缩小了...问题似乎是didDetermineState函数最初没有触发,我必须从灯塔走出范围(或接近它)然后走路返回并且didDetermineState方法触发,有人知道为什么当我在信标的半径开始时它不会被触发吗?

更新

看来我的手机正在识别它位于某个区域,因为当我走出该区域时,didExitRegion方法会触发,然后didDetermineState方法......奇怪,因为状态应该已经确定didExitRegion方法是否正在触发:

2018-02-24 23:01:09.650445-0500 onebeacon[422:33762] [App] if we're in the real pre-commit handler we can't actually add any new fences due to CA restriction
2018-02-24 23:01:09.651978-0500 onebeacon[422:33762] [App] if we're in the real pre-commit handler we can't actually add any new fences due to CA restriction
2018-02-24 23:01:15.007844-0500 onebeacon[422:33762] [App] if we're in the real pre-commit handler we can't actually add any new fences due to CA restriction
2018-02-24 23:01:15.007893-0500 onebeacon[422:33762] [App] if we're in the real pre-commit handler we can't actually add any new fences due to CA restriction
2018-02-24 23:02:00.002451-0500 onebeacon[422:33762] Status bar could not find cached time string image. Rendering in-process.

...(put in for easier reading)...

did exit region --- CLBeaconRegion (identifier:'iBeacon', uuid:12345678-B644-4520-8F0C-720EAF059935, major:1, minor:2)
determined state of beacon
determined state of beacon and started ranging
[] + beacons for ranging
[] + beacons for ranging
[] + beacons for ranging
[] + beacons for ranging
[] + beacons for ranging
[] + beacons for ranging
[] + beacons for ranging

什么是预提交处理程序警告?这些相关吗?

1 个答案:

答案 0 :(得分:0)

我的didDetermineState功能在应用初始加载时停止工作。如果我走出信标的范围,然后回到范围内 - didDetermineState方法会触发(以及enter/exit区域方法)。我购买了另一个iBeacon ......它运行良好...而且,奇怪的是,当我同时使用两个信标时,didDetermineState在初始加载时都会检测到两个信标。我不确定为什么didDetermineState停止为一个灯塔工作......当被孤立地使用时。