iT邦幫忙

2024 iThome 鐵人賽

DAY 29
0
Mobile Development

少年K的Swift奇幻漂流記系列 第 29

Day 29 Swift 藍牙應用實作 Part 1 – 建立藍牙服務的 Swift 檔案

  • 分享至 

  • xImage
  •  

在這篇文章中,我們將深入探討使用 Swift 實作藍牙應用的第一部分。我們將建立一個 BluetoothService 類別,作為我們應用中管理藍牙連接的核心。這個服務將負責掃描藍牙周邊設備、連接這些設備以及管理數據通信。

設置藍牙服務

BluetoothService 類別利用 CoreBluetooth 框架的功能來與藍牙設備進行互動。以下是實作的內容:

import Foundation
import CoreBluetooth

class BluetoothService: NSObject {
    
    static let shared = BluetoothService()
    weak var delegate: BluetoothServiceDelegate?
    
    var central: CBCentralManager?
    var peripheral: CBPeripheralManager?
        
    var connectedPeripheral: CBPeripheral?
    var rxtxCharacteristic: CBCharacteristic?
    
    private var bluePeripherals: [CBPeripheral] = []
    
    // 初始化:副線程
    private override init() {
        super.init()
        
        let queue = DispatchQueue.global()
        central = CBCentralManager(delegate: self, queue: queue)
    }
    
    // 開始掃描藍牙裝置
    func startScan() {
        central?.scanForPeripherals(withServices: nil, options: nil)
    }
    
    // 停止掃描
    func stopScan() {
        central?.stopScan()
    }
    
    // 連接藍牙周邊設備
    func connectPeripheral(peripheral: CBPeripheral) {
        self.connectedPeripheral = peripheral
        central?.connect(peripheral, options: nil)
    }
    
    // 中斷與藍牙周邊設備連接
    func disconnectPeripheral(peripheral: CBPeripheral) {
        central?.cancelPeripheralConnection(peripheral)
    }
}

主要組件說明

  • 單例模式: 我們將 BluetoothService 實作為單例,使用靜態的 shared 實例,這樣可以方便地從應用的任何地方訪問服務。

  • CBCentralManager: 這是管理發現的藍牙設備的主要介面。我們在背景線程中初始化它,以確保性能流暢。

  • 周邊設備管理: 此服務可以掃描周邊設備、連接選定的設備並在必要時中斷連接。

處理藍牙狀態和設備發現

我們需要實作 CBCentralManagerDelegate 的方法,以處理藍牙狀態更新和發現設備的事件:

extension BluetoothService: CBCentralManagerDelegate {
    
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch central.state {
        case .unknown:
            print("unknown")
        case .resetting:
            print("resetting")
        case .unsupported:
            print("unsupported")
        case .unauthorized:
            print("unauthorized")
        case .poweredOff:
            print("poweredOff")
        case .poweredOn:
            print("poweredOn")
        @unknown default:
            print("藍牙裝置未知狀態")
        }
        startScan()
    }
    
    // 發現藍牙裝置
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        
        for newPeripheral in bluePeripherals {
            if peripheral.name == newPeripheral.name {
                return
            }
        }
        if let name = peripheral.name {
            bluePeripherals.append(peripheral)
            print(name)
        }
        delegate?.getBLEPeripherals(peripherals: bluePeripherals)
    }
    
    // 連接到設備
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        peripheral.delegate = self
        peripheral.discoverServices(nil)
    }
}

主要功能說明:

  • 狀態更新: centralManagerDidUpdateState 方法響應藍牙狀態的變化。如果藍牙已開啟,則開始掃描周邊設備。

  • 設備發現: didDiscover 方法過濾掉重複的周邊設備,並更新代理,提供已發現設備的列表。

發現服務和特徵

一旦連接到周邊設備,下一步是發現其服務和特徵。我們可以通過實作 CBPeripheralDelegate 的方法來完成這一點:

extension BluetoothService: CBPeripheralDelegate {
    
    // 發現服務
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: (any Error)?) {
        if let service = peripheral.services {
            for service in service {
                print(service)
                peripheral.discoverCharacteristics(nil, for: service)
            }
        }
    }
    
    // 發現特徵
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: (any Error)?) {
        if let characteristics = service.characteristics {
            for characteristic in characteristics {
                print(characteristic)
                if characteristic.uuid.isEqual(CBUUID(string: "FFE1")) {
                    peripheral.readValue(for: characteristic)
                    peripheral.setNotifyValue(true, for: characteristic)
                    rxtxCharacteristic = characteristic
                }
            }
        }
    }
    
    // 特徵值更新
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: (any Error)?) {
        guard characteristic == rxtxCharacteristic,
              let characteristicValue = characteristic.value,
              let ASCIIstring = String(data: characteristicValue, encoding: String.Encoding.utf8) else {
            return
        }
        print(ASCIIstring)
        delegate?.getBLEPeripheralsValue(value: ASCIIstring)
    }
}

功能概述:

  • 服務發現: didDiscoverServices 方法檢索連接的周邊設備提供的服務。

  • 特徵管理: 在 didDiscoverCharacteristicsFor 中,我們檢查是否存在特定的特徵(UUID 為 "FFE1"),並設置該特徵為通知模式。

  • 數據接收: didUpdateValueFor 方法用於檢索和處理來自周邊設備的數據。

結論

在這部分的藍牙應用實作中,我們成功建立了一個 BluetoothService 類別,這為連接和互動藍牙設備奠定了基礎。通過管理中央管理器和周邊通信,我們現在可以基於這個服務進一步開發功能完善的藍牙應用。


上一篇
Day28 Swift Clock App 實作 Part 8:選擇鈴聲畫面
下一篇
Day30 Swift Bluetooth App 實作 Part 2:主畫面
系列文
少年K的Swift奇幻漂流記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言