CBCentralManager là lớp trung tâm của framework Core Bluetooth trong iOS quản lý việc quét, kết nối và tương tác với các thiết bị ngoại vi BLE. Core Bluetooth (iOS 5+, 2011) cung cấp một lớp trừu tượng cấp cao trên ngăn xếp BLE ở cấp GATT, ẩn chi tiết Link Layer và HCI khỏi nhà phát triển. CBCentralManager thực thi vai trò Central: nó quét sóng qua scanForPeripherals, khởi tạo kết nối qua connect, khám phá dịch vụ qua discoverServices và quản lý truyền dữ liệu. Theo Tài liệu Nhà phát triển Apple (2024), CBCentralManager hỗ trợ tới 7 kết nối đồng thời tới các thiết bị BLE trên các thiết bị có BLE 5.0.
Những Điểm Chính
CBCentralManager là lớp Core Bluetooth chính để thực thi vai trò Central trong kiến trúc BLE trên iOS. Nó quản lý toàn bộ vòng đời kết nối BLE: từ quét các thiết bị đang quảng cáo đến truyền dữ liệu và ngắt kết nối. CBCentralManager hoạt động không đồng bộ qua delegate CBCentralManagerDelegate, thông báo cho ứng dụng về các sự kiện trong ngăn xếp Bluetooth.
Việc khởi tạo CBCentralManager bắt đầu quá trình khôi phục trạng thái: trình quản lý kiểm tra trạng thái Bluetooth trên thiết bị và khôi phục các kết nối trước đó nếu ứng dụng đã bị đóng. Quá trình khởi tạo có thể mất từ 50 đến 500 ms tùy thuộc vào trạng thái Bluetooth. Ứng dụng phải đợi lệnh gọi centralManagerDidUpdateState trước khi bắt đầu bất kỳ thao tác BLE nào.
Kiến trúc Core Bluetooth được xây dựng trên mẫu Delegation: CBCentralManager ủy quyền xử lý sự kiện (khám phá thiết bị, kết nối, lỗi) cho giao thức CBCentralManagerDelegate. Để làm việc với một thiết bị ngoại vi cụ thể, giao thức CBPeripheralDelegate được sử dụng, thông báo về các dịch vụ, đặc tính đã khám phá và dữ liệu nhận được. Mô hình không đồng bộ này đảm bảo giao diện người dùng không bị chặn.
CBCentralManager trải qua nhiều trạng thái xác định xem ngăn xếp BLE có khả dụng hay không. Trạng thái được truyền qua delegate: centralManagerDidUpdateState(_:). Nhà phát triển phải xử lý tất cả các trạng thái — không chỉ poweredOn, mà còn các trường hợp Bluetooth bị tắt hoặc không khả dụng.
| Trạng thái | Giá trị | Hành động của nhà phát triển |
|---|---|---|
| .poweredOn | Bluetooth bật và sẵn sàng | Bắt đầu quét |
| .poweredOff | Bluetooth tắt | Hiển thị cảnh báo cho người dùng |
| .unauthorized | Không có quyền | Yêu cầu quyền trong Cài đặt |
| .unsupported | Thiết bị không hỗ trợ BLE | Ẩn tính năng BLE |
| .unknown | Trạng thái chưa xác định | Đợi bản cập nhật tiếp theo |
| .resetting | Bluetooth đang khởi động lại | Đợi khôi phục |
Trạng thái chưa được ủy quyền ngày càng phổ biến từ iOS 13+. Bắt đầu từ phiên bản này, ứng dụng phải có quyền NSBluetoothAlwaysUsageDescription trong Info.plist. Nếu không có, trình quản lý trung tâm chuyển sang trạng thái .unauthorized và không thể quét. Người dùng có thể thay đổi quyền trong Cài đặt > Quyền riêng tư > Bluetooth bất kỳ lúc nào.
scanForPeripherals(withServices:options:) là phương thức chính để bắt đầu quét. Tham số withServices chấp nhận một mảng UUID dịch vụ để lọc: nếu truyền nil, tất cả thiết bị sẽ được khám phá, làm tăng đáng kể mức tiêu thụ điện năng. Khuyến nghị luôn lọc theo UUID dịch vụ mà ứng dụng cần. Các tùy chọn quét bao gồm CBCentralManagerScanOptionAllowDuplicatesKey (thông báo lặp lại về cùng một thiết bị).
import CoreBluetooth
class BLEController: NSObject,
CBCentralManagerDelegate {
private var centralManager: CBCentralManager!
override init() {
super.init()
centralManager =
CBCentralManager(
delegate: self,
queue: nil
)
}
func startScanning() {
let serviceUUID =
CBUUID("180F") // Dịch vụ Pin
centralManager.scanForPeripherals(
withServices: [serviceUUID],
options: [
CBCentralManagerScanOptionAllowDuplicatesKey: false
]
)
}
}
Khi một thiết bị được khám phá, centralManager(_:didDiscover:advertisementData:rssi:) được gọi. Tham số advertisementData chứa từ điển đầy đủ dữ liệu gói quảng cáo, bao gồm tên thiết bị (CBAdvertisementDataLocalNameKey), UUID dịch vụ (CBAdvertisementDataServiceUUIDsKey) và dữ liệu nhà sản xuất (CBAdvertisementDataManufacturerDataKey). RSSI là mức tín hiệu tính bằng dBm tại thời điểm khám phá.
connect(_:options:) là phương thức để thiết lập kết nối BLE với một thiết bị ngoại vi đã được khám phá. Sau khi gọi connect, iOS cố gắng kết nối tới thiết bị. Kết nối thành công được xác nhận qua centralManager(_:didConnect:), lỗi — qua centralManager(_:didFailToConnect:error:). Các tùy chọn kết nối bao gồm CBConnectPeripheralOptionNotifyOnConnectionKey, CBConnectPeripheralOptionNotifyOnDisconnectionKey và CBConnectPeripheralOptionNotifyOnNotificationKey cho thông báo nền.
// Kết nối tới thiết bị BLE
func connectToPeripheral(
_ peripheral: CBPeripheral
) {
centralManager.connect(peripheral, options: nil)
// Đặt delegate cho thiết bị ngoại vi
peripheral.delegate = self
}
// Delegate: kết nối thành công
func centralManager(
_ central: CBCentralManager,
didConnect peripheral: CBPeripheral
) {
print("Đã kết nối tới " +
"\(peripheral.name ?? "unknown")")
// Bắt đầu khám phá dịch vụ
peripheral.discoverServices(nil)
}
// Delegate: lỗi kết nối
func centralManager(
_ central: CBCentralManager,
didFailToConnect peripheral: CBPeripheral,
error: Error?
) {
print("Connection failed:
\(error?.localizedDescription ?? "")")
}
Thời gian chờ kết nối trên iOS là 30 giây. Nếu thiết bị không phản hồi yêu cầu kết nối trong thời gian này, didFailToConnect được gọi. Thời gian chờ bị ảnh hưởng bởi: khoảng cách tới thiết bị, nhiễu và liệu thiết bị có đang quảng cáo hay không. Trước khi kết nối, hãy đảm bảo thiết bị ở chế độ quảng cáo có thể kết nối (ADV_IND, không phải ADV_NONCONN_IND).
Sau khi kết nối, bạn phải khám phá các dịch vụ (discoverServices) và đặc tính (discoverCharacteristics) của thiết bị ngoại vi. Đây là bước bắt buộc trước khi đọc hoặc ghi dữ liệu. Quá trình này không đồng bộ: discoverServices trả về kết quả qua peripheral(_:didDiscoverServices:), và discoverCharacteristics — qua peripheral(_:didDiscoverCharacteristicsFor:error:).
Khuyến nghị truyền một mảng UUID liên quan tới discoverServices thay vì nil. Lọc giúp tăng tốc khám phá và tiết kiệm năng lượng. Nếu không tìm thấy dịch vụ, iOS sẽ báo cáo một mảng trống. Sau khi khám phá các đặc tính, bạn có thể đọc giá trị của chúng (readValue), đăng ký nhận thông báo (setNotifyValue) hoặc ghi dữ liệu (writeValue).
Một sắc thái quan trọng: MTU được thương lượng tự động sau khi kết nối. Để lấy MTU hiện tại, sử dụng peripheral.maximumWriteValueLength(for: .withResponse) hoặc .withoutResponse. Trên iOS, MTU tối đa là 512 byte cho các thiết bị BLE 5.0. Nếu bạn cần truyền dữ liệu lớn hơn MTU, hãy triển khai phân mảnh ở cấp ứng dụng.
Quét nền thiết bị BLE trên iOS yêu cầu cấu hình đặc biệt. Core Bluetooth hỗ trợ thực thi nền, nhưng với các giới hạn đáng kể. Để hoạt động trong nền, bạn cần: bật bluetooth-central trong Background Modes trong Capabilities của dự án, khởi tạo CBCentralManager với tùy chọn CBCentralManagerOptionRestoreIdentifierKey để khôi phục trạng thái và xử lý các sự kiện của trình quản lý trung tâm khi chuyển sang nền.
Giới hạn BLE nền trên iOS: scanForPeripherals không có lọc UUID không hoạt động trong nền. Ứng dụng phải chỉ định UUID dịch vụ cụ thể để quét. iOS có thể trì hoãn việc phân phối sự kiện BLE vô thời hạn. Core Bluetooth tự động tiếp tục quét khi phát hiện thiết bị phù hợp, ngay cả khi ứng dụng ở chế độ nền. Thời gian chờ quét nền: iOS có thể dừng quét sau 10–30 phút để tiết kiệm năng lượng.
Khôi phục trạng thái là cơ chế Core Bluetooth cho phép khôi phục kết nối BLE sau khi khởi động lại ứng dụng hoặc khởi động lại iOS. Để sử dụng: chỉ định CBCentralManagerOptionRestoreIdentifierKey khi khởi tạo, triển khai centralManager(_:willRestoreState:) trong delegate và khôi phục danh sách các thiết bị ngoại vi đã kết nối từ từ điển được truyền vào. Khôi phục trạng thái là chức năng quan trọng cho các ứng dụng BLE hoạt động trong nền, như máy theo dõi sức khỏe hoặc thiết bị y tế.
CBCentralManager tạo ra lỗi trong một số kịch bản: kết nối thất bại (didFailToConnect), kết nối bị ngắt (didDisconnectPeripheral), đặc tính không khả dụng để đọc/ghi (lỗi didWriteValue). Tất cả lỗi Core Bluetooth được trả về qua đối tượng Error với miền CBErrorDomain. Các mã phổ biến nhất: CBErrorConnectionTimeout (0x04), CBErrorPeripheralDisconnected (0x07), CBErrorOperationNotSupported (0x0A).
Chiến lược khôi phục kết nối: khi nhận được didDisconnectPeripheral, hãy kiểm tra mã lỗi. Nếu lỗi là CBErrorConnectionTimeout hoặc CBErrorPeripheralDisconnected — lên lịch tự động kết nối lại sau 1–5 giây. Nếu lỗi là CBErrorOperationNotSupported — ghi nhật ký và không thử lại thao tác. Đối với các kết nối quan trọng (thiết bị y tế), sử dụng backoff theo cấp số nhân với khoảng thời gian tối đa 60 giây.
// Xử lý ngắt kết nối với tự động kết nối lại
func centralManager(
_ central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: Error?
) {
guard let error = error else {
return // Ngắt kết nối dự kiến
}
print("Disconnected: \(error.localizedDescription)")
// Tự động kết nối lại
if shouldAutoReconnect {
DispatchQueue.main.asyncAfter(
deadline: .now() + reconnectDelay
) {
central.connect(peripheral)
}
}
}
Khi phát triển ứng dụng BLE mạnh mẽ trên iOS, hãy lưu ý: Core Bluetooth không đảm bảo phân phối tất cả các gói khi tín hiệu yếu. Để truyền đáng tin cậy, hãy sử dụng writeType .withResponse (ghi có xác nhận) và đăng ký nhận thông báo (setNotifyValue) để nhận dữ liệu từ thiết bị ngoại vi. Duy trì nhật ký lỗi để chẩn đoán sự cố kết nối trong sản xuất.
Câu Hỏi Thường Gặp
Kiểm tra trạng thái trình quản lý qua centralManagerDidUpdateState. Đảm bảo quyền NSBluetoothAlwaysUsageDescription có trong Info.plist, Bluetooth được bật trên thiết bị và thiết bị ngoại vi đang quảng cáo với đúng loại (quảng cáo có thể kết nối, không phải không thể kết nối).
Trên các thiết bị có BLE 5.0 (iPhone 8 trở lên) — tới 7 kết nối đồng thời. Trên các thiết bị cũ hơn — tới 3–5. Số lượng thiết bị được quét không giới hạn, nhưng các kết nối đang hoạt động có giới hạn cứng do Bộ điều khiển Bluetooth thiết lập.
Khuyến nghị quét với lọc UUID và dừng quét khi tìm thấy thiết bị. Quét liên tục làm hao pin: 1 giờ quét không ngắt quãng tiêu thụ ~10–15% pin iPhone. Sử dụng bộ đếm thời gian và điều kiện để dừng quét.
CBCentralManager dùng để quét và kết nối với thiết bị BLE bên ngoài (vai trò Central). CBPeripheralManager để thiết bị iOS của bạn hoạt động như một thiết bị ngoại vi BLE (quảng cáo dịch vụ). Một phiên bản chỉ có thể ở một vai trò duy nhất.
Triển khai centralManager(_:didDisconnectPeripheral:error:). Nếu lỗi không nil — lên lịch tự động kết nối lại với backoff theo cấp số nhân (1 giây → 2 giây → 4 giây → 8 giây → tối đa 60 giây). Nếu lỗi nil — thiết bị đã ngắt kết nối bình thường (ví dụ: người dùng nhấn nút trên thiết bị).
Tổng Kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm