Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Callback from CBCentralManagerDelegate to retrieve CBPeripheral on IOS8

I have a BluetoothManager class managing BTLE communication. I can scan and connect to a CBPeripheral and discover services or characteristics. I have the good callbacks from CBCentralManagerDelegate and CBPeripheralDelegate

When I'm connected to a CBPeripheral, I save the UUIDString in CoreData to retrieve this peripheral when I relaunched the app.

This is my Swift code to retrieve peripherals when I restart the app:

func retrievePeripheralsWithIdentifiers(identifiers: [AnyObject]!){
    let data = self.centralManager.retrievePeripheralsWithIdentifiers(identifiers)

    println("Data retrieved: \(data)")

    for peripheral in data as [CBPeripheral] {

        println("Peripheral : \(peripheral)")
        peripheral.delegate = self
        centralManager.connectPeripheral(peripheral, options: nil)
    }
}

This is what I've got:

Data retrieved: [<CBPeripheral: 0x1669fcd0, identifier = XXXXX, name = Peripheral1, state = disconnected>]
Peripheral : <CBPeripheral: 0x1669fcd0, identifier = XXXXX, name = Peripheral1, state = disconnected>

I can find one of my peripheral without any problem. But when I call the line "centralManager.connectPeripheral(peripheral, options:nil)", I don't have any response.

These methods

func centralManager(central: CBCentralManager!, didRetrievePeripherals peripherals: [AnyObject]!)
func centralManager(central: CBCentralManager!, didConnectPeripheral peripheral: CBPeripheral!)
func centralManager(central: CBCentralManager!, didFailToConnectPeripheral peripheral: CBPeripheral!, error: NSError!)

are not called back to let me know what's wrong. So I can find the good peripheral but I can't connect to it.

However, I have the same code to connect to some peripherals when I'm scanning and it works; my own CBCentralManager has a the good delegate and my peripheral too.

What am I doing wrong?

I'm on Xcode-Beta5 with a iPod-Touch iOS8-Beta5.

Thanks,

Ben

EDIT

Ok, that's more weird

I try this following code from my older app on iOS7 & Objective-C, I saved the UUIDString when I'm connected, and try to retrieve peripherals. It works well: NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

if ([defaults objectForKey:@"UUIDString"]) {
    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:[defaults objectForKey:@"UUIDString"]];
    NSArray * data = [self.centralManager retrievePeripheralsWithIdentifiers:@[uuid]];

    if ( [data count] > 0 ){
        self.currentPeripheral = [data objectAtIndex:0];
        [self.currentPeripheral setDelegate:self];

        [self.centralManager connectPeripheral:self.currentPeripheral options:nil];
    }
} else {

    NSLog(@"Scanning started");
    /*...*/
}

That's the same code from my new app on iOS8 & Swift:

    let userDefaults = NSUserDefaults.standardUserDefaults()

    if userDefaults.objectForKey("UUIDString") != nil {

        let uuid = NSUUID(UUIDString: userDefaults.objectForKey("UUIDString") as String)
        let data = self.centralManager.retrievePeripheralsWithIdentifiers([uuid]) as [CBPeripheral]

        if data.count > 0 {

            self.currentPeripheral = data[0]

            println("Current peripheral \(self.currentPeripheral)")
            self.currentPeripheral!.delegate = self
            self.centralManager.connectPeripheral(self.currentPeripheral!, options: nil)
        }
    } else {

        println("Start Scanning")
        /*...*/
    }

I try my old app on iPod Touch iOS7 and it works well. I try my old app on iPod Touch iOS8 and it works also fine. I try my new app on iPod Touch iOS8 and it doesn't work.

I didn't find any differences between the both codes. I can scan, discover and connect peripherals, but connect to retrieved peripherals seems not working on iOS8 & Swift.

like image 720
Ben Avatar asked Aug 11 '14 10:08

Ben


3 Answers

It looks like in your original example, you aren't saving a local copy of the CBPeripheral.

From the CBCentralManager Class Reference - connectPeripheral:

Pending connection attempts are also canceled automatically when peripheral is deallocated.

like image 84
Jeffrey Stewart Avatar answered Oct 24 '22 09:10

Jeffrey Stewart


Please check whether you save local copy of CBPeripheral object or not.

You must save local copy of peripheral to avoid dealloc after finishing call back function.

If peripheral object dealloc before calling didConnect peripheral callback, core bluetooth automatically cancels pending connection request.

like image 34
burakim Avatar answered Oct 24 '22 09:10

burakim


Even having reference of peripheral last time connected, i was facing issue. What trick worked is first get previously connected peripheral using identifier by calling

retrievePeripheralsWithIdentifiers

.

  • Now Connect it and try to discover services. Then put one NSTimer and wait for 3-4 seconds.
  • On didDiscoverServices delegate callback. Invalidate Timer.
  • Now even after 4 seconds also service not discovered then just disconnect it and connect back.
  • This time it will sure discover services. I have used this trick and its working for me since long time.
like image 43
Kalpesh Panchasara Avatar answered Oct 24 '22 08:10

Kalpesh Panchasara