How to know if a Bluetooth Device is Connected in iOS?

996 Views Asked by At

What is the best way to know on how a Bluetooth Device is already connected? I am using CBCentralManager to identify if the Bluetooth is Powered ON but I am unable to find out on how I can identify If a Bluetooth Device is already connected.

I am implementing routing of AVAudioSession Calls via a Connected Bluetooth device but AudioSession Category changes are getting called repeatedly due to which I am unable to find if a Bluetooth Device is connected or not. If anyone have tried to implement this behaviour, Your inputs might be helpful. Please share the information.

3

There are 3 best solutions below

0
Lilya On

I am using CBPeripheral.state == .connected to check the state of the BLE device.

From the documentation:

/**
 *  @enum CBPeripheralState
 *
 *  @discussion Represents the current connection state of a CBPeripheral.
 *
 */
@available(iOS 7.0, *)
public enum CBPeripheralState : Int {

    
    case disconnected = 0

    case connecting = 1

    case connected = 2

    @available(iOS 9.0, *)
    case disconnecting = 3
}
0
Rob Napier On

The kind of Bluetooth your describing here is an audio device, which is almost certainly "classic" Bluetooth. This is unrelated to CoreBluetooth, which mostly handles GATT connections over BLE (along with some other, lesser-used protocols). You cannot find out anything about connected audio devices use CoreBluetooth.

To check your audio route, see AVAudioSesssion.currentRoute.outputs. The portType will tell you whether it's a Bluetooth device. Note that there are several types that may classify as "Bluetooth" for your purposes:

  • bluetoothA2DP: High quality music (unidirectional)
  • bluetoothHFP: Bidirectional (microphone/speaker) voice; low-quality
  • carAudio: CarPlay (non-CarPlay systems are either A2DP or HFP)
  • bluetoothLE: Hearing aids. While this is BLE, it's not part of CoreBluetooth.
2
David Feldman On

use NotificationCenter

NotificationCenter.default.addObserver(
   self,
   selector: #selector(handleAudioSessionRouteChange(_:)),
   name: NSNotification.Name.AVAudioSessionRouteChange,
   object: nil)

    @objc private func handleAudioSessionRouteChange(_ notification: Notification) {
            guard let userInfo = notification.userInfo,
                  let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
                  let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else {return}
            switch reason {
            case .newDeviceAvailable:
                let session = AVAudioSession.sharedInstance()
                for output in session.currentRoute.outputs {
                    print("Bluetooth A2DP device connected: \(output.portName)")
                    self.speakerButton.setImage(UIImage(systemName: "s.circle.fill"), for: .normal)
                }
            case .oldDeviceUnavailable:
                if let previousRoute = userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
                    for output in previousRoute.outputs{
                        print("Bluetooth A2DP device disconnected: \(output.portName)")
                        self.speakerButton.setImage(UIImage(named: "speaker-button"), for: .normal)
                    }
                }
            default:
                break
            }
        }
        deinit {
            NotificationCenter.default.removeObserver(self)
        }

or you can use

    func checkBluetoothConnection() {
        let session = AVAudioSession.sharedInstance()
        let connectedBluetoothDevices = session.availableInputs?.filter { input in
            input.portType == .bluetoothHFP || input.portType == .bluetoothLE || input.portType == .bluetoothA2DP
        }
       isBluetoothConnected = connectedBluetoothDevices?.isEmpty == false
    }

the first option is when audio routes change.

the second option looks if a Bluetooth is connected even the AudioSession route did not change