Search code examples
iosswiftbluetoothbluetooth-lowenergycore-bluetooth

swift: pair with bluetooth device with button click


Until now the iPhone has paired to a bluetooth device when the app is opened, but I want to pair with a button click instead. I tried to put all the scanning and connection functions in a IBAction, but nothing happens when I push the button. In the first function after the IBAction I have a print output to check if it even enters the function, but I don't get the print. I also tried to put a delay after the manager.scanForPeripherals but didn't work either. What am I missing here? anyone know? Thanks for any replies! here is my code (without the delay):

var manager: CBCentralManager!
var device: CBPeripheral?
var characteristics: [CBCharacteristic]?
var serviceUUID = "1234"
var char1 = "FFE1"
let deviceName = "HMSoft"
var connected = CBPeripheralState.connected
var disconnected = CBPeripheralState.disconnected

 override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    manager = CBCentralManager(delegate: self, queue: nil)


}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.


}
 func centralManagerDidUpdateState(_ central: CBCentralManager) {
    switch central.state {
    case .poweredOn: break
        // manager.scanForPeripherals(withServices: nil, options: nil)
    case .unknown: break

    case .resetting: break

    case .unsupported: break

    case .unauthorized: break

    case .poweredOff:

        break

    }
}


   @IBAction func connectBluetooth(_ sender: Any) {

   manager.scanForPeripherals(withServices: nil, options: nil)

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {

    if let peripheralName = advertisementData[CBAdvertisementDataLocalNameKey] as? String {

        if peripheralName == self.deviceName {

            // save a reference to the sensor tag
            self.device = peripheral
            self.device!.delegate = self

            // Request a connection to the peripheral

            self.manager.connect(self.device!, options: nil)

            print("Check")
        }
    }
}

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {

    peripheral.discoverServices(nil)
}


func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {

    if error != nil {

        return
    }


    if let services = peripheral.services {
        for service in services {

            if (service.uuid == CBUUID(string: serviceUUID)) {
                peripheral.discoverCharacteristics(nil, for: service)
            }
        }
    }

}


func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {

    device = peripheral
    characteristics = service.characteristics

}

func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
    if error != nil {

        return
    }
}

}


Solution

  • When you initialise the CBCentralManager and set its delegate, the delegate will start receiving events.

    So, if you only want the CBCentralManager to be active once the user has tapped a button, rather than as soon as the screen loads, the minimum you have to do is move the code that initialises the manager from viewDidLoad to the button action.

    So:

    Move manager = CBCentralManager(delegate: self, queue: nil) from viewDidLoad to @IBAction func connectBluetooth(_ sender: Any),

    Remove the call to scanForPeripherals from the IBAction, and;

    Uncomment // manager.scanForPeripherals(withServices: nil, options: nil) in centralManagerDidUpdateState.