CBPeripheral: ano ito, mga pamamaraan at pamamahala ng BLE-peripheral sa iOS

May-akda: IT Sectr Nai-publish: 2026-07-16 Oras ng pagbabasa: 10 min

CBPeripheral — ang klase ng Core Bluetooth framework na kumakatawan sa isang malayong BLE device sa iOS. Bawat CBPeripheral object ay nag-encapsulate ng UUID, pangalan, RSSI, at hierarchy ng GATT services ng nakakonektang BLE device. Ang developer ay nakikipag-ugnayan sa peripheral eksklusibo sa pamamagitan ng CBPeripheral: discovery ng mga serbisyo (discoverServices:), pagbasa ng mga characteristic (readValueForCharacteristic:), pagsulat ng data (writeValue:forCharacteristic:type:) at pag-subscribe sa mga notification (setNotifyValue:forCharacteristic:). Ayon sa Apple Developer, 2026, ang CBPeripheral — ang sentral na bagay para sa lahat ng operasyon sa BLE-peripheral, na ibinabalik ng CBCentralManager sa pagtuklas o pagkonekta ng device.

Mga Pangunahing Punto

  • CBPeripheral — Core Bluetooth class para sa pagtatrabaho sa malayong BLE device sa iOS
  • GATT Hierarchy — Peripheral ay naglalaman ng mga serbisyo (CBService), serbisyo ay naglalaman ng mga characteristic (CBCharacteristic), characteristic ay naglalaman ng mga descriptor (CBDescriptor)
  • Discovery — discoverServices: at discoverCharacteristics:forService: para makuha ang GATT structure ng device
  • Pagbasa at pagsulat — readValueForCharacteristic: at writeValue:forCharacteristic:type: may kumpirmasyon (withResponse) o wala (withoutResponse)
  • Mga Notification — setNotifyValue:forCharacteristic: ay nag-aactivate ng subscription sa mga pagbabago ng BLE device characteristic

Ano ang CBPeripheral: esensya at layunin

CBPeripheral — ay isang bagay na kumakatawan sa isang malayong BLE device sa isang iOS application. Hindi tulad ng CBCentralManager, na namamahala sa lokal na Bluetooth adapter ng iPhone, ang CBPeripheral ay nagmomodelo ng isang panlabas na peripheral device: sensor, fitness tracker, beacon, medikal na aparato. Bawat instance ng CBPeripheral ay naglalaman ng natatanging identifier (UUID) na pinapanatili sa pagitan ng mga session ng koneksyon — iniuugnay ng Apple ang UUID sa isang partikular na device sa pamamagitan ng system Bonding.

Ang CBPeripheral ay hindi direktang nilikha sa pamamagitan ng init. Ang Core Bluetooth framework ay nagbabalik ng CBPeripheral object sa dalawang senaryo: sa pagtuklas ng device sa pamamagitan ng scanForPeripheralsWithServices: (delegate didDiscoverPeripheral) at sa pagkonekta sa isang dating kilalang device sa pamamagitan ng retrievePeripheralsWithIdentifiers:. Pagkatapos matanggap ang object, ang developer ay tumatawag ng connectPeripheral: sa CBCentralManager, pagkatapos nito ang CBPeripheral ay nagiging available para sa GATT operations.

Lifecycle ng CBPeripheral ay may kasamang anim na estado: disconnected (paunang), connecting (pagkatapos ng tawag na connect), connected (pagkatapos ng didConnectPeripheral), discovering (habang tumatawag ng discoverServices), discovered (pagkatapos makatanggap ng mga serbisyo) at disconnecting (pagkatapos ng cancelPeripheralConnection). Bawat estado ay sinusubaybayan sa pamamagitan ng delegado CBPeripheralDelegate — mandatoryong protocol para sa bawat BLE application sa iOS.

CBPeripheral at GATT hierarchy: mga serbisyo, characteristic, descriptor

CBPeripheral ay nag-iimbak ng hierarchical GATT structure na binubuo ng tatlong antas. Ang ugat na antas — isang array ng CBService (mga serbisyo), bawat serbisyo ay naglalaman ng array ng CBCharacteristic (mga characteristic), bawat characteristic ay naglalaman ng array ng CBDescriptor (mga descriptor). Ang modelong ito ay ganap na tumutugma sa Bluetooth GATT specification: serbisyo — function ng device (halimbawa, „Heart Rate Service“), characteristic — konkretong halaga (pulso 72 bpm), descriptor — metadata ng characteristic (mga yunit ng pagsukat, configuration ng notification).

AntasCore Bluetooth ClassPaglalarawan
SerbisyoCBServiceLohikal na grupo ng magkakaugnay na characteristic, kinikilala ng UUID (16-bit, 32-bit o 128-bit)
CharacteristicCBCharacteristicKonkretong halaga ng data, sumusuporta sa pagbasa, pagsulat, notification
DescriptorCBDescriptorMetadata ng characteristic: client configuration CCCD, User Description, Presentation Format

Ang mga karaniwang BLE service ay nakarehistro sa Bluetooth SIG: Heart Rate Service (UUID 180D), Battery Service (180F), Device Information (180A), Blood Pressure (1810). Para sa mga custom na serbisyo, ginagamit ang 128-bit UUID (halimbawa, E20A39F4-73F5-4BC4-A12F-17D1AD07A961). Awtomatikong kinikilala ng iOS ang mga karaniwang UUID at nagpapakita ng mga nababasang pangalan; ang mga custom na UUID ay ipinapakita sa hex format.

Pagkatapos ng koneksyon, ang hierarchy ng CBPeripheral ay walang laman — ang mga serbisyo at characteristic ay hindi na-load. Ang developer ay dapat tumawag ng discoverServices: upang makuha ang mga serbisyo at pagkatapos para sa bawat serbisyo ay tumawag ng discoverCharacteristics:forService:. Kung ang serbisyo ay naglalaman ng mga included services (includedServices), karagdagang tinatawag ang discoverIncludedServices:forService:. Pagkatapos lamang makumpleto ang discovery ng hierarchy, ang CBPeripheral ay napupuno at nagiging available para sa pagbasa at pagsulat.

Discovery ng mga serbisyo at characteristic: mga pamamaraan at delegado

Discovery (pagtuklas) ng GATT structure ng CBPeripheral — isang mandatoryong hakbang bago ang anumang operasyon ng pagbasa o pagsulat. Ang pamamaraang discoverServices: ay naglulunsad ng asynchronous na paghahanap ng lahat ng serbisyo ng device. Kung ang nil ay ipinasa, lahat ng serbisyo ay matutuklasan; kung ang isang array ng CBUUID ay ipinasa — mga serbisyo lamang na may tinukoy na UUID (time optimization). Ang resulta ay darating sa delegado peripheral:didDiscoverServices: — pinupunan ng CBPeripheral object ang properties services ng array ng CBService.

Pagkatapos makuha ang mga serbisyo, para sa bawat CBService ay dapat tawagan ang discoverCharacteristics:forService:. Katulad nito, nil — lahat ng characteristic, array ng CBUUID — mga tinukoy lamang. Resulta: peripheral:didDiscoverCharacteristicsForService:error:. Sa yugtong ito, ang CBCharacteristic ay nakakatanggap ng mga properties (.read, .write, .notify, .indicate) na tumutukoy sa mga pinapayagang operasyon.

swift
import CoreBluetooth

extension BLEViewController: CBPeripheralDelegate {

    // 1. Discovery ng serbisyo
    func peripheral(_ peripheral: CBPeripheral,
                     didDiscoverServices error: Error?) {
        guard let services = peripheral.services else { return }

        for service in services {
            // Hilingin ang mga characteristic para sa bawat serbisyo
            peripheral.discoverCharacteristics(nil, for: service)
        }
    }

    // 2. Discovery ng characteristic
    func peripheral(_ peripheral: CBPeripheral,
                     didDiscoverCharacteristicsFor service: CBService,
                     error: Error?) {
        guard let characteristics = service.characteristics else { return }

        for characteristic in characteristics {
            if characteristic.properties.contains(.read) {
                peripheral.readValue(for: characteristic)
            }
            if characteristic.properties.contains(.notify) {
                peripheral.setNotifyValue(true, for: characteristic)
            }
        }
    }

    // 3. Basahin ang halaga
    func peripheral(_ peripheral: CBPeripheral,
                     didUpdateValueFor characteristic: CBCharacteristic,
                     error: Error?) {
        guard let data = characteristic.value,
              let value = String(data: data, encoding: .utf8)
        else { return }
        print("Characteristic value: \(value)")
    }
}

Sa halimbawa, tatlong mandatoryong pamamaraan ng pagtuklas ng CBPeripheralDelegate ang ipinatupad. Ang didDiscoverServices ay umuulit sa lahat ng natagpuang serbisyo at humihiling ng mga characteristic. Ang didDiscoverCharacteristicsForService ay sumusuri sa mga property ng bawat characteristic: para sa .read ay tumatawag ng readValue, para sa .notify — setNotifyValue(true). Ang pamamaraang didUpdateValueForCharacteristic ay tumatanggap ng kasalukuyang halaga sa format na Data.

Pagbasa at pagsulat ng mga characteristic: withResponse at withoutResponse

Pagbasa ng mga halaga CBCharacteristic ay ginagawa sa pamamagitan ng pamamaraang readValueForCharacteristic:. Ang resulta ay dumarating nang asynchronous sa peripheral:didUpdateValueForCharacteristic:error:. Mahalaga: ang device ay maaaring may naka-cache na halaga (ang characteristic.value ay available kaagad pagkatapos ng discovery), ngunit para makuha ang kasalukuyang halaga, ang tawag na readValue ay mandatory. Maaaring i-cache ng iOS ang mga halaga para sa energy efficiency — nire-refresh ng readValue ang cache.

Pagsulat ng mga halaga ay ginagawa sa pamamagitan ng pamamaraang writeValue:forCharacteristic:type:. Ang parameter na type ay tumutukoy sa uri ng pagsulat: .withResponse (CBCharacteristicWriteWithResponse) — kinukumpirma ng device ang pagsulat sa pamamagitan ng didWriteValueForCharacteristic; .withoutResponse (CBCharacteristicWriteWithoutResponse) — pagsulat nang walang kumpirmasyon, maximum na bilis, ngunit walang garantiya ng paghahatid. Nililimitahan ng BLE specification ang MTU (Maximum Transmission Unit): hanggang 23 bytes para sa BLE 4.0, hanggang 251 bytes para sa BLE 5.0+. Para sa data na mas malaki kaysa sa MTU, kinakailangan ang fragmentation sa antas ng application.

swift
// Pagbasa at pagsulat ng CBPeripheral characteristic
class BLEService {

    private let peripheral: CBPeripheral
    private let serviceUUID = CBUUID(string: "180D")
    private let charUUID = CBUUID(string: "2A37")

    init(peripheral: CBPeripheral) {
        self.peripheral = peripheral
    }

    // Basahin nang may kumpirmasyon
    func readHeartRate() {
        guard let service = peripheral.services?.first(where: { $0.uuid == serviceUUID }),
              let characteristic = service.characteristics?.first(where: { $0.uuid == charUUID })
        else { return }
        peripheral.readValue(for: characteristic)
    }

    // Sumulat nang may kumpirmasyon (withResponse)
    func writeWithResponse(data: Data) {
        guard let characteristic = findCharacteristic() else { return }
        peripheral.writeValue(data, for: characteristic,
                             type: .withResponse)
    }

    // Sumulat nang walang kumpirmasyon (withoutResponse)
    // Maximum throughput, walang garantiya ng paghahatid
    func writeWithoutResponse(data: Data) {
        guard let characteristic = findCharacteristic() else { return }
        peripheral.writeValue(data, for: characteristic,
                             type: .withoutResponse)
    }

    private func findCharacteristic() -> CBCharacteristic? {
        return peripheral.services?
            .flatMap { $0.characteristics ?? [] }
            .first(where: { $0.uuid == charUUID })
    }
}

Ang pagpili ng uri ng pagsulat na withResponse o withoutResponse ay nakadepende sa kinakailangan ng pagiging maaasahan. Para sa mga utos (buksan ang ilaw, buksan ang lock) gamitin ang withResponse — ang garantiya ng paghahatid ay kritikal. Para sa streaming data (pulso, temperatura) gamitin ang withoutResponse — ang pagkawala ng isang packet ay hindi makabuluhan. Ang BLE device ay maaaring sumuporta lamang ng isang uri ng pagsulat — suriin ang property na characteristic.properties.contains(.write) at .writeWithoutResponse.

Pag-subscribe sa mga BLE notification sa pamamagitan ng setNotifyValue

Mga Notification — mekanismo ng BLE kung saan ang peripheral device ay nagpapadala ng halaga ng characteristic sa central device nang asynchronous, walang patuloy na polling mula sa sentral. Ina-activate ng CBPeripheral ang subscription sa pamamagitan ng pamamaraang setNotifyValue:forCharacteristic:. Pagkatapos ng activation ng subscription, awtomatikong isinusulat ng iOS ang CCCD (Client Characteristic Configuration Descriptor) sa peripheral, at ang device ay nagsisimulang magpadala ng mga update sa bawat pagbabago ng halaga.

Hindi tulad ng mga indica (indicate), ang mga notification ay hindi nangangailangan ng kumpirmasyon mula sa sentral — ang packet ay ipinadala at nakalimutan. Ito ay nagbibigay ng maximum bandwidth, ngunit posible ang pagkawala ng packet. Ang mga indica ay nangangailangan ng kumpirmasyon sa antas ng protocol (L2CAP) — mas maaasahan ngunit mas mabagal. Ang CBCharacteristic sa pamamagitan ng property na properties ay eksaktong nagpapahiwatig kung aling mode ang sinusuportahan: .notify, .indicate o pareho.

Sa pagdiskonekta ng CBPeripheral (disconnect, paglabas sa saklaw), lahat ng aktibong subscription ay awtomatikong nare-reset. Sa muling pagkonekta, kailangang tawagan muli ang setNotifyValue:true para sa bawat characteristic. Nawawala rin ng iOS ang mga subscription kapag lumabas ang application mula sa foreground (kung ang background mode ay hindi naka-enable) — para sa background work, kinakailangang i-enable ang capability na „Uses Bluetooth LE accessories“ sa Info.plist.

swift
// Pamamahala ng subscription sa notification ng CBPeripheral
class NotificationManager: NSObject {

    private var peripheral: CBPeripheral?
    private var subscribedCharacteristics: Set<CBUUID> = []

    // Mag-subscribe sa mga notification para sa lahat ng .notify characteristic
    func subscribeToAllNotifications(peripheral: CBPeripheral) {
        self.peripheral = peripheral

        guard let services = peripheral.services else { return }

        for service in services {
            guard let characteristics = service.characteristics else { continue }

            for characteristic in characteristics {
                if characteristic.properties.contains(.notify)
                    || characteristic.properties.contains(.indicate) {
                    peripheral.setNotifyValue(true, for: characteristic)
                    subscribedCharacteristics.insert(characteristic.uuid)
                }
            }
        }
    }

    // Mag-unsubscribe sa lahat ng notification
    func unsubscribeFromAll() {
        guard let peripheral = peripheral else { return }
        guard let services = peripheral.services else { return }

        for service in services {
            guard let characteristics = service.characteristics else { continue }

            for characteristic in characteristics {
                if subscribedCharacteristics.contains(characteristic.uuid) {
                    peripheral.setNotifyValue(false, for: characteristic)
                }
            }
        }
        subscribedCharacteristics.removeAll()
    }

    // Handler ng notification
    func peripheral(_ peripheral: CBPeripheral,
                     didUpdateNotificationStateFor characteristic: CBCharacteristic,
                     error: Error?) {
        if characteristic.isNotifying {
            print("Subscription active: \(characteristic.uuid)")
        } else {
            print("Subscription inactive: \(characteristic.uuid)")
        }
    }
}

Ang tagapamahala ng subscription na NotificationManager ay nagpapakita ng tamang pagtatrabaho sa mga notification ng CBPeripheral. Ang subscribeToAllNotifications ay umuulit sa lahat ng serbisyo at characteristic, ina-activate ang .notify at .indicate. Sinusubaybayan ng subscribedCharacteristics ang mga aktibong subscription para sa tamang pag-unsubscribe. Kinukumpirma ng didUpdateNotificationStateForCharacteristic ang matagumpay na pagbabago ng estado ng subscription sa pamamagitan ng property na characteristic.isNotifying.

Buong halimbawa ng pagtatrabaho sa CBPeripheral sa Swift

Buong cycle ng trabaho sa CBPeripheral ay may kasamang: pagtanggap ng object mula sa CBCentralManager, pagkonekta, discovery, pagbasa/pagsulat, pag-subscribe sa mga notification at pagdiskonekta. Sa halimbawa sa ibaba, ipinatupad ang klase na BLEConnection na namamahala sa buong lifecycle ng BLE-peripheral sa Swift gamit ang modernong async/await API (iOS 15+).

swift
import CoreBluetooth

// Buong halimbawa ng pamamahala ng CBPeripheral gamit ang async/await
class BLEConnection: NSObject {

    private let centralManager: CBCentralManager
    private var peripheral: CBPeripheral?
    private var continuation: CheckedContinuation<Void, Error>?

    override init() {
        centralManager = CBCentralManager(delegate: nil, queue: .main)
        super.init()
        centralManager.delegate = self
    }

    // 1. Kumonekta sa peripheral
    func connect(to peripheral: CBPeripheral) async throws {
        self.peripheral = peripheral
        peripheral.delegate = self
        centralManager.connect(peripheral, options: nil)

        try await withCheckedThrowingContinuation { continuation in
            self.continuation = continuation
        }
    }

    // 2. Discovery  
    func discoverServices() async throws {
        guard let peripheral = peripheral else {
            throw BLEError.notConnected
        }
        peripheral.discoverServices(nil)
        try await withCheckedThrowingContinuation { continuation in
            self.continuation = continuation
        }
    }
}

// 3. CBCentralManager
extension BLEConnection: CBCentralManagerDelegate {
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        // Pangasiwaan ang estado ng Bluetooth device
    }

    func centralManager(_ central: CBCentralManager,
                        didConnect peripheral: CBPeripheral) {
        continuation?.resume()
        continuation = nil
    }

    func centralManager(_ central: CBCentralManager,
                        didFailToConnect peripheral: CBPeripheral,
                        error: Error?) {
        continuation?.resume(throwing: error ?? BLEError.connectionFailed)
        continuation = nil
    }
}

enum BLEError: Error {
    case notConnected
    case connectionFailed
    case serviceNotFound
    case characteristicNotFound
}

Ang klase na BLEConnection ay gumagamit ng Swift Concurrency (async/await) sa pamamagitan ng CheckedContinuation — isang modernong pattern para sa pagtatrabaho sa delegate APIs ng Core Bluetooth. Ang connect(to:) ay naghihintay ng kumpirmasyon ng koneksyon sa pamamagitan ng didConnectPeripheral, ang discoverServices() — sa pamamagitan ng didDiscoverServices. Ang pamamaraang ito ay nag-aalis ng nested na mga delegado at ginagawang linear at nababasa ang BLE code. Ang paghawak ng error sa pamamagitan ng BLEError ay sumasaklaw sa lahat ng tipikal na senaryo ng pagkabigo ng BLE connection.

Mga Madalas Itanong

Paano makakuha ng CBPeripheral nang walang pag-scan?

Ang CBPeripheral para sa dating nakonektang device ay maaaring makuha sa pamamagitan ng retrievePeripheralsWithIdentifiers: sa CBCentralManager. Magpasa ng array ng UUID (NSUUID) ng mga dating na-save na device — ibabalik ng framework ang isang array ng CBPeripheral para sa mga device sa system BLE-bonding database. Ito ay gumagana lamang para sa mga device na dati nang na-pair sa iPhone. Para sa bagong device, ang pag-scan ay mandatory.

Bakit hindi natutuklasan ng CBPeripheral ang mga serbisyo?

Mga pangunahing dahilan: ang device ay nasa labas ng saklaw (RSSI sa ibaba ng threshold), ang BLE radio ay naka-off (CBCentralManager.state != .poweredOn), ang delegado CBPeripheralDelegate ay hindi naka-set (peripheral.delegate = self), o ang tawag na discoverServices ay naisagawa bago ang koneksyon. Suriin ang status ng centralManager.state, tiyakin na ang delegado ay naka-set bago ang tawag na connect at gumamit ng retry na may timeout na 5–10 segundo.

Ano ang gagawin kung ang writeValue ay hindi tumutugon?

Dahilan — paggamit ng .withResponse sa isang characteristic na sumusuporta lamang sa .writeWithoutResponse o vice versa. Suriin ang characteristic.properties bago ang tawag. Maaari ring problema sa MTU: kung ang data > 20 bytes (BLE 4.0 MTU), kailangan ang MTU negotiation sa pamamagitan ng negotiateMTU o fragmentation. Gamitin ang peripheral.maximumWriteValueLength(for: .withResponse) upang matukoy ang maximum na laki ng packet.

Paano makilala ang CBPeripheral na nasa saklaw mula sa hindi ma-access?

Ang CBPeripheral sa labas ng saklaw ay hindi agad nadidiskonekta — inililipat ito ng iOS sa estado na .disconnected sa pamamagitan ng timeout (karaniwang 20–30 segundo). Para sa pagsubaybay, gamitin ang readRSSI sa CBPeripheral — kapag hindi available, magbabalik ito ng error na may code na CBError.connectionTimeout. Subaybayan din ang centralManager:didDisconnectPeripheral:error: para sa napapanahong pagtuklas ng pagkawala ng koneksyon.

Maaari bang gamitin ang isang CBPeripheral mula sa maraming thread?

Ang Core Bluetooth ay hindi thread-safe — lahat ng tawag sa CBPeripheral ay dapat isagawa mula sa isang queue (karaniwang main queue o serial queue na tinukoy sa initialization ng CBCentralManager). Ang sabay-sabay na mga tawag mula sa iba't ibang thread ay humahantong sa race condition at pag-crash ng application. Gamitin ang DispatchQueue(label: „com.app.ble“) para sa lahat ng BLE operations at DispatchQueue.main.async para sa UI updates.

Buod

  • CBPeripheral — Core Bluetooth class para sa pagtatrabaho sa malayong BLE device sa iOS, ibinabalik ng CBCentralManager
  • GATT hierarchy ay binubuo ng mga serbisyo (CBService), characteristic (CBCharacteristic) at descriptor (CBDescriptor) na may 16-bit o 128-bit UUID
  • Discovery ay isinasagawa nang sunud-sunod: discoverServices: → discoverCharacteristics:forService: na may pagproseso sa pamamagitan ng delegado
  • Pagbasa — readValueForCharacteristic:, pagsulat — writeValue:forCharacteristic:type: (.withResponse o .withoutResponse)
  • Mga Notification — setNotifyValue:forCharacteristic: ay nag-aactivate ng asynchronous na pagpapadala ng data mula sa peripheral patungo sa central
  • MTU BLE 4.0 ay naglilimita ng packet sa 23 bytes, BLE 5.0+ — hanggang 251 bytes, ang data na mas malaki sa MTU ay nangangailangan ng fragmentation
  • Async/await Swift sa pamamagitan ng CheckedContinuation ay pinapasimple ang BLE code, pinapalitan ang nested na mga delegado ng linear na mga tawag

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din