CBPeripheral: apa itu, metode dan manajemen BLE-periferal di iOS

Penulis: IT Sectr Diterbitkan: 2026-07-16 Waktu membaca: 10 mnt

CBPeripheral — kelas dari framework Core Bluetooth yang mewakili perangkat BLE jarak jauh di iOS. Setiap objek CBPeripheral mengenkapsulasi UUID, nama, RSSI, dan hierarki layanan GATT dari perangkat BLE yang terhubung. Pengembang berinteraksi dengan periferal secara eksklusif melalui CBPeripheral: discovery layanan (discoverServices:), membaca karakteristik (readValueForCharacteristic:), menulis data (writeValue:forCharacteristic:type:) dan berlangganan notifikasi (setNotifyValue:forCharacteristic:). Menurut Apple Developer, 2026, CBPeripheral — objek pusat untuk semua operasi dengan periferal BLE, dikembalikan oleh CBCentralManager saat mendeteksi atau menghubungkan perangkat.

Poin Utama

  • CBPeripheral — kelas Core Bluetooth untuk bekerja dengan perangkat BLE jarak jauh di iOS
  • Hierarki GATT — Peripheral berisi layanan (CBService), layanan berisi karakteristik (CBCharacteristic), karakteristik berisi deskriptor (CBDescriptor)
  • Discovery — discoverServices: dan discoverCharacteristics:forService: untuk mendapatkan struktur GATT perangkat
  • Membaca dan menulis — readValueForCharacteristic: dan writeValue:forCharacteristic:type: dengan konfirmasi (withResponse) atau tanpa (withoutResponse)
  • Notifikasi — setNotifyValue:forCharacteristic: mengaktifkan langganan perubahan karakteristik perangkat BLE

Apa itu CBPeripheral: esensi dan tujuan

CBPeripheral — adalah objek yang mewakili perangkat BLE jarak jauh dalam aplikasi iOS. Tidak seperti CBCentralManager yang mengelola adaptor Bluetooth lokal iPhone, CBPeripheral memodelkan perangkat periferal eksternal: sensor, pelacak kebugaran, beacon, perangkat medis. Setiap instance CBPeripheral berisi pengidentifikasi unik (UUID) yang dipertahankan antar sesi koneksi — Apple mengaitkan UUID dengan perangkat tertentu melalui Bonding sistem.

CBPeripheral tidak dibuat langsung melalui init. Framework Core Bluetooth mengembalikan objek CBPeripheral dalam dua skenario: saat mendeteksi perangkat melalui scanForPeripheralsWithServices: (delegat didDiscoverPeripheral) dan saat menghubungkan ke perangkat yang sebelumnya dikenal melalui retrievePeripheralsWithIdentifiers:. Setelah menerima objek, pengembang memanggil connectPeripheral: pada CBCentralManager, setelah itu CBPeripheral tersedia untuk operasi GATT.

Siklus hidup CBPeripheral mencakup enam status: disconnected (awal), connecting (setelah pemanggilan connect), connected (setelah didConnectPeripheral), discovering (selama pemanggilan discoverServices), discovered (setelah menerima layanan) dan disconnecting (setelah cancelPeripheralConnection). Setiap status dilacak melalui delegat CBPeripheralDelegate — protokol wajib untuk setiap aplikasi BLE di iOS.

CBPeripheral dan hierarki GATT: layanan, karakteristik, deskriptor

CBPeripheral menyimpan struktur hierarkis GATT yang terdiri dari tiga tingkat. Tingkat akar — array CBService (layanan), setiap layanan berisi array CBCharacteristic (karakteristik), setiap karakteristik berisi array CBDescriptor (deskriptor). Model ini sepenuhnya sesuai dengan spesifikasi Bluetooth GATT: layanan — fungsi perangkat (misalnya, „Heart Rate Service“), karakteristik — nilai konkret (denyut nadi 72 bpm), deskriptor — metadata karakteristik (satuan ukuran, konfigurasi notifikasi).

TingkatKelas Core BluetoothDeskripsi
LayananCBServiceGrup logis karakteristik terkait, diidentifikasi oleh UUID (16-bit, 32-bit atau 128-bit)
KarakteristikCBCharacteristicNilai data konkret, mendukung pembacaan, penulisan, notifikasi
DeskriptorCBDescriptorMetadata karakteristik: konfigurasi klien CCCD, User Description, Presentation Format

Layanan BLE standar terdaftar di Bluetooth SIG: Heart Rate Service (UUID 180D), Battery Service (180F), Device Information (180A), Blood Pressure (1810). Untuk layanan kustom digunakan UUID 128-bit (misalnya, E20A39F4-73F5-4BC4-A12F-17D1AD07A961). iOS secara otomatis mengenali UUID standar dan menampilkan nama yang dapat dibaca manusia; UUID kustom ditampilkan dalam format hex.

Setelah koneksi, hierarki CBPeripheral kosong — layanan dan karakteristik belum dimuat. Pengembang harus memanggil discoverServices: untuk mendapatkan layanan dan kemudian untuk setiap layanan memanggil discoverCharacteristics:forService:. Jika layanan berisi layanan yang disertakan (includedServices), tambahan discoverIncludedServices:forService: dipanggil. Hanya setelah penyelesaian discovery hierarki, CBPeripheral terisi dan tersedia untuk pembacaan dan penulisan.

Discovery layanan dan karakteristik: metode dan delegat

Discovery (deteksi) struktur GATT CBPeripheral — langkah wajib sebelum operasi pembacaan atau penulisan apa pun. Metode discoverServices: memulai pencarian asinkron semua layanan perangkat. Jika nil diteruskan, semua layanan terdeteksi; jika array CBUUID diteruskan — hanya layanan dengan UUID yang ditentukan (optimalisasi waktu). Hasilnya tiba di delegat peripheral:didDiscoverServices: — objek CBPeripheral mengisi properti services dengan array CBService.

Setelah menerima layanan, untuk setiap CBService harus dipanggil discoverCharacteristics:forService:. Demikian pula, nil — semua karakteristik, array CBUUID — hanya yang ditentukan. Hasil: peripheral:didDiscoverCharacteristicsForService:error:. Pada tahap ini, CBCharacteristic mendapatkan properti (properties: .read, .write, .notify, .indicate) yang menentukan operasi yang diizinkan.

swift
import CoreBluetooth

extension BLEViewController: CBPeripheralDelegate {

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

        for service in services {
            // Minta karakteristik untuk setiap layanan
            peripheral.discoverCharacteristics(nil, for: service)
        }
    }

    // 2. Discovery karakteristik
    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. Baca nilai
    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)")
    }
}

Dalam contoh, tiga metode deteksi wajib dari CBPeripheralDelegate diimplementasikan. didDiscoverServices mengulangi semua layanan yang ditemukan dan meminta karakteristik. didDiscoverCharacteristicsForService memeriksa properti setiap karakteristik: untuk .read memanggil readValue, untuk .notify — setNotifyValue(true). Metode didUpdateValueForCharacteristic menerima nilai saat ini dalam format Data.

Membaca dan menulis karakteristik: withResponse dan withoutResponse

Membaca nilai CBCharacteristic dilakukan dengan metode readValueForCharacteristic:. Hasilnya tiba secara asinkron di peripheral:didUpdateValueForCharacteristic:error:. Penting: perangkat mungkin memiliki nilai yang di-cache (characteristic.value tersedia segera setelah discovery), tetapi untuk mendapatkan nilai saat ini, pemanggilan readValue wajib dilakukan. iOS dapat menyimpan cache nilai untuk efisiensi energi — readValue menyegarkan cache.

Menulis nilai dilakukan dengan metode writeValue:forCharacteristic:type:. Parameter type menentukan jenis penulisan: .withResponse (CBCharacteristicWriteWithResponse) — perangkat mengonfirmasi penulisan melalui didWriteValueForCharacteristic; .withoutResponse (CBCharacteristicWriteWithoutResponse) — penulisan tanpa konfirmasi, kecepatan maksimum, tetapi tanpa jaminan pengiriman. Spesifikasi BLE membatasi MTU (Maximum Transmission Unit): hingga 23 byte untuk BLE 4.0, hingga 251 byte untuk BLE 5.0+. Untuk data lebih besar dari MTU, fragmentasi pada tingkat aplikasi diperlukan.

swift
// Membaca dan menulis karakteristik CBPeripheral
class BLEService {

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

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

    // Baca dengan konfirmasi
    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)
    }

    // Tulis dengan konfirmasi (withResponse)
    func writeWithResponse(data: Data) {
        guard let characteristic = findCharacteristic() else { return }
        peripheral.writeValue(data, for: characteristic,
                             type: .withResponse)
    }

    // Tulis tanpa konfirmasi (withoutResponse)
    // Throughput maksimum, tanpa jaminan pengiriman
    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 })
    }
}

Pemilihan jenis penulisan withResponse atau withoutResponse tergantung pada persyaratan keandalan. Untuk perintah (nyalakan lampu, buka kunci) gunakan withResponse — jaminan pengiriman sangat penting. Untuk data streaming (denyut nadi, suhu) gunakan withoutResponse — kehilangan satu paket tidak signifikan. Perangkat BLE mungkin hanya mendukung satu jenis penulisan — periksa properti characteristic.properties.contains(.write) dan .writeWithoutResponse.

Berlangganan notifikasi BLE melalui setNotifyValue

Notifikasi (notifications) — mekanisme BLE di mana perangkat periferal mengirimkan nilai karakteristik ke perangkat pusat secara asinkron, tanpa polling konstan dari pihak pusat. CBPeripheral mengaktifkan langganan melalui metode setNotifyValue:forCharacteristic:. Setelah aktivasi langganan, iOS secara otomatis menulis CCCD (Client Characteristic Configuration Descriptor) pada periferal, dan perangkat mulai mengirim pembaruan pada setiap perubahan nilai.

Berbeda dengan indikasi (indicate), notifikasi tidak memerlukan konfirmasi dari pusat — paket dikirim dan dilupakan. Ini memberikan bandwidth maksimum, tetapi kemungkinan kehilangan paket. Indikasi memerlukan konfirmasi pada tingkat protokol (L2CAP) — lebih andal tetapi lebih lambat. CBCharacteristic melalui properti properties secara tepat menunjukkan mode mana yang didukung: .notify, .indicate atau keduanya.

Saat pemutusan CBPeripheral (disconnect, keluar dari jangkauan), semua langganan aktif secara otomatis diatur ulang. Saat menghubungkan kembali, setNotifyValue:true harus dipanggil lagi untuk setiap karakteristik. iOS juga kehilangan langganan saat aplikasi keluar dari foreground (jika mode background tidak diaktifkan) — untuk kerja latar belakang, diperlukan mengaktifkan capability „Uses Bluetooth LE accessories“ di Info.plist.

swift
// Manajemen langganan notifikasi CBPeripheral
class NotificationManager: NSObject {

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

    // Langganan notifikasi untuk semua karakteristik .notify
    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)
                }
            }
        }
    }

    // Berhenti berlangganan semua notifikasi
    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 notifikasi
    func peripheral(_ peripheral: CBPeripheral,
                     didUpdateNotificationStateFor characteristic: CBCharacteristic,
                     error: Error?) {
        if characteristic.isNotifying {
            print("Subscription active: \(characteristic.uuid)")
        } else {
            print("Subscription inactive: \(characteristic.uuid)")
        }
    }
}

Manajer langganan NotificationManager mendemonstrasikan cara kerja yang benar dengan notifikasi CBPeripheral. subscribeToAllNotifications mengulangi semua layanan dan karakteristik, mengaktifkan .notify dan .indicate. subscribedCharacteristics melacak langganan aktif untuk berhenti berlangganan yang benar. didUpdateNotificationStateForCharacteristic mengonfirmasi perubahan status langganan yang berhasil melalui properti characteristic.isNotifying.

Contoh lengkap bekerja dengan CBPeripheral di Swift

Siklus kerja lengkap dengan CBPeripheral meliputi: menerima objek dari CBCentralManager, menghubungkan, discovery, membaca/menulis, berlangganan notifikasi, dan memutuskan. Dalam contoh di bawah, kelas BLEConnection diimplementasikan yang mengelola siklus hidup lengkap periferal BLE di Swift menggunakan API async/await modern (iOS 15+).

swift
import CoreBluetooth

// Contoh manajemen CBPeripheral lengkap dengan 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. Hubungkan ke periferal
    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) {
        // Tangani status perangkat Bluetooth
    }

    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
}

Kelas BLEConnection menggunakan Swift Concurrency (async/await) melalui CheckedContinuation — pola modern untuk bekerja dengan API delegat Core Bluetooth. connect(to:) menunggu konfirmasi koneksi melalui didConnectPeripheral, discoverServices() — melalui didDiscoverServices. Pendekatan ini menghilangkan delegat bersarang dan membuat kode BLE linier dan mudah dibaca. Penanganan kesalahan melalui BLEError mencakup semua skenario kegagalan koneksi BLE yang umum.

Pertanyaan yang Sering Diajukan

Bagaimana cara mendapatkan CBPeripheral tanpa pemindaian?

CBPeripheral untuk perangkat yang sebelumnya terhubung dapat diperoleh melalui retrievePeripheralsWithIdentifiers: pada CBCentralManager. Berikan array UUID (NSUUID) dari perangkat yang sebelumnya disimpan — framework akan mengembalikan array CBPeripheral untuk perangkat di database sistem BLE-bonding. Ini hanya berfungsi untuk perangkat yang sebelumnya telah dipasangkan dengan iPhone. Untuk perangkat baru, pemindaian wajib dilakukan.

Mengapa CBPeripheral tidak mendeteksi layanan?

Penyebab utama: perangkat berada di luar jangkauan (RSSI di bawah ambang batas), radio BLE dimatikan (CBCentralManager.state != .poweredOn), delegat CBPeripheralDelegate tidak diatur (peripheral.delegate = self), atau pemanggilan discoverServices dilakukan sebelum koneksi. Periksa status centralManager.state, pastikan delegat diatur sebelum pemanggilan connect dan gunakan retry dengan waktu tunggu 5–10 detik.

Apa yang harus dilakukan jika writeValue tidak merespons?

Penyebab — menggunakan .withResponse pada karakteristik yang hanya mendukung .writeWithoutResponse atau sebaliknya. Periksa characteristic.properties sebelum pemanggilan. Juga mungkin masalah MTU: jika data > 20 byte (BLE 4.0 MTU), negosiasi MTU melalui negotiateMTU atau fragmentasi diperlukan. Gunakan peripheral.maximumWriteValueLength(for: .withResponse) untuk menentukan ukuran paket maksimum.

Bagaimana membedakan CBPeripheral dalam jangkauan dari yang tidak dapat diakses?

CBPeripheral di luar jangkauan tidak langsung terputus — iOS memindahkannya ke status .disconnected melalui waktu tunggu (biasanya 20–30 detik). Untuk pemantauan, gunakan readRSSI pada CBPeripheral — saat tidak tersedia akan mengembalikan kesalahan dengan kode CBError.connectionTimeout. Juga pantau centralManager:didDisconnectPeripheral:error: untuk deteksi tepat waktu pemutusan koneksi.

Bisakah satu CBPeripheral digunakan dari beberapa thread?

Core Bluetooth tidak aman untuk thread — semua pemanggilan CBPeripheral harus dilakukan dari satu antrian (biasanya main queue atau serial queue berurutan yang ditentukan saat inisialisasi CBCentralManager). Pemanggilan bersamaan dari thread yang berbeda menyebabkan race condition dan crash aplikasi. Gunakan DispatchQueue(label: „com.app.ble“) untuk semua operasi BLE dan DispatchQueue.main.async untuk pembaruan UI.

Ringkasan

  • CBPeripheral — kelas Core Bluetooth untuk bekerja dengan perangkat BLE jarak jauh di iOS, dikembalikan oleh CBCentralManager
  • Hierarki GATT terdiri dari layanan (CBService), karakteristik (CBCharacteristic) dan deskriptor (CBDescriptor) dengan UUID 16-bit atau 128-bit
  • Discovery dilakukan secara berurutan: discoverServices: → discoverCharacteristics:forService: dengan pemrosesan melalui delegat
  • Membaca — readValueForCharacteristic:, menulis — writeValue:forCharacteristic:type: (.withResponse atau .withoutResponse)
  • Notifikasi — setNotifyValue:forCharacteristic: mengaktifkan pengiriman data asinkron dari periferal ke pusat
  • MTU BLE 4.0 membatasi paket hingga 23 byte, BLE 5.0+ — hingga 251 byte, data lebih besar dari MTU memerlukan fragmentasi
  • Async/await Swift melalui CheckedContinuation menyederhanakan kode BLE, menggantikan delegat bersarang dengan panggilan linier

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga