iOS 14 - how to get iBeacon to wake up the app when precise location permission is denied? - cllocationmanager

I’m running into the following problem with iOS 14.0 previously - with background location permission I could:
Register for iBeacon region monitoring
Kill the app from the app switcher
Tap the screen and see the app relaunched in the console.
App is running but is not in the app switcher
Retested with iOS14, without precise location my app is no longer being woken up from being terminated from the app switcher.
Re-enabled precise location permission and everything works as before.
What do I need to do to enable the background app to wake up for the iBeacon region without precise location permission?
Or
How do I detect that the precise location permission is missing and notify the user that the app will not work as expected?

The Precise Location switch is new to iOS 14, and the specifics of what happens when user switch it to off are unfortunately not well documented by Apple. Here is a summary based on experimentation:
With Precise Location Enabled/Disabled:
Precise Location
CoreLocation Accuracy/Function Enabled Disabled
---------------------------------- -------- -------
kCLLocationAccuracyThreeKilometers YES YES
kCLLocationAccuracyReduced YES YES
kCLLocationAccuracyBest YES DEGRADED
kCLLocationAccuracyNearestTenMeters YES DEGRADED
kCLLocationAccuracyHundredMeters YES DEGRADED
kCLLocationAccuracyKilometer YES DEGRADED
Beacon Monitoring YES NO
Beacon Ranging YES NO
Precise Location
CoreBluetooth Enabled Disabled
---------------------------------- -------- -------
Bluetooth LE scanning YES NO
Precise Location
NearbyInteraction Enabled Disabled
---------------------------------- -------- -------
NI Ranging YES NO
When precise location is disabled, lat/lon location updates to CoreLocation will be degraded to that provided by kCLAccuracyReduced similar to 3km accuracy provided by cell tower data.
Ranging and Monitoring of iBeacons is blocked -- delegate method callbacks do not get made, and apps will not be launched in the background. Nearby Interaction ranging is blocked.
These effects take effect immediately when you turn off Precise Location. You can see this yourself by looking at logging from your app while it is running, then going to settings to turn off Precise Location and seeing the behavioral changes.
Unfortunately, there is nothing you can do to force iOS to give you beacon or other location updates when the user has disabled Precise Location. The best you can do is detect that the user has done this (use code like below), and then prompt the user to change this in settings so your app works properly.
if CLLocationManager.locationServicesEnabled() {
if #available(iOS 14.0, *) {
switch self.locationManager.accuracyAuthorization {
case .fullAccuracy:
NSLog("Precise Location allowed")
case .reducedAccuracy:
NSLog("Precise location disabled")
default:
NSLog("Precise Location not known")
}
}
}

Related

CMMotionActivityManager - authorizationStatus "refresh"

I am checking the authorizationStatus() of CMMotionActivityManager when "Fitness Tracking" status is disabled in phone's Settings > Privacy > Motion & Fitness. I get a correct status of "restricted" for system wide restrictions.
When I enable the "Fitness Tracking", and bring my app back to foreground from background, the authorizationStatus() still returns "restricted". If I swipe-out/terminate the application and relaunch, it then changes the authorization status.
Is there a way to refresh the authorizationStatus() when bringing the app from background to foreground.
Thanks!
I came across the same issue and this behavior happens only before the user grants permission for motion data to your app. Once your app has given permission the first time THEN if the motion permission is toggled on device level, iOS will terminate your app (but if and only if your app has given permission at some point). So once you give permission your app will appear in the motion permission list (see image below) and if so then iOS will terminate when the switch is toggled.

Unable to detect Beacon when Device already in Beacon range & then we turn on Bluetooth & application is killed

I have implemented Beacon with local notification.
Every thing works fine for the case when bluetooth in ON & then device enters the beacon range & app is in "Not running" state.
But, when device is already in Beacon range & then Bluetooth is turned ON, no delegate gets called. Is it a limitation or am I missing something?
This is a limitation of the Core Location framework.
When an application is terminated "Not Running" state, it can be re-launched due to location manager region didEnter / didExit region events. Your location manager will not receive region enter / exit events if you toggle your Bluetooth on and off while the application is terminated. The only way you'll be able to get didEnter / didExit events to fire is by physically entering or exiting one of your beacon regions by crossing their detection threshold.
Terminated apps will wake up on region didEnter / didExit events.
The region monitoring service delivers events normally while an app is running in the foreground or background. (You can use this service for both geographic and beacon regions.) For a terminated iOS app, this service relaunches the app to deliver events.
Beacon ranging will not wake up your app.
(If the beacon region’s notifyEntryStateOnDisplay property is true, waking the device causes the app to range for beacons for a few seconds in the background.) This service does not relaunch iOS apps that have been terminated; however, you can be relaunched by monitoring beacon regions using the region monitoring service.

iBeacon did enter region does not trigger when user turns manually bluetooth on

I am testing iBeacon region monitoring and doing the following steps.
1: Precondition: Bluetooth is on in the phone and App is not running
2: I turn the beacon on
3: The app gets launched following a location event (beacon region)
4: I turned the beacon off
5: The app is still running and detects the did exit region event
6: I then kill the app manually (it is ok to do so, region monitoring will still work)
7: I turn off Bluetooth on the phone
8: I turn the beacon back on
9: I turn on Bluetooth again on the phone
10: I expect to... see below (Expected result)
Expected result: the app should wake up following entering the region (I tested this without manually switching the Bluetooth and it works)
Actual result: does not happen.
Why does 10 not happen? Is this a bug in iOS?
Turning Bluetooth off doesn't usually work as a good way to test monitoring. Enter and exit events only happen when the region's state (i.e., CLRegionState) transitions from "outside" to "inside" (and vice versa). If you turn Bluetooth off, the state goes to "unknown"[1] (because how would the device know if you're out or in with Bluetooth disabled), and thus if you switch it back on, and it transitions to "outside" or "inside," it won't actually trigger an event by design.
You can test that by implementing the didDetermineState method, in addition to didEnter and didExit. Start with the beacon turned off, confirm via didDetermineState that the state is "outside." Turn Bluetooth off, turn the beacon on, turn Bluetooth on. You will see didDetermineState with state "inside," but no didEnter. (It works the same the other way around, i.e., if you start with the beacon turned on, and turn it off while the iPhone's Bluetooth is disabled. You will see didDetermineState "outside," but no didExit.)
Note: this test only works in the foreground. It looks like in the background, didDetermineState is not enough for iOS to wake up the app to handle the event—it needs to be didEnter or didExit.
[1] A little clarification here as well. When you disable Bluetooth, there won't actually be an explicit call to didDetermineState with CLRegionStateUnknown. This is because I suspect that iOS stops delivering any beacon events when Bluetooth is off. How did I arrive at the conclusion that it really changes to "unknown" then? I added an NSTimer that calls requestStateForRegion (which in turn forces an asynchronous call to didDetermineState) every second. When I turn Bluetooth off, didDetermineState calls stop arriving. But as soon as I turn Bluetooth on, these calls resume, and the state is "unknown"—before it changes to "outside" or "inside" depending on the current state of the beacon. Again, per the note above, all of this is with the app in the foreground.
(Same mechanics actually apply when you start monitoring already in range of a beacon. Before you start monitoring, the state is "unknown." When you start monitoring, the state transitions to "inside" our "outside" (depending on whether the beacon is in range at the time when monitoring starts), but this does not trigger didEnter or didExit. Here too you can verify this with didDetermineState.)

DidEnterRegion only called if requestAlwaysAuthorization is called. Beacons

didEnterRegion and didExitRegion are only called after I request and allow Always Authorization for CoreLocation
Even if I request WhenInUseAuthorization didExit and didEnter won't be called
How am I supposed to trigger ranging of beacons if I can't get this to be called?
Any solutions?
UPDATE
Apple rejected my app for calling requestAlwaysAuthorization()
Here is my question submitted to the review team this morning:
In order to monitor beacon regions (a very core functionality of beacons used in many apps including some Apple apps) you need to have the user allow the app to access location even when not using the app. I am using .requestAlwaysAuthorization to enable beacons to monitor in the background. Why won't this be allowed?
Apples response this afternoon on iTunes Connect:
Thank you for your feedback. However, background location is not necessary for iBeacon functionality. Therefore, it is necessary to remove the background location feature before resubmission.
So if beacons are supposed to automatically monitor regions in the background, but I can't ask permission for background monitoring and beacons won't monitor in the background unless I get permission, how then am I supposed to monitor regions in the background??
Do you mean when the app is in the background? If so, then it is true that didEnterRegion and didExitRegion don't get called with only a WhenInUseAuthorization. They will only get called when you app is in the foreground and you enter/exit a region
background location is not necessary for iBeacon functionality. Therefore, it is necessary to remove the background location feature before resubmission.
It seems that your app was rejected because of the Background Modes (specifically, the "location updates" mode), no the "always" authorization. You don't need any Background Modes enabled for beacon monitoring to work in the background, the "always" authorization is enough.
Simply disable the Background Modes capability in your project settings and you should be good!
Unfortunately, you must request Always Allow location access to use region monitoring with beacons.
From the docs:
Important
Apps must have always authorization to use region monitoring, and they must be configured with the Location updates background mode to be launched.
https://developer.apple.com/documentation/corelocation/determining_the_proximity_to_an_ibeacon

Sometimes App is not giving notification of iBeacon when app is kill by user in ios

I am using iBeacon Technology in my application.When I open the app,beacon monitoring gets started and after that I kill the application and put the phone in sleep mode or lock the screen. If I go near to the beacon then sometimes app starts monitoring and sometimes not. Don't know what's the issue? I have set three flag for monitoring beacon region as below.
beaconRegion.notifyOnEntry = true;
beaconRegion.notifyOnExit = true;
beaconRegion.notifyEntryStateOnDisplay= true;
And When I press the lock button of the iphone. It starts monitoring for beacons and if I am in beacon region then it works perfectly..
Can anyone help me out ?
I have been working with iBeacon for around a year now, i have had the same scenarios encountered.
As per my experience with this if you are already inside a region, it takes some time to notify the 'didEnterRegion' delegate method. But if you are outside region a then entering the same you are likely to get the delegate called instantly and this depends on the Beacon Manufacture you are testing with. [More accuracy were found with RadBeacon, Estimote and Kontakt ]
Normally the TxPower configured to the beacons will be +4 dBm thats a Beacon can transmit till 70m/230". Try with going out of the region with the App in killed state and then enter the region.
When we set notifyOnEntry, notifyOnExit to YES/true, the control is with the OS LocationManager wether to notify the App about the region entry state, and you can handle it with a Notification thrown to the User and start Monitoring and then Ranging for the encountered region.

Resources