[iOS] CoreBluetooth - CentralManager
CentralManager
중앙관리자는 주변 장치 스캔을 할 수 있으며
앱이 실행되고 있는 기기의 블루투스 상태를 모니터링 할 수 있다
let centralManager = CBCentralManager(delegate: self, queue: nil)
delegate : CBCentralManagerDelegate 프로토콜을 구현한 타입의 인스턴스
queue: CentralManager 인스턴스가 활동할 대기열
CentralManager 모니터링
CBCentralManagerDelegate 프로토콜의 centralManagerDidUpdateState(_:) 사용
class or extension 타입: CBCentralManagerDelegate {
centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state { ... }
}
}
디바이스와 앱 내의 블루투스 상태가 업데이트 될 때마다 CoreBluetooth를 통하여 호출 되는 델리게이트 메서드
CBCentralManager 인스턴스가 생성, 초기화 후에 centralManagerDidUpdate가 바로 호출된다.
정상적인 상황에서는 매개변수로 넘어온 central 인스턴스의 state 프로퍼티의 값이 .poweredOn 이다
- state 목록
- .poweredOff : 블루투스 기능이 해제, 기기의 제어센터 / 설정에서 블루투스 기능을 활성화 시켜야한다
- .poweredOn : 블루투스 기능이 활성화 된 상태이며 앱에서 블루투스 기능을 사용할 수 있는 상태이다
- .resetting : 블루투스 서비스와의 연결이 중단 된 상태
- .unauthorized : 사용자가 블루투스 권한 요청을 거부한 상태로 앱의 설정에서 직접 활성화 해야함
- .unknown : 블루투스 서비스에 대한 중앙관리자와 앱의 연결상태를 알 수 없는 경우
- .unsupport : 기기가 블루투스를 지원하지 않음
Scanning for peripherals
중앙 관리자는 주변 기기를 탐색할 수 있다
centralManagerDidUpdateState(_ central: CBCentralManager) 델리게이트 메소드에서
central.state 값이 .poweredOn 상태라면 탐색 시작이 가능하다
중앙관리자 인스턴스에서 scanForPeripherals(withService:,options:) 메서드를 호출하여 탐색을 시작한다
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
central.scanForPeripherals(withServices: nil, options: nil)
...
}
}
withServices :[CBUUID]?
옵셔널 CBUUID 배열로 찾고자 하는 UUID를 필터링할 수 있다
options: [String : Any]?
다음 나열된 키 중 0개 이상이 포함된 딕셔너리를 사용하여 전달할 수 있음
- CBCentralManagerScanOptionAllowDuplicatesKey
Bool 타입을 값으로 가짐
true일 경우 처음 수신된 광고 패킷이 아닌 지정된 장치의 모든 탐지된 광고 패킷에 대해 델리게이트 호출을 수행
즉, 광고 패킷을 처음 수신 받고 더 이상 받지 않는 것이 아니라 지속적으로 수신을 받음
기본 값은 false이다
apple은 배터리와 메모리 성능에 악영향을 미치기 때문에 false를 권장함
- CBCentralManagerScanOptionSolicitedServiceUUIDsKey
중앙 관리자가 클라이언트 대신 Gatt 서버 역할을 하는 GAD 중앙부에 GAD 주변장치를 광고하는 경우 유용
사실 무슨말인지 잘 이해가 안간다
scanForPeripherals 호출 후 중앙관리자는 CBCentralManagerDelegate 프로토콜의
centralManager(_:, didDiscover:,advertisementData: rssi:) 델리게이트 메서드를 호출
scanForPeripherals의 withServices 인자에 [CBUUID]를 전달했다면 해당 서비스 UUID를 하나 이상 가지고 있는 주변 장치를 전달 받음
Scan Result
/// scanForPeripherals(withServices:, options) 메소드 호출 후 탐지된 광고 패킷을 받는 메서드
/// - Parameters:
/// - central: 해당 장치를 발견한 중앙 관리자 객체
/// - peripheral: 발견된 주변장치
/// - advertisementData: 광고된 패킷에 포함된 data 딕셔너리, CoreBluetooth는 기본 키세트를 사용하여 이 데이터를 분석하고 구성함
/// - RSSI: 수신된 광고 패킷의 신호 강도, -30 ~ -99 범위를 가지며 -30이 제일 강한 강도
func centralManager(_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData: [String : Any],
rssi RSSI: NSNumber)
위에서 설명했듯이 scanForPeripherals메소드 호출한 후 탐지된 광고 패킷은
CBCentralManagerDelegate 프로토콜의 델리게이트 메서드인
centralManager(_:, didDiscover:,advertisementData: rssi:)에서 확인할 수 있음
이 델리게이트 메서드는 주변기기의 범위, 광고 상태, scanForPeripherals 메서드의 options 매개변수에 따라 호출 되는 빈도가 달라진다
정리
- 중앙관리자는 주변 장치를 탐색하고, 앱을 사용하는 기기의 블루투스 상태를 모니터링하는 객체다
- 모니터링은 중앙관리자 객체를 인스턴스 한 직후 CBCentralManagerDelegate 프로토콜의 centralManagerDidUpdateState 메서드가 호출 되며 현재 상태를 알 수 있으며, 상태가 변경될 때마다 이 메서드가 호출됨
- 중앙관리자 인스턴스의 scanForPeripherals(withServices:, options:) 메서드를 사용하여 탐색을 시작
- CBCentralManagedDelegate 프로토콜의 centralManaged(_: didDiscover: advertisementData:, rssi:) 메서드를 통해 탐색된 광고 패킷의 주변장치와 그외 정보를 전달 받는다
주변 장치와의 Connecting, Disconnecting
Connecting
중앙 관리자 인스턴스에서 connect(_:, options:) 메서드를 호출하여 연결을 시도할 수 있음
중앙관리자인스턴스.connect(peripherals, options: nil)
- peripherals : CBPeripheral 인스턴스
- options: [String : Any] 타입의 딕셔너리 (Peripheral Connection Options 참조)
연결 성공 시 CBCentralManagerDelegate 프로토콜
central(_:, didConnect:) 델리게이트 메서드 호출
/// 연결이 성공 되었을 때 호출 되는 델리게이트 메서드
/// - Parameters:
/// - central: 중앙관리자
/// - peripheral: 연결된 주변기기
func centralManager(_ central: CBCentralManager,
didConnect peripheral: CBPeripheral) { }
연결 실패 시 CBCentralManagerDelegate 프로토콜
central(_: didFailToConnect:, error:) 델리게이트 메서드 호출
/// 연결이 실패 했을 때 호출되는 델리게이트 메서드
/// - Parameters:
/// - central: 중앙관리자
/// - peripheral: 연결 시도하였으나 실패한 주변기기
/// - error: 실패 이유(에러)
func centralManager(_ central: CBCentralManager,
didFailToConnect peripheral: CBPeripheral,
error: Error?) { }
범위를 벗어난 특정 주변장치에 대해 연결 요청도 할 수 있다.
해당 주변 장치의 정보를 미리 가지고 있다면
이런 경우 iOS는 블루투스가 중지되거나 앱을 수동으로 종료하지 않는 한
central(_:, didConnect:) 가 호출될 때 까지 무기한 대기하게 된다.
Disconnecting
중앙관리자 인스턴스의
cancelPeripheralConnection(_:) 메서드 호출
중앙관리자인스턴스.cancelPeripheralConnection(periphearals)
주변 장치의 모든 참조를 제거하면 암시적으로 cancelPeripheralConnection를 호출한다고 하였으나 테스트를 해보진 않았음
cancelPeripheralConnection(_:)를 호출에 대한 결과는 CBCentralManagerDelegate 프로토콜의
/// 연결 해제 시도 후 호출되는 델리게이트 메서드
/// - Parameters:
/// - central: 중앙 관리자
/// - peripheral: 연결 해제된 주변 장치
/// - error: 해제 실패시 오류 내용이 담겨짐
func centralManager(_ central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: Error?) {
if let error = error {
print("disConnected Error \(error.localizedDescription)")
return
}
}
델리게이트 메서드로 전달된다.
정리
- 중앙관리자 인스턴스의 connect(_:, options:) 메서드를 호출하여 주변 장치로 연결을 시도할 수 있음
- 연결 성공 시 CBCentralManagerDelegate의 centralManager(_:, didConnecting:) 메서드 호출
- 연결 실패 시 CBCentralManagerDelegate의 centralManager(_:, didFailToConnect:, error:) 메서드 호출
- 중앙관리자 인스턴스의 cancelPeripheralConnection(_:) 메서드를 호출하여 주변 장치와의 연결 해제 시도
- 연결 해제 시도후 CBCentralManagerDelegate의 centralManager(_:, didDisconnecting:, error:) 메서드 호출
댓글남기기