Reputation: 895
I'm having trouble getting Core Bluetooth to discover peripherals on iOS 8. Same code works fine on iOS 7 device. Initially I thought it would be a permissions issue since I had been doing some iBeacon work and there are some changes in Core Location permissions on iOS 8. I couldn't find anything online that helped with that however. Here is a link to a sample project that works fine for me on iOS 7 but not on iOS 8:
https://github.com/elgreco84/PeripheralScanning
If I run this project on an iOS 7 device it will log advertisement data for a number of devices around me. On iOS 8 the only output I see is that the Central Manager state is "Powered On".
Upvotes: 14
Views: 6013
Reputation: 496
I ran into the same issue while building a very basic BLE scanner app. The required method "centralManagerDidUpdateState" was added. But nothing worked.
I believe the problem is related to queue
.
Put the CBCentralManager
instance in a dispatch_get_main_queue
This code snippet does that:
// BLE Stuff
let myCentralManager = CBCentralManager()
// Put CentralManager in the main queue
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
myCentralManager = CBCentralManager(delegate: self, queue: dispatch_get_main_queue())
}
Using the Default Single View xCode start app. You can put this into the ViewController.swift file:
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
// BLE Stuff
let myCentralManager = CBCentralManager()
var peripheralArray = [CBPeripheral]() // create now empty array.
// Put CentralManager in the main queue
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
myCentralManager = CBCentralManager(delegate: self, queue: dispatch_get_main_queue())
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// Mark CBCentralManager Methods
func centralManagerDidUpdateState(central: CBCentralManager!) {
updateStatusLabel("centralManagerDidUpdateState")
switch central.state{
case .PoweredOn:
updateStatusLabel("poweredOn")
case .PoweredOff:
updateStatusLabel("Central State PoweredOFF")
case .Resetting:
updateStatusLabel("Central State Resetting")
case .Unauthorized:
updateStatusLabel("Central State Unauthorized")
case .Unknown:
updateStatusLabel("Central State Unknown")
case .Unsupported:
println("Central State Unsupported")
default:
println("Central State None Of The Above")
}
}
func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) {
println("Did Discover Peripheral")
}
}
Upvotes: 4
Reputation: 114783
It isn't valid to start scanning for peripherals until you are in the 'powered on' state. Perhaps on your iOS7 device you are lucky with timing, but the code is still incorrect. Your centralManagerDidUpdateState:
should be
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
switch (central.state)
{
case CBCentralManagerStateUnsupported:
{
NSLog(@"State: Unsupported");
} break;
case CBCentralManagerStateUnauthorized:
{
NSLog(@"State: Unauthorized");
} break;
case CBCentralManagerStatePoweredOff:
{
NSLog(@"State: Powered Off");
} break;
case CBCentralManagerStatePoweredOn:
{
NSLog(@"State: Powered On");
[self.manager scanForPeripheralsWithServices:nil options:nil];
} break;
case CBCentralManagerStateUnknown:
{
NSLog(@"State: Unknown");
} break;
default:
{
}
}
}
And remove the call to scanForPeripheralsWithServices
from didFinishLaunchingWithOptions
Upvotes: 33