Potecuta
Potecuta

Reputation: 85

CBManager state always unknown

I am trying to check if the bluetooth of a device is on or off. This is the code I've written so far

   CBCentralManager *cbManager = [[CBCentralManager alloc] initWithDelegate:self
                                                                       queue:nil
                                                                     options:
                                   [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:0]
                                                               forKey:CBCentralManagerOptionShowPowerAlertKey]];


    [cbManager scanForPeripheralsWithServices:nil options:
                                    [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:0]
                                                                forKey:CBCentralManagerOptionShowPowerAlertKey]];

    if (cbManager.state==CBCentralManagerStatePoweredOff)
    {
        //do stuff
    }

- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    NSString *stateString = nil;
    switch(bluetoothManager.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;
    }
    UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"Bluetooth state"
                                                     message:stateString
                                                    delegate:nil
                                           cancelButtonTitle:@"Okay" otherButtonTitleArray:nil] autorelease];
    [alert show];
}

The problem is that the state of the manager is always Unknown regardless if the bluetooth on the device is turned on or not. Any ideas on why this happens ?

Upvotes: 1

Views: 4789

Answers (3)

Th. Thielemann
Th. Thielemann

Reputation: 2825

I had the same issue after upgrade from Sierra, Xcode 8, Swift 3 to High Sierra, Xcode 9, Swift 4.

  • Solution 1: (Just for tests) Wait a second bit between init and start of scan

    var scanner = BLESensorScanner(sensorName: sensorName);
    sleep(1);
    DispatchQueue.global(qos: .userInteractive).async {
        if (scanner.isPoweredOn()) {
            DBG("Bluetooth is powered on");
            scanner.startScan();
        }
        else {
            DBG("Bluetooth is not powered");
            exit(-1);
        }
    }
    

Note: BLESensorScanner implements NSObject, CBCentralManagerDelegate, CBPeripheralDelegate. sensorName is the name of the bluetooth device

  • Solution 2: Use event handler to wait until state becomes poweredOn

    public func centralManagerDidUpdateState(_ central: CBCentralManager) {
        DBG("CBCentralManager.centralManagerDidUpdateState");
        DBGI("state=\(toString(central.state))");
        if (state == CBManagerState.poweredOn) {
            scanner.startScan();
        }
    }
    

Upvotes: -1

Paulw11
Paulw11

Reputation: 114773

Two things -

  1. Your CBCentralManager should be a property, otherwise it will be released as soon as the method you initialise it in exits

  2. You shouldn't call scanForPeripheralsWithServices until you are in the powered on state.

    @property (strong,nonatomic) CBCentralManager *cbManager;
    
    
    
    self.cbManager = [[CBCentralManager alloc] initWithDelegate:self
                                                                   queue:nil
                                                                 options:
                               [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:0]
                                                                   forKey:CBCentralManagerOptionShowPowerAlertKey]];
    
    
    - (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.";
               [central scanForPeripheralsWithServices:nil options:
                                [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:0]
                                                            forKey:CBCentralManagerOptionShowPowerAlertKey]]; 
               break;
            default: 
               stateString = @"State unknown, update imminent."; 
               break;
        }
        UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"Bluetooth state"
                                                         message:stateString
                                                        delegate:nil
                                               cancelButtonTitle:@"Okay" otherButtonTitleArray:nil] autorelease];
        [alert show];
    }
    

Upvotes: 3

mond
mond

Reputation: 38

the method

-(void)centralManagerDidUpdateState(CBCentralManager*)central

is called. try to implement this one

- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
  // Possible states that the central manager can return.
  char *managerStrings[] = {"Unknown Error",            "Resetting",
                            "Unsupported Device",       "Unauthorized",
                            "Bluetooth is deactivated", "PoweredOn"};

  NSString *managerString =
      [NSString stringWithFormat:@"%s", managerStrings[central.state]];

  // the search is enabled if everything is ok
  if ([managerString isEqualToString:@"PoweredOn"]) {

      //Do something

  }
}

Upvotes: -1

Related Questions