I've been programming with swift for a bit now, but I'm completely new to Core Bluetooth. Is there a way to send primitive data (integers, characters) from one iOS device to another using Core Bluetooth?
Thanks in advance
Yes. You need to make one device peripheral and the second central(or both of them). In the peripheral you need to advertise data(peripheralManager.startAdvertising) and in the central you need to get it by the characteristic. You can read all about that in https://developer.apple.com/documentation/corebluetooth
Here is the code related to CBCentral and CBPeripheral in Swift.
CBCentral
After Scan & Connect
/** We've connected to the peripheral, now we need to discover the services and characteristics to find the 'transfer' characteristic.
*/
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Peripheral Connected")
// Stop scanning
centralManager?.stopScan()
print("Scanning stopped")
// Clear the data that we may already have
data.length = 0
// Make sure we get the discovery callbacks
peripheral.delegate = self
// Search only for services that match our UUID
peripheral.discoverServices([transferServiceUUID])
}
/** The Transfer Service was discovered
*/
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
guard error == nil else {
print("Error discovering services: \(error!.localizedDescription)")
cleanup()
return
}
guard let services = peripheral.services else {
return
}
// Discover the characteristic we want...
// Loop through the newly filled peripheral.services array, just in case there's more than one.
for service in services {
peripheral.discoverCharacteristics([transferCharacteristicUUID], for: service)
}
}
/** The Transfer characteristic was discovered.
* Once this has been found, we want to subscribe to it, which lets the peripheral know we want the data it contains
*/
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
// Deal with errors (if any)
guard error == nil else {
print("Error discovering services: \(error!.localizedDescription)")
cleanup()
return
}
guard let characteristics = service.characteristics else {
return
}
// Again, we loop through the array, just in case.
for characteristic in characteristics {
// And check if it's the right one
if characteristic.uuid.isEqual(transferCharacteristicUUID) {
// If it is, subscribe to it
peripheral.setNotifyValue(true, for: characteristic)
}
}
// Once this is complete, we just need to wait for the data to come in.
}
/** This callback lets us know more data has arrived via notification on the characteristic
*/
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
guard error == nil else {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let stringFromData = NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue) else {
print("Invalid data")
return
}
// Have we got everything we need?
if stringFromData.isEqual(to: "EOM") {
// We have, so show the data,
textView.text = String(data: data.copy() as! Data, encoding: String.Encoding.utf8)
// Cancel our subscription to the characteristic
peripheral.setNotifyValue(false, for: characteristic)
// and disconnect from the peripehral
centralManager?.cancelPeripheralConnection(peripheral)
} else {
// Otherwise, just add the data on to what we already have
data.append(characteristic.value!)
// Log it
print("Received: \(stringFromData)")
}
}
CBPeripheral
After Scan & Connect
/** Catch when someone subscribes to our characteristic, then start sending them data
*/
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
print("Central subscribed to characteristic")
// Get the data
dataToSend = textView.text.data(using: String.Encoding.utf8)
// Reset the index
sendDataIndex = 0;
// Start sending
sendData()
}
/** Recognise when the central unsubscribes
*/
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didUnsubscribeFrom characteristic: CBCharacteristic) {
print("Central unsubscribed from characteristic")
}
// First up, check if we're meant to be sending an EOM
fileprivate var sendingEOM = false;
/** Sends the next amount of data to the connected central
*/
fileprivate func sendData() {
if sendingEOM {
// send it
let didSend = peripheralManager?.updateValue(
"EOM".data(using: String.Encoding.utf8)!,
for: transferCharacteristic!,
onSubscribedCentrals: nil
)
// Did it send?
if (didSend == true) {
// It did, so mark it as sent
sendingEOM = false
print("Sent: EOM")
}
// It didn't send, so we'll exit and wait for peripheralManagerIsReadyToUpdateSubscribers to call sendData again
return
}
// We're not sending an EOM, so we're sending data
// Is there any left to send?
guard sendDataIndex < dataToSend?.count else {
// No data left. Do nothing
return
}
// There's data left, so send until the callback fails, or we're done.
// Can't be longer than 20 bytes
var didSend = true
while didSend {
// Make the next chunk
// Work out how big it should be
var amountToSend = dataToSend!.count - sendDataIndex!;
// Copy out the data we want
let chunk = dataToSend!.withUnsafeBytes{(body: UnsafePointer<UInt8>) in
return Data(
bytes: body + sendDataIndex!,
count: amountToSend
)
}
// Send it
didSend = peripheralManager!.updateValue(
chunk as Data,
for: transferCharacteristic!,
onSubscribedCentrals: nil
)
// If it didn't work, drop out and wait for the callback
if (!didSend) {
return
}
let stringFromData = NSString(
data: chunk as Data,
encoding: String.Encoding.utf8.rawValue
)
print("Sent: \(stringFromData)")
// It did send, so update our index
sendDataIndex! += amountToSend;
// Was it the last one?
if (sendDataIndex! >= dataToSend!.count) {
// It was - send an EOM
// Set this so if the send fails, we'll send it next time
sendingEOM = true
// Send it
let eomSent = peripheralManager!.updateValue(
"EOM".data(using: String.Encoding.utf8)!,
for: transferCharacteristic!,
onSubscribedCentrals: nil
)
if (eomSent) {
// It sent, we're all done
sendingEOM = false
print("Sent: EOM")
}
return
}
}
}
/** This callback comes in when the PeripheralManager is ready to send the next chunk of data.
* This is to ensure that packets will arrive in the order they are sent
*/
func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) {
// Start sending again
sendData()
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With