Reputation: 77
I am writing an app that allows me to send an image through BLE to the app of someone else.
In order to test it out properly, I would need to be able to connect to an device, but my scanned peripherals are always disconnected and have nil as value. I am uncertain as to whether I am doing this right. I have been reading through guides and I am following the right procedure so could someone point out to me what I might be doing wrong? What are the peripherals I'm detecting?
output:
<CBPeripheral: 0x165b9c90, identifier = 6B74A074-6F5B-0E3A-94EB-6E7BB890569C, name = (null), state = disconnected>
<CBPeripheral: 0x165a0940, identifier = A35AC32E-5668-BD0D-4DBC-D4BF959B9242, name = (null), state = disconnected>
<CBPeripheral: 0x166a8220, identifier = 4D9FA1A1-0090-465F-B53D-363B0F3BBD27, name = (null), state = disconnected>
Edit: Added more code
Here is my code
import Foundation
import CoreBluetooth
import UIKit
class BluetoothController: UITableViewController, CBCentralManagerDelegate, CBPeripheralManagerDelegate, CBPeripheralDelegate {
var centralManager: CBCentralManager!
var peripheralManager: CBPeripheralManager!
var service : CBMutableService!
let uuid:CBUUID = CBUUID(string: "09d921ff-b80c-47b1-bc2b-5bbaadf62010")
let charaUuid:CBUUID = CBUUID(string: "09d921ff-b80c-47b1-bc2b-5bbaadf62021")
override func viewDidLoad() {
print("Initialzing managers")
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
centralManager = CBCentralManager(delegate: self, queue: nil)
service = CBMutableService(type: uuid, primary: true) //<--Probably not causing it but without a service...
let properties: CBCharacteristicProperties = [.notify, .read, .write]
let permissions: CBAttributePermissions = [.readable, .writeable]
let characteristic = CBMutableCharacteristic(
type: charaUuid,
properties: properties,
value: nil,
permissions: permissions)
service.characteristics = [characteristic];
peripheralManager.add(service)
}
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
print("peripheral state updated")
print("\(peripheral.description)")
}
func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?)
{
print("started advertising")
}
// Check if the bluetooth is powered on
// Start looking for devices
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
print("Scanning for devices")
centralManager.scanForPeripherals(withServices: nil, options: nil)
startAdvert()
} else {
print("Bluetooth not available.")
}
}
func startAdvert(){
let advertisingData = [CBAdvertisementDataLocalNameKey:"Test Device", CBAdvertisementDataServiceUUIDsKey: uuid] as [String : Any]
peripheralManager.startAdvertising(advertisingData)
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
print(peripheral)
//didReadPeripheral(peripheral, rssi: RSSI)
}
}
Upvotes: 0
Views: 2240
Reputation: 299713
As Paulw11 notes, you're not connected because you never call connect()
. You're discovering random BLE devices around you that have nothing to do with your app. That's because you're scanning for all possible services:
centralManager.scanForPeripherals(withServices: nil, options: nil)
You should almost never do that. It's bad for the battery and it's rarely what you want. You want to scan for your service.
centralManager.scanForPeripherals(withServices: [uuid], options: nil)
And then when you discover other devices advertising your service, then you need to connect to them.
To @WholeCheese's comment, the details of the question didn't really relate to the nil name, but to address the question in the title, you will not see a name from advertising if the devices does not advertise a local name over BLE. This is quite common. There is not a lot of space in the advertising packet for data (roughly 30 bytes), and local names can be quite large.
If you're building a scanning app and want to display those names, you'll need to connect to the device. At that point, Core Bluetooth will read the GAP name (rather than the advertised Local Name). In most cases the GAP names should be there (it's not promised from all devices, but it generally should be there). Core Bluetooth caches a lot of information, so if you've ever connected to the device before, it is possible that peripheral.name
will be filled out without connecting even if it's not advertised. But if it isn't, you'll need to connect.
Upvotes: 2