Swift Bluetooth 사용법
ios 디바이스에 내장된 기능들을 연구하던 도중, bluetooth 또한 공부를 해봐야겠다는 생각이 들었습니다. 그래서 이번 시간에는 BlueTooth를 사용하는 방법에 대해 정리하려고 합니다.
blueTooth의 두 가지 모드
제가 이해한 바로는 bluetooth는 두 가지 모드를 가집니다.
하나는 데이터를 수신할 상태인 centralMode
이고
다른 하나는 데이터를 보낼 상태인 `peripheralMode 입니다.
그러니까 블루투스는 보내는 사람과 받는 사람을 명확히 해줘야 한다는 뜻이 되겠습니다.
물론 어떤 장치는 centralMode와 peripheralMode를 번갈아가며 사용할 수 있습니다.
우리는 이번에 어떤 장치로부터 데이터를 받아올 겁니다.
그래서 데이터를 수신할 상태인 centralMode에서 peripheral 기기로부터 데이터를 받아오도록 하겠습니다.
기본 준비사항 (CBCentral Manager)
먼저 bluetooth 기능을 사용할 viewController에 CoreBluetooth
를 import 합니다.
그리고 블루투스 기능들을 관리할 CBCentralManager
를 하나 생성합니다.
var centralManager = CBCentralManger
처럼요.
그런 다음 viewDidLoad() 함수 내에 다음과 같이 적어줍니다.
centralManager = CBCentralManager(delegate: self, queue: nil)
그리고 CNCentralManagerDelegate
를 받는 extension을 하나 만들어줍니다.
그런 다음 해당 블록 안에 func centralManagerDidUpdateState(_ central: CBCentralManager) {}
를 하나 선언해줍시다.
블록 안에는 central의 상태에 따라 로직을 처리할 switch-case 문을 하나 적어줄 겁니다.
가장 간단한 방법은 switch central.state {}
만 적어두면 옆에 뜨는 오류메시지에서 fix 를 누르는 것입니다.
여기까지 잘 따라하셨다면 코드는 다음과 같아야 합니다.
import CoreBluetooth
import UIKit
class BlueToothViewController: UIViewController {
var centralManager: CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
}
extension BlueToothViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unknown:
print("central.state is unknown")
case .resetting:
print("central.state is resetting")
case .unsupported:
print("central.state is unsupported")
case .unauthorized:
print("central.state is unauthorized")
case .poweredOff:
print("central.state is poweredOff")
case .poweredOn:
print("central.state is poweredOn")
@unknown default:
print("central.state default case")
}
}
}
또한 애플 공식문서 를 보면 반드시 info.plist에 다음의 사진에 나와있는 것들을 추가하라고 나와있습니다.
ios 버젼에 따라 둘 중 하나를 쓸 것입니다. (말투가 왜이렇게 번역체 같을까요?)
이대로 실행해보면 다음과 같은 메시지가 콘솔창에 출력됩니다.
central.state is poweredOn
CBCentralManager로 Peripheral 출력하기
이제 poweredOn case에 다음 한 줄을 적어줍니다.
centralManager.scanForPeripherals(withServices: nil)
이 메서드는 주변의 peripheral device(데이터를 보낼 준비가 돼 있는 장치)들을 스캔합니다.
여기서 서비스에 특정 기기만 적용하고 싶다면 다음 글을 참고해주세요 : 링크
이 정보를 받아오기 위해서는 다음의 메서드를 써야 하는데, 너무 길기 때문에 그냥 device
만 치면 나오는 auto-complete를 이용합시다.
// extension 안에 적어줍니다.
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(peripheral)
}
build and run을 해봅시다.
다음과 같이 주변에 사용할 수 있는 장치들이 검색됩니다.
<CBPeripheral: 0x281aa5540, identifier = DB469E0F-2CDE-D87B-BD7E-6D4191D6A646, name = 최강훈’s MacBook Pro, state = disconnected>
<CBPeripheral: 0x281aa1680, identifier = FF8294B9-AB4A-1FE3-C4B5-968429F58B52, name = (null), state = disconnected>
<CBPeripheral: 0x281aa1680, identifier = EE3EF6D1-A08E-8BAE-538F-017D839CFB62, name = LE_WH-1000XM4, state = disconnected>
peripheral 연결하기
여기서 제 맥북의 정보만 얻어오고 싶다고 가정하겠습니다.
이를 위해 위에서 출력한 제 맥북의 identifer 복사헤두고,
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
함수 안에
다음의 조건문을 적어줍시다.
if peripheral.identifier.uuidString == "your macbook pro's identifier"
그럼 이제 받아온 peripheral을 연결해야 하는데, 연결 이후 정보를 얻어오기 위해서는 아무래도 자체 peripheral 변수가 필요할 것 같습니다.
그래서 우리가 선언한
var centralManager: CBCentralManager!
밑에
var macbookPeripheral: CBPeripheral!
변수를 추가해주겠습니다.
그리고
if peripheral.identifier.uuidString == "your macbook pro's identifier"
조건문 내에
다음을 적어주겠습니다.
if peripheral.identifier.uuidString == "DB469E0F-2CDE-D87B-BD7E-6D4191D6A646" {
self.macbookPeripheral = peripheral
// macbookPeripheral.delegate = self // 아직 안 씀.
centralManager.stopScan()
centralManager.connect(macbookPeripheral)
}
여기까지 했다면 이제 블루투스가 연결이 될 겁니다.
이를 테스트 하기 위해
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
함수를
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
함수
밑에 추가해줍니다.
그리고 그 브라켓 안에 code에 print("Connected")로 교체하여 실행하면
정상적으로 Connected라는 문구가 출력됩니다.
service discover하기
블루투스에는 discover
라는 용어를 쓰는 것 같습니다.
그래서 방금 print("Connected")
라고 적어준 코드를 다음 코드로 바꿔줍시다.
macbookPeripheral.discoverServices(nil)
참고로 여기서 nil 이라는 옵션은 모든 서비스를 검색하는 것입니다.
discover한 service는 for - in 문을 이용해 출력할 수 있습니다.
그러나
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
함수 안에서
for - in 문을 호출하면 제대로 출력되지 않습니다.
connect 되기 전에 함수가 돌아가기 때문입니다.
이를 위해 우리는 CBPeripheralDelegate라는 프로토콜을 하나 더 구현할 것입니다.
extension 하나를 다음과 같이 추가해줍시다.
extension BlueToothViewController: CBPeripheralDelegate {
code
}
그리고 if peripheral.identifier.uuidString ==""
영역 안에서 delegate를 self로 바꿔줍시다.
다음과 같이요.
self.macbookPeripheral = peripheral
macbookPeripheral.delegate = self // 이 부분.
centralManager.stopScan()
centralManager.connect(macbookPeripheral)
이제 service를 출력해봅시다.
방금 만든 extension 내에 다음 함수를 추가합니다.
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
}
그리고 내용을 다음과 같이 줍시다.
guard let services = macbookPeripheral.services else {return}
for service in services {
print(service)
peripheral.discoverCharacteristics(nil, for: service)
}
여기까지 한다면 services 하나하나를 출력해볼 수 있습니다.
build and run을 해봅시다.
<CBService: 0x283501b00, isPrimary = YES, UUID = Device Information>
<CBService: 0x283501bc0, isPrimary = YES, UUID = Continuity>
<CBService: 0x283501c00, isPrimary = YES, UUID = 9FA480E0-4967-4542-9390-D343DC5D04AE>
이번 글에서 bluetooth를 테스트해보는 것은 여기가 끝입니다.
전체 코드는 글의 맨 아래에 첨부해두겠습니다.
추가로 확인할 수 있는 것들
방금 출력한 Service들은 macbook 정보를 출력해서 그렇지 블루투스를 목적으로 하는 기기에 대한 것들은 조금 다르게 생겼습니다.
이것에 대해 자세히 확인하고 싶다면 다음 링크를 참고해주세요 : 링크
전체 코드
import CoreBluetooth
import UIKit
class BlueToothViewController: UIViewController {
var centralManager: CBCentralManager!
var macbookPeripheral: CBPeripheral!
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
}
extension BlueToothViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unknown:
print("central.state is unknown")
case .resetting:
print("central.state is resetting")
case .unsupported:
print("central.state is unsupported")
case .unauthorized:
print("central.state is unauthorized")
case .poweredOff:
print("central.state is poweredOff")
case .poweredOn:
print("central.state is poweredOn")
centralManager.scanForPeripherals(withServices: nil)
@unknown default:
print("central.state default case")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if peripheral.identifier.uuidString == "DB469E0F-2CDE-D87B-BD7E-6D4191D6A646" {
self.macbookPeripheral = peripheral
macbookPeripheral.delegate = self
centralManager.stopScan()
centralManager.connect(macbookPeripheral)
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("connected!")
// 아래 파라미터가 nil이면 모든 서비스를 검색.
macbookPeripheral.discoverServices(nil)
// 연결 끊기
// centralManager.cancelPeripheralConnection(peripheral)
}
}
extension BlueToothViewController: CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
guard let services = macbookPeripheral.services else {return}
for service in services {
print(service)
peripheral.discoverCharacteristics(nil, for: service)
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
guard let characteristics = service.characteristics else {return}
for characteristic in characteristics {
print("characteristic: \(characteristic)")
if characteristic.properties.contains(.read) {
print("readable")
peripheral.readValue(for: characteristic)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
print("didUpdateValueFor characteristic")
print(characteristic.value ?? "can't get value")
}
}
'iOS::스위프트(swift) > iOS Device' 카테고리의 다른 글
[21.10.19] 맥북 M1 드디어 공개 !!(m1프로/맥스) (0) | 2021.10.19 |
---|---|
[iOS][Swift] 디바이스 고유 ID(UUID) 키체인 저장. (0) | 2021.10.15 |
PLA / iOS team provisioning 에러 처리하기 (0) | 2021.07.22 |
스마트폰(아이폰) 센서로는 어떤 것들이 있을까 ? (2) | 2021.04.02 |
최근댓글