天天看點

iOS Core Bluetooth_3 用作中央裝置的常用方法(1/2)[swift實作]章節連接配接寫在前面1 執行個體化中央裝置管理器2 發現正在廣播的外圍裝置3 掃描後連接配接發現的外圍裝置

章節連接配接

iOS Core Bluetooth_1 概述

iOS Core Bluetooth_2 基礎知識

iOS Core Bluetooth_3 用作中央裝置的常用方法(1/2)[swift實作]

iOS Core Bluetooth_4 用作中央裝置的常用方法(2/2)[swift實作]

寫在前面

在藍牙低功耗通信中發揮核心作用的裝置執行許多常見任務,例如,發現并連接配接到可用的外圍裝置,以及探索外圍裝置所提供的資料并與之互動。實作外圍角色的裝置還執行許多常見的其他任務,例如釋出和廣告服務,以及響應來自連接配接的中心的讀取,寫入和訂閱請求。

在本章中,您将從中央學習如何使用Core Bluetooth架構執行最常見的Bluetooth低能耗任務。以下基于代碼的示例将幫助您開發應用程式,以在本地裝置上實作核心角色。具體來說,您将學習如何:

  • 執行個體化中央管理器對象
  • 發現并連接配接到正在廣播的外圍裝置
  • 在連接配接到外圍裝置後浏覽其資料
  • 發送讀寫請求到外圍服務的特征值
  • 訂閱特征值以在更新時被通知

在本文中找到的代碼示例是簡單抽象的。您可能需要進行适當的更改以将其合并到您的真實應用中。

1 執行個體化中央裝置管理器

由于CBCentralManager對象是本地中央裝置的核心藍牙面向對象的表示形式,是以您可以在執行任何藍牙低能耗事務之前配置設定和初始化中央管理器執行個體。您可以通過調用中央管理器的initWithDelegate:queue:options:方法來初始化中央管理器,代碼如下:

注意:在此示例中,self被設定為接收任何外圍角色事件的委托。當您将排程隊列指定為時nil,外圍裝置管理器使用主隊列排程外圍裝置角色事件。

建立外圍裝置管理器時,外圍裝置管理器将調用peripheralManagerDidUpdateState:其代理對象的方法。您必須實作此代理方法,以確定支援低功耗藍牙并可以在本地外圍裝置上使用。通常可以在用extension來實作,實作代碼如下:(完整版本)

internal func centralManagerDidUpdateState(_ central: CBCentralManager) {

        switch central.state {
        case .poweredOn:
            // ... so start working with the peripheral
            os_log("CBManager is powered on")
            retrievePeripheral()
        case .poweredOff:
            os_log("CBManager is not powered on")
            // In a real app, you'd deal with all the states accordingly
            return
        case .resetting:
            os_log("CBManager is resetting")
            // In a real app, you'd deal with all the states accordingly
            return
        case .unauthorized:
            // In a real app, you'd deal with all the states accordingly
            if #available(iOS 13.0, *) {
                switch central.authorization {
                case .denied:
                    os_log("You are not authorized to use Bluetooth")
                case .restricted:
                    os_log("Bluetooth is restricted")
                default:
                    os_log("Unexpected authorization")
                }
            } else {
                // Fallback on earlier versions
            }
            return
        case .unknown:
            os_log("CBManager state is unknown")
            // In a real app, you'd deal with all the states accordingly
            return
        case .unsupported:
            os_log("Bluetooth is not supported on this device")
            // In a real app, you'd deal with all the states accordingly
            return
        @unknown default:
            os_log("A previously unknown central manager state occurred")
            // In a real app, you'd deal with yet unknown cases that might occur in the future
            return
            
        }
    }
           

2 發現正在廣播的外圍裝置

執行個體化後,中央管理器的第一項任務是發現外圍裝置。外圍裝置通過廣播來告知其存在。您的應用通過調用中央管理器的scanForPeripheralsWithServices:options:方法來發現附近正在做廣告的外圍裝置:

centralManager.scanForPeripherals(withServices: [TransferService.serviceUUID],
                                               options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
           
注意:如果nil為第一個參數指定,則中央管理器将傳回所有發現的外圍裝置,而不管其支援的服務如何。在真實應用中,通常需要指定一個CBUUID對象數組,每個對象代表外圍裝置正在廣播的服務的通用唯一辨別符(UUID)。當您指定服務UUID的數組時,中央管理器僅傳回廣播這些服務的外圍裝置,進而使您僅掃描到您可能希望掃描的裝置。CBUUID的聲明方法在後文中涉及。

中央管理器每次發現外圍裝置時,都會調用centralManager:didDiscoverPeripheral:advertisementData:RSSI:其代理對象的方法。新發現的外圍裝置作為CBPeripheral對象傳回。如果您打算連接配接到發現的外圍裝置,請對其進行強引用,以使系統不會取消配置設定它。以下示例顯示了一個使用類屬性來維護對發現的外圍裝置的引用的方案,仍通常在extension中進行實作:

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
        
        // Reject if the signal strength is too low to attempt data transfer.
        // Change the minimum RSSI value depending on your app’s use case.
        guard RSSI.intValue >= -50
        else {
                os_log("Discovered perhiperal not in expected range, at %d", RSSI.intValue)
                return
        }
        
        os_log("Discovered %s at %d", String(describing: peripheral.name), RSSI.intValue)
        
        // Device is in range - have we already seen it?
        if discoveredPeripheral != peripheral {
            
            // Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it.
            discoveredPeripheral = peripheral
            
            // And finally, connect to the peripheral.
            os_log("Connecting to perhiperal %@", peripheral)
            centralManager.connect(peripheral, options: nil)
        }
    }
           

如果您希望連接配接到多個裝置,則可以保留一個Array發現的外圍裝置。無論如何,一旦找到了要連接配接的所有外圍裝置,就停止掃描其他裝置以節省電量,代碼如下:

3 掃描後連接配接發現的外圍裝置

在發現您感興趣的外圍裝置廣告服務之後,您可以通過調用中央管理器的connectPeripheral:options:方法來請求與外圍裝置的連接配接。代碼如下:

如果連接配接請求成功,則中央管理器将調用centralManager:didConnectPeripheral:其代理對象的方法。在開始與外圍裝置進行互動之前,請設定其代理以確定該委托收到适當的回調,通常也使用extension進行實作,代碼如下:

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral){
        // 設定代理
        peripheral.delegate = self
        // 開始發現服務
        peripheral.discoverServices(nil)
        // 儲存目前連接配接裝置
        self.peripheral = peripheral
        // 這裡可以發通知出去告訴裝置連接配接界面連接配接成功
    }
           

如果連接配接失敗,也需要調用對應的 central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error? 代理方法進行回調,實作如下:

func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
        os_log("Failed to connect to %@. %s", peripheral, String(describing: error))
        cleanup()
    }
           

其他發現服務與特征,讀取,訂閱與編寫特征值的方法将在下文中實作。