23

I'm pulling my hair out of this problems. I'm trying to connect to BLE devices, can't see what I've done wrong in my code below.

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    _cm = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

+ (NSString*)UUIDString:(CFUUIDRef)uuid {
    CFStringRef string = CFUUIDCreateString(NULL, uuid);
    return (__bridge_transfer NSString*)string;
}

- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    if (central.state == CBCentralManagerStatePoweredOn) {
        [self scanForPeripherals];
    }
}

- (void)centralManager:(CBCentralManager *)central
 didDiscoverPeripheral:(CBPeripheral *)peripheral
     advertisementData:(NSDictionary *)advertisementData
                  RSSI:(NSNumber *)RSSI {
//    NSLog(@"Received peripheral : \n%@", peripheral);
//    NSLog(@"Adv data : %@", advertisementData);

    [peripheral setDelegate:self];
    [central connectPeripheral:peripheral options:nil];
    [peripheral readRSSI];
}

- (int)scanForPeripherals {
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:NO], CBCentralManagerScanOptionAllowDuplicatesKey,
                             nil];

    [_cm scanForPeripheralsWithServices:nil options:options];
    return 0;
}

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    NSLog(@"didConnectPeripheral");
}

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@"didDisconnectPeripheral");
}

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@"failed to connect");
}

- (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error {
    NSLog(@"didReadRSSI");
}

These devices are not my own. I don't know its proximity UUID, but as far as I know, It won't be needed in connecting via CoreBluetooth right?

All of the devices are discovered in didDiscoverPeripheral:, in the selector I tried to connect them. But there's nothing comes after that.

Am I to expect a dialog with Pairing Password Request when I called to didDiscoverPeripheral:? If so I don't see any dialog, why is that?

From apple documents, It clearly stated that after trying to connect to a device you should get a called to either didConnectPeripheral or didFailToConnectPeripher but I got none.

Any thoughts? I've been trying for almost a week now. Appreciate every helps, thanks.

Mysteltainn
  • 411
  • 3
  • 5
  • 13
  • Do you get a call to `didDiscoverPeripheral`? Have you tried removing the call to `[peripheral readRSSI]` that immediately follows your connect request? You shouldn't issue that request until you are connected. I always suggest people try the free LightBlue app from the app store as a test to see if their device is advertising and is connectable – Paulw11 Oct 15 '14 at 09:09
  • Yes I've tried, There was the first version of this code where, it's do nothing but, discover and try to connect, but after `connectPeripheral` executed nothing happen. – Mysteltainn Oct 15 '14 at 09:11
  • Try LightBlue - this way you can at least confirm that the hardware is connectable. Also try storing the peripheral you are connecting to in a property so that it isn't released – Paulw11 Oct 15 '14 at 09:12
  • Tried, All of them shows up in LightBlue, No services was displayed for any devices. There are 2 of The **Estimotes BLE** and another 2 of my **country customized BLE***. Interrogating the estimotes BLE result in successful connection but after a fews seconds, LightBlue says "Disconnected alert", and There is a red text saying "Data is stale", for another 2 devices interrogation disclosing another page like the estimotes and nothing more – Mysteltainn Oct 15 '14 at 09:17
  • May help: http://stackoverflow.com/questions/28167804/why-use-corebluetooth-connectperipheral-did-not-call-delegate-methods-in-ios8/31961410#31961410 – oOEric Aug 12 '15 at 09:38

2 Answers2

61

If you don't somehow retain the peripheral object that is delivered to didDiscoverPeripheral then it is released once this delegate method exits and you won't get a connection.

I suggest adding a property to track discovered peripherals

@property (strong,nonatomic) NSMutableArray *peripherals;

initialise this in viewDidLoad or init

self.peripherals=[NSMutableArray new];

And then add the peripheral to it in didDiscoverPeripheral

-(void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
    NSLog(@"Discovered peripheral %@",peripheral.identifier.UUIDString);
    [self.peripherals addObject:peripheral];
    [central connectPeripheral:peripheral options:nil];
}
Paulw11
  • 95,291
  • 12
  • 135
  • 153
  • 4
    Yes!!! That does the trick, Thank you so much @Paulw11. I didn't know that peripheral passed in from `didDiscoverPeripheral` was weak referenced. I also don't find anything telling about this in apple docs or it was me skipping that part? Anyway, thanks a bunch!!!. – Mysteltainn Oct 15 '14 at 09:37
  • 3
    I don't know how I found it - I think I had to figure it out the hard way. Anyway I compared my app with your code and that was the difference – Paulw11 Oct 15 '14 at 09:39
  • 1
    Good catch. I also notified just now, after your answer, that all tutorial I've been working after keep reference to the connected devices. A small matter, but surely thanks a lot, again. @Paulw11 – Mysteltainn Oct 15 '14 at 09:40
  • @Paulw11 My app doesn't get launched in the background when I turn the bluetooth off.. I have asked a question here: https://stackoverflow.com/questions/48030480/turning-bluetooth-back-on-after-the-app-is-suspended-doesnt-launch-the-app-in-t – Saleh Jan 01 '18 at 16:18
  • @Paulw11 does the centralManagerDidUpdateState method gets called when user turns on the bluetooth after a couple of hours? I am stuck where centralManagerDidUpdateState doesn't get called if I turn the radio off and turn it on after a few hours. – Saleh Jan 03 '18 at 16:27
  • I don't believe that didUpdateState is called in the background; I would need to check. – Paulw11 Jan 03 '18 at 20:54
  • @Paulw11 when I turn off the bluetooth while the app is connected, and I turn it on after few minutes nothing seems to be called in the app. And when I manually launch the app, peripheral is stuck in connecting state. How can I recover from this situation. I have asked a detail question here: https://stackoverflow.com/questions/48030480/turning-bluetooth-radio-back-on-after-the-app-is-suspended-doesnt-call-centralm – Saleh Jan 08 '18 at 18:13
  • @Paulw11 I need to remain connected to the app at all times in the background. It works perfectly, until I turn the radio off while in connected state. On turning on it never notifies the app. – Saleh Jan 08 '18 at 18:21
  • @Paulw11 Can you please have a look at this. https://stackoverflow.com/questions/53321747/how-to-retrieve-connected-ble-device-while-app-is-in-background – va05 Nov 16 '18 at 13:29
  • @paulw11 Can you tell me one thing When I go in background func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) method will called in my side and give me a state of service.How I scan new devices in background using center manger ?Can you give me idea? – sarit bahuguna Jun 09 '20 at 06:48
3
var peripherals = [CBPeripheral]()

func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
    peripherals.append(peripheral)
    bleManager.connectPeripheral(peripheral, options: nil)
}

This is the Swift version.

Antony Wong
  • 313
  • 4
  • 12