Reputation: 747
Im developing an app on OSX that uses CoreBluetooth. I have encountered a problem on OSX Mavericks that i cant seem to get around. (All of this works perfectly on OSX 10.8).
First lets go through the flow of the application
This flow is fairly established and has been used used successfully in iOS apps and works on 10.8. So on Mavericks, the first run completes successfully. It scans, finds and connects to the device correctly. It also saves out the UUID of the device to a .plist file along with other properties.
Upon relaunch of the app, it attempts to go down the left hand column of the flow which is where the problems seem to occur.
So the first issue i noticed was that my call to self.central retrievePeripherals:
never calls my delegate callback of -(void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
. It simply never gets the callback on Mavericks.
My next thought was "oh they have a new API for fetching peripherals on Mavericks and the old one is deprecated, lets try that". So i added in my calls to NSArray *identifiers = [self.central retrievePeripheralsWithIdentifiers:@[uuid]];
and i get caught in a sempahore wait trap. Upon closer debugging of what was going on it turned out that sometimes my CBCentralManager gets into a state of CBCentralManagerStateUnknown and never updates the state to a newer one.
The next thing i tried was to fire up Activity Monitor and kill the blued process. Finally, my delegate callback for -(void)centralManagerDidUpdateState:(CBCentralManager *)central
was called with the correct CBCentralManagerStatePoweredOn so i performed retrievePeripheralsWithIdentifiers
again and received an empty array.
So all of these problems seem to be linked to blued in some way. Does anyone have more insight into this process to elude as to what is going on?
My main question is. Why does this work the first time through the app but not the second? Upon quitting the app after the initial scan and connection it seems i can no longer use the system bluetooth for anything without resetting blued (which even then doesn't retrieve peripherals). Is there some sort of shutdown sequence i need to do on the CBCentralManager to keep blued from going AWOL?
Any advice would be greatly apprecciated!
Upvotes: 3
Views: 619
Reputation: 81
While this is obviously a very old thread, I stumbled upon the same issue today and decided to post a fix for posterity.
I was trying to hack together a simple app based on the HeartRateMonitor example provided by Apple. Unfortunately, it does not work on 10.9 if autoConnect is set to TRUE, what's worse, it brings blued down on its knees.
In 10.9, a call to the (deprecated) retrievePeripherals
freezes blued without a chance to restore. CBCentralManager goes into CBCentralManagerStateUnknown, Bluetooth cannot be turned on/off using OS functions etc. The only solution that I found is to killall -9 blued
.
However, the synchronous retrievePeripheralsWithIdentifiers worked well for me (on 10.9.4). Here's the relevant excerpt from the modified HeartRateMonitor code:
/* Retreive already known devices */
if(autoConnect)
{
NSArray *peripherals = [manager retrievePeripheralsWithIdentifiers:[NSArray arrayWithObject:(id)aPeripheral.identifier]];
NSLog(@"Retrieved peripheral: %lu - %@", [peripherals count], peripherals);
[self stopScan];
/* If there are any known devices, automatically connect to it.*/
if([peripherals count] >=1)
{
[indicatorButton setHidden:FALSE];
[progressIndicator setHidden:FALSE];
[progressIndicator startAnimation:self];
peripheral = [peripherals objectAtIndex:0];
[peripheral retain];
[connectButton setTitle:@"Cancel"];
[manager connectPeripheral:peripheral options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];
}
}
Upvotes: 3