Notice
Recent Posts
Recent Comments
Link
투케이2K
619. (ios/swift5) [간단 소스] 블루투스 GATT 클라이언트 실시간 Notify 알림 수신 방법 본문
[개발 환경 설정]
개발 툴 : XCODE
개발 언어 : SWIFT5
[소스 코드]
// --------------------------------------------------------------------------------------
[개발 및 테스트 환경]
// --------------------------------------------------------------------------------------
- 언어 : Swift
- 개발 툴 : Xcode
- 기술 구분 : Bluetooth / Gatt / Client / Notify
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
[사전) 권한 설정 및 import 추가 관련]
// --------------------------------------------------------------------------------------
/**
* // ------------------------------------------------------
* 1. 필요 퍼미션 권한 설정 : 블루투스 사용 권한
*
* - Privacy - Bluetooth Always Usage Description
* - Privacy - Bluetooth Peripheral Usage Description
* // ------------------------------------------------------
* 2. 필요 import 호출 선언 :
*
* - import CoreBluetooth
* - import UIKit
* // ------------------------------------------------------
* 3. 참고 사항 :
*
* - 블루투스 GATT 연결을 하기 위해서는 사전 페어링이 되어 있어야합니다 (클라이언트 To 서버)
* - 서버 연결 시 블루투스 Name 값을 기준으로 찾는다
* - 클라이언트와 서버 연결을 위해서는 ServiceUUID , CharacteristicUUID 값이 일치해야합니다
* // ------------------------------------------------------
* */
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
[소스 코드]
// --------------------------------------------------------------------------------------
// -----------------------------------------------------------------------
// MARK: - [전역 변수 선언]
// -----------------------------------------------------------------------
public static let ACTIVITY_NAME = "C_Bluetooth_Gatt_Client_Module"
let SEARCH_BLUETOOTH_NAME = "TWOK-BLUETOOTH" // MARK: [찾으려는 블루투스 이름] : 연결할 Gatt 서버 이름
static var scanBluetoothCentralManager: CBCentralManager! // [블루투스 활성 상태 확인 및 실시간 블루투스 신호 스캔]
static var discoveredPeripheral: CBPeripheral? // [블루투스 연결에 필요한 객체]
var scanBluetoothList: Array<Dictionary<String, String>> = [] // [블루투스 스캔 리스트를 담을 변수]
// -----------------------------------------------------
// MARK: [UUIDs for the GATT service and characteristic] : 서버 및 클라이언트 UUID 값이 일치해야합니다
// -----------------------------------------------------
// MARK: [Android , Ios 간에는 UUID 형식이 다르게 표현 될 수 있습니다]
// -----------------------------------------------------
let targetServiceUUID = CBUUID(string: "0000180F-0000-1000-8000-00805F9B34FB") // 대상 서비스 UUID
let targetCharacteristicUUID = CBUUID(string: "00002A19-0000-1000-8000-00805F9B34FB") // 대상 특성 UUID
// -----------------------------------------------------------------------
// MARK: - [블루투스 권한 확인 요청]
// -----------------------------------------------------------------------
DispatchQueue.main.async {
// [블루투스 권한 확인]
C_Bluetooth_Gatt_Client_Module.scanBluetoothCentralManager = CBCentralManager(delegate: self, queue: nil)
}
// -----------------------------------------------------------------------
// MARK: - [블루투스 권한 부여 상태 확인 함수] : CBCentralManagerDelegate : Delegate
// -----------------------------------------------------------------------
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unknown:
S_Log._E_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: 블루투스 권한 :: unknown :: 블루투스 상태 알수 없음", data: nil)
case .resetting:
S_Log._E_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: 블루투스 권한 :: resetting :: 블루투스 서비스 리셋", data: nil)
case .unsupported:
S_Log._E_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: 블루투스 권한 :: unsupported :: 기기가 블루투스를 지원하지 않습니다", data: nil)
case .unauthorized:
S_Log._E_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: 블루투스 권한 :: unauthorized :: 블루투스 사용 권한 확인 필요", data: nil)
// MARK: [앱 블루투스 권한 사용 설정창 이동 및 확인 필요]
case .poweredOff:
S_Log._E_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: 블루투스 권한 :: poweredOff :: 블루투스 비활성 상태", data: nil)
// MARK: [자동으로 시스템에서 비활성 상태 알림 및 팝업창 호출 실시]
case .poweredOn:
S_Log._W_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: 블루투스 권한 :: poweredOn :: 블루투스 활성 상태", data: nil)
// ---------------------------------------------------------
// MARK: [블루투스 실시간 스캔 시작] : centralManager : didDiscover : 함수에서 확인
// ---------------------------------------------------------
if C_Bluetooth_Gatt_Client_Module.scanBluetoothCentralManager != nil {
// ----------------------------------
// MARK: [전체 블루투스 목록 스캔] : withServices nil 설정
// ----------------------------------
C_Bluetooth_Gatt_Client_Module.scanBluetoothCentralManager?.stopScan() // [사전 블루투스 스캔 종료]
C_Bluetooth_Gatt_Client_Module.scanBluetoothCentralManager?.scanForPeripherals(withServices: nil, options: nil)
}
else {
S_Log._E_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: 블루투스 권한 :: poweredOn :: 실시간 블루투스 리스트 스캔 실패", data: ["scanBluetoothCentralManager is null"])
}
@unknown default:
S_Log._E_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: 블루투스 권한 :: default :: 상태", data: nil)
self.scanBluetoothOperationQueue.isSuspended = false // [블루투스 스캔 큐 해제]
}
}
// -----------------------------------------------------------------------
// MARK: - [실시간 블루투스 스캔 리스트 확인 및 GATT 연결 수행 함수]
// -----------------------------------------------------------------------
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
if peripheral.name == self.SEARCH_BLUETOOTH_NAME {
print("🔵 :: didDiscover :: 실시간 블루투스 스캔 정보 >> NAME - \(String(peripheral.name ?? "")) / UUID - \(String(peripheral.identifier.uuidString)) / RSSI - \(String(RSSI.intValue))")
}
else {
print("🔴 :: didDiscover :: 실시간 블루투스 스캔 정보 >> NAME - \(String(peripheral.name ?? "")) / UUID - \(String(peripheral.identifier.uuidString)) / RSSI - \(String(RSSI.intValue))")
}
// -------------------------------------------------
// MARK: [스캔 리스트에 저장할 포맷 지정]
// -------------------------------------------------
var bleScanDic : Dictionary<String, String> = [String : String]()
bleScanDic["NAME"] = "\(String(peripheral.name ?? ""))"
bleScanDic["UUID"] = "\(String(peripheral.identifier.uuidString))"
//bleScanDic["RSSI"] = "\(String(RSSI.intValue))"
// -------------------------------------------------
// MARK: [블루투스 GATT 연결할 서버 이름을 찾은 경우 >> 연결 수행 실시]
// -------------------------------------------------
if self.scanBluetoothList != nil
&& self.scanBluetoothList.contains(bleScanDic) == false
&& peripheral.name == self.SEARCH_BLUETOOTH_NAME
&& self.scanBluetoothList.count < 1 { // MARK: [배열에 하나만 저장 수행]
// MARK: [배열에 추가]
self.scanBluetoothList.append(bleScanDic)
// MARK: [서버 연결에 필요한 peripheral 삽입]
peripheral.delegate = self // [딜리게이트 지정]
C_Bluetooth_Gatt_Client_Module.discoveredPeripheral = peripheral // [static 객체에 추가]
// MARK: [연결 nil 옵션 지정]
C_Bluetooth_Gatt_Client_Module.scanBluetoothCentralManager?.connect(peripheral, options: nil)
}
}
// -----------------------------------------------------------------------
// MARK: - [블루투스 주변 장치 연결 성공] : CBCentralManagerDelegate : didConnect
// -----------------------------------------------------------------------
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
S_Log._W_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: didConnect :: 실시간 블루투스 GATT 서버 연결 성공", data: ["Connected Name :: \(peripheral.name ?? "Unknown")"])
// MARK: [서비스 찾기 설정]
C_Bluetooth_Gatt_Client_Module.discoveredPeripheral?.discoverServices([self.targetServiceUUID])
}
// -----------------------------------------------------------------------
// MARK: - [블루투스 주변 장치 연결 실패] : CBCentralManagerDelegate : didFailToConnect
// -----------------------------------------------------------------------
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
S_Log._E_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: didFailToConnect :: 실시간 블루투스 GATT 서버 연결 실패", data: ["Error :: \(error?.localizedDescription ?? "Unknown error")"])
}
// -----------------------------------------------------------------------
// MARK: - [블루투스 서비스 발견] : CBPeripheral : didDiscoverServices
// -----------------------------------------------------------------------
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let error = error {
S_Log._E_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: didDiscoverServices :: 서비스 발견 :: Error", data: ["Error :: \(error.localizedDescription)"])
return
}
guard let services = peripheral.services else { return }
for service in services {
if service.uuid == self.targetServiceUUID {
S_Log._W_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: didDiscoverServices :: 서비스 발견 :: Success", data: ["Service Uuid :: \(service.uuid)"])
// [Characteristics 찾기 수행]
peripheral.discoverCharacteristics([self.targetCharacteristicUUID], for: service)
}
}
}
// -----------------------------------------------------------------------
// MARK: - [블루투스 GATT 읽기 요청 및 실시간 알림 수신 결과 처리] : CBPeripheralDelegate : didUpdateValueFor
// -----------------------------------------------------------------------
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
S_Log._E_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: didUpdateValueFor :: 서버 >> 클라이언트 [읽기] 및 [실시간 알림 수신] 응답 :: Error", data: ["Error :: \(error.localizedDescription)"])
}
else {
if let value = characteristic.value {
let stringValue = String(data: value, encoding: .utf8) ?? "Invalid Data"
S_Log._W_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: didUpdateValueFor :: 서버 >> 클라이언트 [읽기] 및 [실시간 알림 수신] 응답 :: Success", data: ["VALUE :: \(stringValue)"])
}
else {
S_Log._E_(description: "\(C_Bluetooth_Gatt_Client_Module.ACTIVITY_NAME) :: didUpdateValueFor :: 서버 >> 클라이언트 [읽기] 및 [실시간 알림 수신] 응답 :: Success", data: ["UUID :: \(characteristic.uuid)"])
}
}
}
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
[참고 사이트]
// --------------------------------------------------------------------------------------
[IOS - 실시간 블루투스 목록 스캔]
https://blog.naver.com/kkh0977/223704822567
[CLLocationManager 간단 설명 및 사용 옵션 정리 - 위치 이벤트]
https://blog.naver.com/kkh0977/223690092317
// --------------------------------------------------------------------------------------
반응형
'IOS' 카테고리의 다른 글
Comments