What causes CBCentralManagerStateUnknown in iOS?

2019-04-05 01:55发布

问题:

Why do I get CBCentralManagerStateUnknown on an iPad 2 when using this simple code?

- (BOOL)viewDidLoad {

    bluetoothManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];

    if ([manager state] == CBCentralManagerStatePoweredOff) NSLog(@"CBCentralManagerStatePoweredOff");
    if ([manager state] == CBCentralManagerStatePoweredOn) NSLog(@"CBCentralManagerStatePoweredOn");
    if ([manager state] == CBCentralManagerStateResetting) NSLog(@"CBCentralManagerStateResetting");
    if ([manager state] == CBCentralManagerStateUnauthorized) NSLog(@"CBCentralManagerStateUnauthorized");
    if ([manager state] == CBCentralManagerStateUnknown) NSLog(@"CBCentralManagerStateUnknown");
    if ([manager state] == CBCentralManagerStateUnsupported) NSLog(@"CBCentralManagerStateUnsupported");

}

I cannot figure out what CBCentralManagerStateUnknown means. What do I do? The Apple docs just say:

State unknown, update imminent.

I get this response with a Bluetooth device connected, and also when Bluetooth is off. If I try to run something like [manager retrieveConnectedPeripherals], I also get this message in the console:

CoreBluetooth[WARNING] <CBConcreteCentralManager: ...> is not powered on

回答1:

I know why delegate is never called. Because the object is deleted from memory. Just make a strong property

@property (strong, nonatomic) DiscoverBluetoothDevices *btDevices;

And in init

@implementation DiscoverBluetoothDevices
- (id) init
{
    self = [super init];
    if(self) {
        centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
        [centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey: @YES}];

    }
    return self;
}

And now delegate is called properly.



回答2:

CBCentralManagerStateUnknown simply means iOS has started the BLE process, but has not completed initialization. Give it a moment, and the state will change.

In general, you will "give it a moment" by detecting a state chang in a CBCentralManagerDelegate delegate handler rather than looking at it right after the initialization call. You will implement

- (void) centralManagerDidUpdateState: (CBCentralManager *) central;

There are some good examples that show this, such as Apple's heart rate monitor.



回答3:

If a central's state goes to CBCentralManagerStateUnsupported (while Bluetooth Low Energy is supported by the device) it most likely means the app has done something bad with CoreBluetooth.

Check the iOS Bluetooth Diagnostic Logging logs.

For example, if you do this...

_cm1 = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{ CBCentralManagerOptionRestoreIdentifierKey: @"not_unique" }]; _cm2 = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{ CBCentralManagerOptionRestoreIdentifierKey: @"not_unique" }];

... the second central's state will go to CBCentralManagerStateUnsupported.



回答4:

The actual answer (old question I know); start a scan for peripherals, this will start BT LE up and your delegates will get called back. My Delegates and state info did not change until I did this.

a. Setup your cbcentralmanager as below b. Have the -central* delegates in your code and in your .h file c. NSLog or have a label on screen update with new status. And... Success.

cManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];

[cManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey: @YES}];


回答5:

You need to both retain the CBCentralManager instance (put it in an ivar or private property) and wait for the state change delegate to be called. (The state is always "unknown" if you check it immediately after instantiating the manager. The real state will appear momentarily in the delegate method.)



回答6:

In my case I did use AppDelegate as delegate for

CBCentralManagerDelegate

and indirectional for

 AVCaptureMetadataOutputObjectsDelegate.

in one time.

1) Take care about threads. Use

dispatch_get_main_queue() 

or

[NSThread mainThread]

for work with BLE.

2) Take care about using this 2 delegates on 1 object. Because hardware is NOT thead and context save