4
votes

We have a project that is using CoreLocation regions to monitor iBeacon region entering/exiting in the app background. CLBeaconRegion (CLRegion), CLBeacon, etc. CLLocationManager returns callbacks when a CLBeacon (iBeacon) region is entered. It is a light wrapper around a bluetoothManager underneath.

// various CLLocation delegate callback examples
- (void) locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region;
- (void) locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region;

The problem we're having is that when a user does not have bluetooth turned on, the Iphone issues a system level warning on a regular basis to 'Turn On Bluetooth to Allow "APP_NAME" to Connect ot Accessories'. This happens a lot, I've got it 4 times this morning already as the app runs in the background. CLLocationManager may be attempting to monitor those CLBeaconRegion, but bluetooth is off so it can't do this.

Another post, mentions that CBCentralManager has a property, CBCentralManagerOptionShowPowerAlertKey, that allows disabling this warning.

iOS CoreBluetooth passively check if Bluetooth is enabled without prompting user to turn Bluetooth on

Unfortunately I've found no way to access underlying bluetooth, or any CBCentralManager reference to use this.

Is there any way to disable this warning for CLBeaconRegion monitoring?

enter image description here

1
Are you just instantiating a CLLocationManager instance or are you using some other library? As far as I know you shouldn't get this prompt with straight CoreLocationPaulw11
We are using CLLocationManager and implementing its delegate methodsMiro
I tested with an app that uses beacon monitoring and I get a slightly different dialog that informs the user that location accuracy will be improved if Bluetooth is enabled. I only get this the first time I run the app with Bluetooth off. The dialog you are showing is the dialog I would expect with Core Bluetooth, not Core Location. What version of iOS are you running?Paulw11
I just tried another iBeacon app from the app store and it is displaying the same dialog you are seeing, so perhaps it depends on the API that the app is compiled against or something. Probably the only way you can avoid the dialog is just to allocate a CBCentral using the technique in the answer you linked to and detect if Bluetooth is on or off. If it is off don't initialise the beacon region monitoring.Paulw11
FYI, I'm running the latest iOS, about 8.1. I worked out a solution similar in logic to your last comment about CBCentral and detecting bluetooth.Miro

1 Answers

3
votes

I worked out a solution that uses CoreBluetooth and CBCentralManager to detect, stop, and start bluetooth usage. Below is the majority of the code, plus an initial check to see if it is on before starting. It works to suppress the error prompt by guaranteeing beacons are not being used when bluetooth is off. If it is disabled, beacons are stopped. The warning thus goes away. We're unable to actually enable/disable bluetooth programmatically unfortunately.

// initialize in viewdidLoad, etc
_bluetoothManager =  [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{CBCentralManagerOptionShowPowerAlertKey:@NO}];


// bluetooth manager state change
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    NSString *stateString = nil;
    switch(central.state)
    {
        case CBCentralManagerStateResetting: stateString = @"The connection with the system service was momentarily lost, update imminent."; break;
        case CBCentralManagerStateUnsupported: stateString = @"The platform doesn't support Bluetooth Low Energy."; break;
        case CBCentralManagerStateUnauthorized: stateString = @"The app is not authorized to use Bluetooth Low Energy."; break;
        case CBCentralManagerStatePoweredOff: stateString = @"Bluetooth is currently powered off."; break;
        case CBCentralManagerStatePoweredOn: stateString = @"Bluetooth is currently powered on and available to use."; break;
        default: stateString = @"State unknown, update imminent."; break;
    }

    if(_bluetoothState != CBCentralManagerStateUnknown && _bluetoothState != CBCentralManagerStatePoweredOn && central.state == CBCentralManagerStatePoweredOn){
         NSLog(@"BEACON_MANAGER: Bluetooth just enabled. Attempting to start beacon monitoring.");
        _forceRestartLM = YES; // make sure we force restart LMs on next update, since they're stopped currently and regions may not be updated to trigger it
        [self startBeaconMonitoring];
    }

    if(_bluetoothState != CBCentralManagerStateUnknown && _bluetoothState == CBCentralManagerStatePoweredOn && central.state != CBCentralManagerStatePoweredOn)    {
        NSLog(@"BEACON_MANAGER: Bluetooth just disabled. Attempting to stop beacon monitoring.");
        [self stopBeaconMonitoring];
    }
}