CoreBluetooth didDiscoverPeripheral not being called in Swift - ios

I am 99% sure I followed the instructions to setup CoreBluetooth correctly. No matter what I do, when I run this app on my iPad mini, the Bluetooth is saying its on. It's saying it is scanning for devices, but it is absolutely not finding any devices. If I go to the Bluetooth menu on the device I do see other devices being discovered. I initialize the CBCentralManager. I setup centralManagerDidUpdateState. When that is sure the bluetooth is ready it calls centralManager.scanForPeripheralsWithServices. All this is happening correctly. But my delegate function centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) never ever gets called. My code is very simple. Maybe I am missing something but I was able to confirm that my Macbook is a BTLE device and my ipad mini is a BTLE device as well. Here is my code.
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate {
var centralManager:CBCentralManager!
var blueToothReady = false
override func viewDidLoad() {
super.viewDidLoad()
startUpCentralManager()
}
func startUpCentralManager() {
println("Initializing central manager")
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func discoverDevices() {
println("discovering devices")
centralManager.scanForPeripheralsWithServices(nil, options: nil)
}
func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) {
println("Discovered \(peripheral.name)")
}
func centralManagerDidUpdateState(central: CBCentralManager!) {
println("checking state")
switch (central.state) {
case .PoweredOff:
println("CoreBluetooth BLE hardware is powered off")
case .PoweredOn:
println("CoreBluetooth BLE hardware is powered on and ready")
blueToothReady = true;
case .Resetting:
println("CoreBluetooth BLE hardware is resetting")
case .Unauthorized:
println("CoreBluetooth BLE state is unauthorized")
case .Unknown:
println("CoreBluetooth BLE state is unknown");
case .Unsupported:
println("CoreBluetooth BLE hardware is unsupported on this platform");
}
if blueToothReady {
discoverDevices()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

I had to get my macbook advertising. Once I did that using https://github.com/mttrb/BeaconOSX it worked exactly as I had written it.

Related

How to capture the change of Bluetooth in iOS development?

Can we be notified in those situations? When iPhone's Bluetooth is on or off. When iPhone connects to or disconnect to another device by Bluetooth.
You can use CBCentralManager and add the CBCentralManagerDelegate methods to see when a peripheral device is connected / disconnected.
centralManagerDidUpdateState will give information about your iOS device's bluetooth state.
didConnectPeripheral and didDisconnectPeripheral can be used for monitoring connected devices when you connect to the device within your app using connect on your centralManager (seen in example below).
If you know the identifier of the device you want to check for, you can use CBCentralManager's retrievePeripheralsWithIdentifiers to check the connection status for devices that are connected independent of your app.
class ViewController: UIViewController, CBCentralManagerDelegate {
var centralManager:CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager.init(delegate: self, queue: DispatchQueue.main)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn {
centralManager.scanForPeripherals(withServices: nil, options: nil)
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
centralManager.connect(peripheral, options: nil)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("peripheral \(String(describing: peripheral.name)) connected")
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("peripheral \(String(describing: peripheral.name)) disconnected")
}
}
You can detect bluetooth On/Off status change implementing CBCentralManagerDelegate delegate of CoreBluetooth.
declare proparty like #property (nonatomic, strong) CBCentralManager *bluetoothManager;
And function like
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
NSLog(#"In status update function");
switch(self.bluetoothManager.state)
{
case CBManagerStateResetting:
_isBluetoothOn = NO;
break;
case CBManagerStateUnsupported:
_isBluetoothOn = NO;
break;
case CBManagerStateUnauthorized:
_isBluetoothOn = NO;
break;
case CBManagerStatePoweredOff:
_isBluetoothOn = NO;
break;
case CBManagerStatePoweredOn:
_isBluetoothOn = YES;
break;
default:
_isBluetoothOn = NO;
break;
}
}

How can we connect garmin devices to iOS Application using BLE

I am developing an iOS application for Heart rate monitoring, and want to connect a garmin device to my application using Bluetooth.
But I am not able to list down any Garmin device Using Core bluetooth in Swift using (180D Service UUID).
func startUpCentralManager() {
print("Initializing central manager")
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func discoverDevices() {
print("discovering devices")
let services = [CBUUID(string: HRM_HEART_RATE_SERVICE_UUID),CBUUID(string:HRM_DEVICE_INFO_SERVICE_UUID),CBUUID(string:HRM_DEVICE_BATTERY_LEVEL_SERVICE_UUID),CBUUID(string:CALORIE_SERVICE)]
centralManager.scanForPeripherals(withServices: services, options: nil)
}
//MARK: CBCentralManagerDelegate
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("checking state")
switch (central.state) {
case .poweredOff:
print("CoreBluetooth BLE hardware is powered off")
case .poweredOn:
print("CoreBluetooth BLE hardware is powered on and ready")
blueToothReady = true;
case .resetting:
print("CoreBluetooth BLE hardware is resetting")
case .unauthorized:
print("CoreBluetooth BLE state is unauthorized")
case .unknown:
print("CoreBluetooth BLE state is unknown");
case .unsupported:
print("CoreBluetooth BLE hardware is unsupported on this platform");
}
if blueToothReady {
discoverDevices()
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
let nameOfDeviceFound = (advertisementData as NSDictionary).object(forKey: CBAdvertisementDataLocalNameKey) as? NSString
print("\(String(describing: nameOfDeviceFound))")
print("Discovered Peripheral name : ", peripheral.name ?? String())
if !Utilities.allPeripheralList.contains(peripheral)
{
Utilities.allPeripheralList.add(peripheral)
}
let deviceObj = DeviceModel()
deviceObj.deviceName = peripheral.name ?? String()
deviceObj.UDID = String(format: "%#",(peripheral.identifier).uuidString)
self.addingPeripheralToGlobalSearchArray(obj: deviceObj)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheral.delegate = self
peripheral.discoverServices(nil)
self.connected = peripheral.state == CBPeripheralState.connected ? "YES" : "NO"
print("Connection Status : %#", self.connected)
if self.connected == "YES"{
Utilities.sharedInstance.goToDashboardTabBarScreen(viewController: self)
}
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
// central.scanForPeripherals(withServices: nil, options: nil)
}
func addingPeripheralToGlobalSearchArray(obj:DeviceModel){
var isFound:Bool = false
for i in 0..<Utilities.allDeviceList.count{
let deviceObj = Utilities.allDeviceList[i] as! DeviceModel
if obj.UDID == deviceObj.UDID{
isFound = true
}
}
if !isFound{
Utilities.allDeviceList.add(obj)
}
}
Above is the code which I am using to list down BLE devices. I am able to find Mio-Fuse devices using same peace of code but not Garmin devices.
You need to use the Garmin Standard SDK. Contact Garmin and register as a developer. You cannot connect directly using BLE you have to connect via the Garmin SDK API.

didDisconnectPeripheral not called iOS Swift 3

I'm trying to disconnect from a BLE device. I'm doing cancelPeripheralConnection() and its never calling didDisconnectPeripheral().
I'm setting notify value to one characteristic, so while disconnecting i'm setting it false.
{
BLEOperations.sharedInstance.connectedDevice?.setNotifyValue(false, for: BLEOperations.sharedInstance.peripheralCharacteristics[0])
BLEOperations.sharedInstance.manager.cancelPeripheralConnection(BLEOperations.sharedInstance.connectedDevice!)
}
I'm trying to disconnect connectedPeripheral when user tries to connect to new device. The current device is not disconnected but new device is connected along with old one.
{
BLEOperations.sharedInstance.manager.connect(self.peripheralArray[indexPath.row] as! CBPeripheral , options: nil)
}
What am i doing wrong here? When device connection is lost the method is being called.
It will work fine when the CentralManager has only one instance in the entire flow.
Instead of using centralmanagerdelegates in viewcontroller, you can create a CentralManager operations class (which is a singleton) and perform operations.
I did that and its working fine.
Well, probably we would need more information about your code. But the method you are looking for, is this one.
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
disconnected(central: central)
}
You should set your centralManager's delegate to self, and everytime a peripheral is disconnected it should call the delegate.
Doing some tests, the disconnection process is not as nice as it seems, you can see your peripheral is still disconnecting but the delegate has been called (this can be adjusted with the hardware itself or the firmware on your peripheral).
BTW, you can connect several devices at once.
Cancels an active or pending connection to peripheral
class ViewController: UIViewController, CBCentralManagerDelegate {
var manager: CBCentralManager!
var peripherals: [CBPeripheral]?
#IBAction func actionScanBLEDevice(_ sender: AnyObject) {
manager = CBCentralManager (delegate: self, queue: nil)
}
#IBAction func actionDisconnectBLE(_ sender: AnyObject) {
//Use As per need where you want to disconnect perticular peripheral
manager.cancelPeripheralConnection(peripheral[0]) // Disconnent numbers of BLE Devices
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
//Manage Some Condition then disconnect
print("Disconnected from peripheral")
peripherals?.append(peripheral)
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Discovered peripheral \(peripheral.name,peripheral.identifier.uuidString)")
print("advertisementData\(advertisementData)")
// Use discovered peripheral here
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("Checking")
switch(central.state)
{
case.unsupported:
print("BLE is not supported")
case.unauthorized:
print("BLE is unauthorized")
case.unknown:
print("BLE is Unknown")
case.resetting:
print("BLE is Resetting")
case.poweredOff:
print("BLE service is powered off")
case.poweredOn:
print("BLE service is powered on")
print("Start Scanning")
manager.scanForPeripherals(withServices: nil, options: nil)
}
}
}

Bluetooth doesn't discover devices

First off, I know this question has been asked a lot on SO. And I went through all of them trying to resolve it but to no avail.
I have a simple app that scans for Bluetooth enabled devices. Here's my code.
import CoreBluetooth
import UIKit
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
var manager: CBCentralManager!
var peripheral: CBPeripheral!
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil)
}
// MARK: - CBCentralManagerDelegate
func centralManagerDidUpdateState(central: CBCentralManager) {
print(#function)
switch central.state {
case .Unsupported:
print("Unsupported")
case .Unauthorized:
print("Unauthorized")
case .PoweredOn:
print("Powered On")
central.scanForPeripheralsWithServices(nil, options: nil)
case .Resetting:
print("Resetting")
case .PoweredOff:
print("Powered Off")
case .Unknown:
print("Unknown")
}
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
print(#function)
print("Discovered \(peripheral.name) at \(RSSI)")
if peripheral.name!.containsString(name) {
manager.stopScan()
self.peripheral = peripheral
self.peripheral.delegate = self
manager.connectPeripheral(peripheral, options: nil)
}
}
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
print(#function)
}
func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
central.scanForPeripheralsWithServices(nil, options: nil)
}
// MARK: - CBPeripheralDelegate
func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
print(#function)
guard let services = peripheral.services else {
return
}
for service in services {
print(service.UUID)
if service.UUID == serviceUUID {
peripheral.discoverCharacteristics(nil, forService: service)
}
}
}
func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
print(#function)
guard let characteristics = service.characteristics else {
return
}
for characteristic in characteristics {
print(characteristic.UUID)
if characteristic.UUID == scratchUUID {
peripheral.setNotifyValue(true, forCharacteristic: characteristic)
}
}
}
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
print(#function)
var count: UInt32 = 0
if characteristic.UUID == scratchUUID {
characteristic.value!.getBytes(&count, length: sizeof(UInt32))
print(String(format: "%llu", count))
}
}
}
I ran it in my iPhone 5 (iOS 9.3.4). I had a laptop running Windows, an Android phone, an iPad Air 2 and my Mac all Bluetooth turned on. But none of those devices were discovered. centralManagerDidUpdateState method gets called and scanning starts but that's it. didDiscoverPeripheral delegate method never gets called.
I repeated the process, this time ran it in the iPad Air 2 but same result.
If I go to the Bluetooth menu on the device I do see other devices being discovered.
In some SO answers, I saw that running it in the main queue would work. Like so, manager = CBCentralManager(delegate: self, queue: dispatch_get_main_queue()). But that did not work for me either.
I'd really appreciate any help on this.
Your other devices are probably not advertising a BLE service (like Paulw11 mentioned in the comments). All of the devices you mentioned will not appear as discoverable unless they are in the Bluetooth Settings page.
There are apps for iOS, Android, and Windows that have them advertise over LE. The easiest to use is LightBlue for iOS. Run your app on the iPhone while the other iOS device is advertising and you should see the advertisements. It might be useful to get an LE advertisement scanner on Windows or Android to double check that LightBlue is advertising.
Note Windows does not yet support Peripheral Role for Bluetooth LE,
so even though you will be able to see the advertisement you will not
be able to connect to it.

How can I see the BLE services of a peripheral device?

I would to make app which will allow me to download some data from a peripheral device. I can connect with the peripheral device, but I can’t download services which are supported by this device. I don’t have second app which works as a peripheral. The second device is an iPad which has a virtual peripheral made in LightBlue.app. Sometimes it’s called Blank and sometimes it’s called iPad, I don’t know why.
This is my code:
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate{
#IBOutlet var coreBluetooth: UILabel!
#IBOutlet var discoveredDevices: UILabel!
#IBOutlet var foundBLE: UILabel!
#IBOutlet var connected: UILabel!
var centralManager:CBCentralManager!
var blueToothReady = false
var connectingPeripheral:CBPeripheral!
override func viewDidLoad() {
super.viewDidLoad()
startUpCentralManager()
}
func startUpCentralManager() {
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func discoverDevices() {
centralManager.scanForPeripheralsWithServices(nil, options: nil)
}
func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: (NSDictionary), RSSI: NSNumber!) {
discoveredDevices.text = "Discovered \(peripheral.name)"
println("Discovered: \(peripheral.name)")
centralManager.stopScan()
if peripheral.name == "iPad" || peripheral.name == "Blank"
{
println("ok")
centralManager.connectPeripheral(peripheral, options: nil)
self.connectingPeripheral = peripheral
}
}
func centralManagerDidUpdateState(central: CBCentralManager!) { //BLE status
switch (central.state) {
case .PoweredOff:
coreBluetooth.text = "CoreBluetooth BLE hardware is powered off"
case .PoweredOn:
coreBluetooth.text = "CoreBluetooth BLE hardware is powered on and ready"
blueToothReady = true;
case .Resetting:
coreBluetooth.text = "CoreBluetooth BLE hardware is resetting"
case .Unauthorized:
coreBluetooth.text = "CoreBluetooth BLE state is unauthorized"
case .Unknown:
coreBluetooth.text = "CoreBluetooth BLE state is unknown"
case .Unsupported:
coreBluetooth.text = "CoreBluetooth BLE hardware is unsupported on this platform"
}
if blueToothReady {
discoverDevices()
}
}
func centralManager(central: CBCentralManager!,didConnectPeripheral peripheral: CBPeripheral!)
{
connectingPeripheral.discoverServices(nil)
println("Connected")
foundBLE.textColor = UIColor.redColor()
foundBLE.text = "Connected to: \(peripheral.name)"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func scanBLE(sender: UIButton) {
centralManager.scanForPeripheralsWithServices(nil, options: nil)
}
func connectingPeripheral(peripheral: CBPeripheral!, didDiscoverServices error: NSError!)
{
println("Services \(connectingPeripheral.services)")
}
}
You need to set the peripheral's delegate to self in func centralManager(central: CBCentralManager!,didConnectPeripheral peripheral: CBPeripheral!) in order to get the call back when the services are discovered -
func centralManager(central: CBCentralManager!,didConnectPeripheral peripheral: CBPeripheral!)
{
connectingPeripheral.delegate=self
connectingPeripheral.discoverServices(nil)
println("Connected")
foundBLE.textColor = UIColor.redColor()
foundBLE.text = "Connected to: \(peripheral.name)"
}
You will then get a call back to func connectingPeripheral(peripheral: CBPeripheral!, didDiscoverServices error: NSError!)
swift 3
var peripheralDevice:CBPeripheral!
//if connected
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("connected")
self.peripheralDevice.discoverServices(nil)
}
//if disconnect
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("Disconnect")
}
//fail to connect
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print("Fail to connect, Please try again.")
}

Resources