Why do I get CBCentralManagerStateUnknown
on an iPad 2 when using this simple code?
- (BOOL)viewDidLoad {
bluetoothManager = [[CBCentralManager
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.
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
.
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.
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
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.)
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}];