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 — 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 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).
| Tingkat | Kelas Core Bluetooth | Deskripsi |
|---|---|---|
| Layanan | CBService | Grup logis karakteristik terkait, diidentifikasi oleh UUID (16-bit, 32-bit atau 128-bit) |
| Karakteristik | CBCharacteristic | Nilai data konkret, mendukung pembacaan, penulisan, notifikasi |
| Deskriptor | CBDescriptor | Metadata 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 (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.
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 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.
// 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.
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.
// 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.
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+).
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
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.
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.
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.
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.
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
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.
Baca juga