CBCentralManager — είναι η κεντρική κλάση του πλαισίου Core Bluetooth στο iOS που διαχειρίζεται τη σάρωση, τη σύνδεση και την αλληλεπίδραση με BLE περιφερειακές συσκευές. Το Core Bluetooth (iOS 5+, 2011) παρέχει μια αφαίρεση υψηλού επιπέδου πάνω από τη στοίβα BLE σε επίπεδο GATT, κρύβοντας από τον προγραμματιστή τις λεπτομέρειες του Link Layer και του HCI. Το CBCentralManager εκτελεί τον ρόλο Central: σαρώνει τον αιθέρα μέσω scanForPeripherals, ξεκινά σύνδεση μέσω connect, ανακαλύπτει υπηρεσίες μέσω discoverServices και διαχειρίζεται τη μεταφορά δεδομένων. Σύμφωνα με το Apple Developer Documentation (2024), το CBCentralManager υποστηρίζει έως 7 ταυτόχρονες συνδέσεις BLE σε συσκευές με BLE 5.0.
Κύρια σημεία
CBCentralManager — είναι η κύρια κλάση του Core Bluetooth για την υλοποίηση του ρόλου Central στην αρχιτεκτονική BLE στο iOS. Διαχειρίζεται ολόκληρο τον κύκλο ζωής μιας σύνδεσης BLE: από τη σάρωση συσκευών που διαφημίζονται έως τη μεταφορά δεδομένων και την αποσύνδεση. Το CBCentralManager λειτουργεί ασύγχρονα μέσω του αντιπροσώπου CBCentralManagerDelegate, ενημερώνοντας την εφαρμογή για συμβάντα στη στοίβα Bluetooth.
Η αρχικοποίηση του CBCentralManager ξεκινά τη διαδικασία state restoration: ο διαχειριστής ελέγχει την κατάσταση Bluetooth στη συσκευή και επαναφέρει προηγούμενες συνδέσεις εάν η εφαρμογή ήταν κλειστή. Η διαδικασία αρχικοποίησης μπορεί να διαρκέσει από 50 έως 500 ms ανάλογα με την κατάσταση Bluetooth. Η εφαρμογή πρέπει να περιμένει την κλήση centralManagerDidUpdateState πριν ξεκινήσει οποιεσδήποτε λειτουργίες BLE.
Η αρχιτεκτονική του Core Bluetooth βασίζεται στο μοτίβο Delegation: το CBCentralManager αναθέτει την επεξεργασία συμβάντων (ανακάλυψη συσκευών, σύνδεση, σφάλματα) στο πρωτόκολλο CBCentralManagerDelegate. Για εργασία με ένα συγκεκριμένο Peripheral χρησιμοποιείται το πρωτόκολλο CBPeripheralDelegate, το οποίο ενημερώνει για την ανακάλυψη υπηρεσιών, χαρακτηριστικών και λήψη δεδομένων. Αυτό το ασύγχρονο μοντέλο εξασφαλίζει τη μη αποκλειστική λειτουργία του UI.
Το CBCentralManager περνά από διάφορες καταστάσεις που καθορίζουν εάν η στοίβα BLE είναι διαθέσιμη για εργασία. Η κατάσταση μεταδίδεται μέσω του αντιπροσώπου: centralManagerDidUpdateState(_:). Ο προγραμματιστής πρέπει να χειρίζεται όλες τις καταστάσεις — όχι μόνο το poweredOn, αλλά και τις περιπτώσεις όταν το Bluetooth είναι απενεργοποιημένο ή μη διαθέσιμο.
| Κατάσταση | Σημασία | Ενέργεια προγραμματιστή |
|---|---|---|
| .poweredOn | Το Bluetooth είναι ενεργό και έτοιμο | Έναρξη σάρωσης |
| .poweredOff | Το Bluetooth είναι απενεργοποιημένο | Εμφάνιση ειδοποίησης στον χρήστη |
| .unauthorized | Χωρίς άδεια | Αίτηση άδειας στις Ρυθμίσεις |
| .unsupported | Η συσκευή δεν υποστηρίζει BLE | Απόκρυψη λειτουργιών BLE |
| .unknown | Η κατάσταση δεν έχει οριστεί | Αναμονή για την επόμενη ενημέρωση |
| .resetting | Το Bluetooth επανεκκινείται | Αναμονή για αποκατάσταση |
Unauthorized state γίνεται όλο και πιο συχνή από iOS 13+. Από αυτήν την έκδοση, η εφαρμογή πρέπει να έχει την άδεια NSBluetoothAlwaysUsageDescription στο Info.plist. Χωρίς αυτήν, ο κεντρικός διαχειριστής μεταβαίνει σε κατάσταση .unauthorized και η σάρωση είναι αδύνατη. Ο χρήστης μπορεί να αλλάξει την άδεια ανά πάσα στιγμή στις Ρυθμίσεις > Απόρρητο > Bluetooth.
scanForPeripherals(withServices:options:) — η κύρια μέθοδος για έναρξη σάρωσης. Η παράμετρος withServices δέχεται έναν πίνακα UUID υπηρεσιών για φιλτράρισμα: εάν σταλεί nil, θα ανακαλυφθούν όλες οι συσκευές, αυξάνοντας σημαντικά την κατανάλωση ενέργειας. Συνιστάται να φιλτράρετε πάντα βάσει UUID των υπηρεσιών που χρειάζεται η εφαρμογή. Οι επιλογές σάρωσης περιλαμβάνουν το CBCentralManagerScanOptionAllowDuplicatesKey (επανειλημμένες ειδοποιήσεις για την ίδια συσκευή).
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") // Υπηρεσία Μπαταρίας
centralManager.scanForPeripherals(
withServices: [serviceUUID],
options: [
CBCentralManagerScanOptionAllowDuplicatesKey: false
]
)
}
}
Κατά την ανακάλυψη μιας συσκευής, καλείται η centralManager(_:didDiscover:advertisementData:rssi:). Η παράμετρος advertisementData περιέχει ένα πλήρες λεξικό δεδομένων του πακέτου διαφήμισης, συμπεριλαμβανομένου του ονόματος συσκευής (CBAdvertisementDataLocalNameKey), των UUID υπηρεσιών (CBAdvertisementDataServiceUUIDsKey) και των δεδομένων κατασκευαστή (CBAdvertisementDataManufacturerDataKey). RSSI — επίπεδο σήματος σε dBm, διαθέσιμο τη στιγμή της ανακάλυψης.
connect(_:options:) — μέθοδος για τη δημιουργία σύνδεσης BLE με ένα ανακαλυφθέν Peripheral. Μετά την κλήση connect, το iOS προσπαθεί να συνδεθεί στη συσκευή. Η επιτυχής σύνδεση επιβεβαιώνεται από την κλήση centralManager(_:didConnect:), το σφάλμα από την centralManager(_:didFailToConnect:error:). Οι επιλογές σύνδεσης περιλαμβάνουν τα CBConnectPeripheralOptionNotifyOnConnectionKey, CBConnectPeripheralOptionNotifyOnDisconnectionKey και CBConnectPeripheralOptionNotifyOnNotificationKey για ειδοποιήσεις παρασκηνίου.
// Σύνδεση σε συσκευή BLE
func connectToPeripheral(
_ peripheral: CBPeripheral
) {
centralManager.connect(peripheral, options: nil)
// Ορισμός αντιπροσώπου για Peripheral
peripheral.delegate = self
}
// Αντιπρόσωπος: επιτυχής σύνδεση
func centralManager(
_ central: CBCentralManager,
didConnect peripheral: CBPeripheral
) {
print("Συνδεδεμένο σε " +
"\(peripheral.name ?? "unknown")")
// Έναρξη ανακάλυψης υπηρεσιών
peripheral.discoverServices(nil)
}
// Αντιπρόσωπος: σφάλμα σύνδεσης
func centralManager(
_ central: CBCentralManager,
didFailToConnect peripheral: CBPeripheral,
error: Error?
) {
print("Connection failed:
\(error?.localizedDescription ?? "")")
}
Χρονικό όριο σύνδεσης στο iOS είναι 30 δευτερόλεπτα. Εάν η συσκευή δεν απαντήσει στο αίτημα σύνδεσης εντός αυτού του χρόνου, καλείται η didFailToConnect. Παράγοντες που επηρεάζουν το χρονικό όριο: απόσταση από τη συσκευή, παρεμβολές, εάν η συσκευή διαφημίζεται αυτήν τη στιγμή. Πριν τη σύνδεση, βεβαιωθείτε ότι η συσκευή βρίσκεται σε λειτουργία connectable advertising (ADV_IND, όχι ADV_NONCONN_IND).
Μετά τη σύνδεση πρέπει να ανακαλυφθούν οι υπηρεσίες (discoverServices) και τα χαρακτηριστικά (discoverCharacteristics) του Peripheral. Αυτό είναι υποχρεωτικό βήμα πριν από την ανάγνωση ή εγγραφή δεδομένων. Η διαδικασία είναι ασύγχρονη: η discoverServices επιστρέφει αποτέλεσμα μέσω peripheral(_:didDiscoverServices:), και η discoverCharacteristics μέσω peripheral(_:didDiscoverCharacteristicsFor:error:).
Συνιστάται να στέλνετε στη discoverServices έναν πίνακα ενδιαφερόντων UUID, όχι nil. Το φιλτράρισμα επιταχύνει την ανακάλυψη και εξοικονομεί ενέργεια. Εάν η υπηρεσία δεν βρεθεί, το iOS θα αναφέρει έναν κενό πίνακα. Μετά την ανακάλυψη χαρακτηριστικών, μπορείτε να διαβάσετε τις τιμές τους (readValue), να εγγραφείτε σε ειδοποιήσεις (setNotifyValue) ή να γράψετε δεδομένα (writeValue).
Μια σημαντική λεπτομέρεια: Το MTU συμφωνείται αυτόματα μετά τη σύνδεση. Για να λάβετε το τρέχον MTU, χρησιμοποιήστε το peripheral.maximumWriteValueLength(for: .withResponse) ή .withoutResponse. Στο iOS, το μέγιστο MTU είναι 512 byte για συσκευές BLE 5.0. Εάν χρειάζεται να μεταφέρετε δεδομένα μεγαλύτερα από το MTU, εφαρμόστε κατακερματισμό σε επίπεδο εφαρμογής.
Σάρωση παρασκηνίου συσκευών BLE στο iOS απαιτεί ειδική διαμόρφωση. Το Core Bluetooth υποστηρίζει εκτέλεση στο παρασκήνιο, αλλά με σημαντικούς περιορισμούς. Για λειτουργία στο παρασκήνιο απαιτείται: ενεργοποίηση του bluetooth-central στα Background Modes στις Capabilities του έργου, αρχικοποίηση του CBCentralManager με την επιλογή CBCentralManagerOptionRestoreIdentifierKey για state restoration και χειρισμός των συμβάντων του κεντρικού διαχειριστή κατά τη μετάβαση στο παρασκήνιο.
BLE περιορισμοί στο παρασκήνιο στο iOS: η scanForPeripherals χωρίς φιλτράρισμα UUID δεν λειτουργεί στο παρασκήνιο. Η εφαρμογή πρέπει να καθορίζει συγκεκριμένα UUID υπηρεσιών για σάρωση. Το iOS μπορεί να καθυστερήσει την παράδοση BLE συμβάντων για αόριστο χρονικό διάστημα. Το Core Bluetooth συνεχίζει αυτόματα τη σάρωση κατά την ανακάλυψη μιας ταιριαστής συσκευής, ακόμα κι αν η εφαρμογή είναι στο παρασκήνιο. Χρονικό όριο σάρωσης παρασκηνίου: το iOS μπορεί να σταματήσει τη σάρωση μετά από 10–30 λεπτά για εξοικονόμηση ενέργειας.
State Restoration — ο μηχανισμός του Core Bluetooth που επιτρέπει την αποκατάσταση συνδέσεων BLE μετά από επανεκκίνηση της εφαρμογής ή επανεκκίνηση iOS. Για χρήση: καθορίστε το CBCentralManagerOptionRestoreIdentifierKey κατά την αρχικοποίηση, εφαρμόστε το centralManager(_:willRestoreState:) στον αντιπρόσωπο και επαναφέρετε τη λίστα των συνδεδεμένων Peripheral από το μεταδιδόμενο λεξικό. Το State Restoration είναι κρίσιμη λειτουργία για εφαρμογές BLE που λειτουργούν στο παρασκήνιο, όπως ιχνηλάτες γυμναστικής ή ιατρικές συσκευές.
Το CBCentralManager δημιουργεί σφάλματα σε αρκετά σενάρια: αποτυχία σύνδεσης (didFailToConnect), διακοπή σύνδεσης (didDisconnectPeripheral), χαρακτηριστικό μη διαθέσιμο για ανάγνωση/εγγραφή (didWriteValue error). Όλα τα σφάλματα Core Bluetooth επιστρέφονται μέσω του αντικειμένου Error με τομέα CBErrorDomain. Οι πιο συνηθισμένοι κωδικοί: CBErrorConnectionTimeout (0x04), CBErrorPeripheralDisconnected (0x07), CBErrorOperationNotSupported (0x0A).
Στρατηγική αποκατάστασης σύνδεσης: κατά τη λήψη didDisconnectPeripheral ελέγξτε τον κωδικό σφάλματος. Εάν το σφάλμα είναι CBErrorConnectionTimeout ή CBErrorPeripheralDisconnected — προγραμματίστε αυτόματη επανασύνδεση μετά από 1–5 δευτερόλεπτα. Εάν το σφάλμα είναι CBErrorOperationNotSupported — καταγράψτε και μην επιχειρήσετε να επαναλάβετε τη λειτουργία. Για κρίσιμες συνδέσεις (ιατρικές συσκευές) χρησιμοποιήστε exponential backoff με μέγιστο διάστημα 60 δευτερολέπτων.
// Χειρισμός αποσύνδεσης με αυτόματη επανασύνδεση
func centralManager(
_ central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: Error?
) {
guard let error = error else {
return // Αναμενόμενη αποσύνδεση
}
print("Disconnected: \(error.localizedDescription)")
// Αυτόματη επανασύνδεση
if shouldAutoReconnect {
DispatchQueue.main.asyncAfter(
deadline: .now() + reconnectDelay
) {
central.connect(peripheral)
}
}
}
Κατά την ανάπτυξη μιας αξιόπιστης εφαρμογής BLE στο iOS, λάβετε υπόψη: το Core Bluetooth δεν εγγυάται την παράδοση όλων των πακέτων όταν το σήμα είναι ασθενές. Για αξιόπιστη μεταφορά, χρησιμοποιήστε writeType .withResponse (επιβεβαιωμένη εγγραφή) και εγγραφείτε σε ειδοποιήσεις (setNotifyValue) για λήψη δεδομένων από το Peripheral. Διατηρήστε ένα αρχείο σφαλμάτων για διάγνωση προβλημάτων σύνδεσης στην παραγωγή.
Συχνές Ερωτήσεις
Ελέγξτε την κατάσταση του διαχειριστή μέσω centralManagerDidUpdateState. Βεβαιωθείτε ότι η άδεια NSBluetoothAlwaysUsageDescription υπάρχει στο Info.plist, το Bluetooth είναι ενεργοποιημένο στη συσκευή και η περιφερειακή συσκευή διαφημίζεται με τον σωστό τύπο (connectable advertising, όχι non-connectable).
Σε συσκευές με BLE 5.0 (iPhone 8 και νεότερες) — έως 7 ταυτόχρονες συνδέσεις. Σε παλαιότερες συσκευές — έως 3–5. Ο αριθμός των σαρωμένων συσκευών είναι απεριόριστος, αλλά οι ενεργές συνδέσεις έχουν αυστηρό όριο που ορίζεται από τον Bluetooth Controller.
Συνιστάται σάρωση με φίλτρο UUID και απενεργοποίηση της σάρωσης όταν η συσκευή βρεθεί. Η συνεχής σάρωση καταναλώνει μπαταρία: 1 ώρα συνεχούς σάρωσης καταναλώνει ~10–15% της μπαταρίας του iPhone. Χρησιμοποιήστε χρονοδιακόπτες και συνθήκες για διακοπή της σάρωσης.
CBCentralManager — για σάρωση και σύνδεση σε εξωτερικές συσκευές BLE (ρόλος Central). CBPeripheralManager — για να λειτουργεί η συσκευή iOS σας ως BLE περιφερειακό (να διαφημίζει υπηρεσίες). Ένα στιγμιότυπο μπορεί να είναι μόνο σε έναν ρόλο.
Εφαρμόστε το centralManager(_:didDisconnectPeripheral:error:). Εάν το σφάλμα δεν είναι nil — προγραμματίστε αυτόματη επανασύνδεση με exponential backoff (1 δ → 2 δ → 4 δ → 8 δ → μέγ. 60 δ). Εάν το σφάλμα είναι nil — η συσκευή αποσυνδέθηκε κανονικά (π.χ. ο χρήστης πάτησε ένα κουμπί στη συσκευή).
Περίληψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης