Reputation: 2749
I've been working on detecting iBeacons on iOS 10 with swift 3 and Xcode 8.2.1.
I've been following this tutorial and so far i've been able to get the beacons detected in the foreground. However, what i need is for the beacons to be detected in the background as well as when the app is closed.
I've set the key NSLocationAlwaysUsageDescription
in info.plist
and also added Location updates
in the apps Background Modes
.
I'm also requesting requestAlwaysAuthorization
from the user.
Everything works fine till i add the following statement to the code: locationManager.startMonitoring(for: beaconRegion)
After i add the above statement and run the code, my app detects the beacon in the foreground and prints me a message. But as soon as i minimise the app and reopen it, the app cant seem to find the beacon. If i comment the line out and then rerun my program, the app detects the beacon in foreground as well as when i minimise and reopen the app again. I don't understand what i'm doing wrong.
Here is my ViewController
code:
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
var locationManager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.allowsBackgroundLocationUpdates = true
locationManager.requestAlwaysAuthorization()
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways {
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
if CLLocationManager.isRangingAvailable() {
startScanning()
}
}
}
}
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
if beacons.count > 0 {
NSLog("Found beacon")
} else {
NSLog("Beacon not found")
}
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
let beaconRegion = region as! CLBeaconRegion
print("Did enter region: " + (beaconRegion.major?.stringValue)!)
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
let beaconRegion = region as! CLBeaconRegion
print("Did exit region: " + (beaconRegion.major?.stringValue)!)
}
func startScanning() {
let uuid = UUID(uuidString: "2f234454-cf6d-4a0f-adf2-f4911ba9ffa6")!
let beaconRegion = CLBeaconRegion(proximityUUID: uuid, major: CLBeaconMajorValue(0), minor: CLBeaconMinorValue(1), identifier: "MyBeacon")
beaconRegion.notifyEntryStateOnDisplay = true
beaconRegion.notifyOnEntry = true
beaconRegion.notifyOnExit = true
// locationManager.startMonitoring(for: beaconRegion)
locationManager.startRangingBeacons(in: beaconRegion)
}
}
Here's what my log looks like:
Found beacon
Found beacon
Found beacon
// App minimised and reopened here
Found beacon
Found beacon
Found beacon
Found beacon
Found beacon
Found beacon
Beacon not found
Beacon not found
Beacon not found
Beacon not found
Beacon not found
Beacon not found
Upvotes: 0
Views: 1297
Reputation: 1061
Interaction with iBeacons can be done with ranging en monitoring. Ranging for a beacon provides you the value/data of the iBeacon, like uuid, major & minors. The problem with ranging is that apple accepts only a few (circa 10 seconds) of ranging time in the background. Monitoring can be done in the background. You should check if you can range in background (print/logs) ifso, detecting the ibeacon is the problem.
ps: When you start ranging inside a region the didEnter delegate method doesn't get called, because you are already in the region.
Upvotes: 0
Reputation: 65025
Try adding the monitoring delegate callbacks didEnter(region: region)
and didExit(region: region)
. Not sure why it would change things, bit it is unusual that the code starts monitoring but does not have them.
EDIT: After seeing updated code, I suspect the issue may be the way ranging is started. Instead of starting it in the didChangeAuthorization
callback, just start it in viewDidLoad
. The code will not crash if authorization has not been given. It just won't actually scan until it is.
Upvotes: 1