如何在iOS中find蓝牙audio设备

好的,我正在做一个有趣的项目,有一个障碍,我需要为我的iOS应用程序启用蓝牙audio支持。

我所处的障碍是我根本无法获得连接的蓝牙audio设备列表。 即使我的iPhone 5S可以识别我的听筒(准确地说是一个3 – 4岁的LG HBM-230 ),并通过它来播放audio以进行通话,但是当我查询两者时, BOTH External Accessory和CoreBluetooth都没有什么用处。

我将自己的代码放在CoreBluetooth和External Accessory框架的问题和答案上。

当我的代码只是试图“ scanForPeripheralsWithServices:nil ”的任何蓝牙设备的设置 – >蓝牙说可见和连接,下面的代码只是不会有一个单一的命中超出控制台的“ CBCentralManagerStatePoweredOn ”消息。

和我的代码中的这一行(与一个有效的EAAccessoryManager实例)

 NSArray * connectedDevices = [self.eAAccessoryManager connectedAccessories]; 

也返回一个零arrays。

我可能做错了什么?

顺便说一句, 我已经把这个代码作为一个GitHub项目 。

 @implementation BluetoothManager + (BluetoothManager *)sharedInstance { static dispatch_once_t pred = 0; __strong static id _bluetoothMGR = nil; dispatch_once(&pred, ^{ _bluetoothMGR = [[BluetoothManager alloc] init]; }); return _bluetoothMGR; } - (id)init { self = [super init]; if(self) { dispatch_queue_t centralQueue = dispatch_queue_create("com.yo.mycentral", DISPATCH_QUEUE_SERIAL); // whether we try this on a queue of "nil" (the main queue) or this separate thread, still not getting results self.cbManager = [[CBCentralManager alloc] initWithDelegate:self queue:centralQueue options:nil]; } return self; } // this would hit.... if I instantiated this in a storyboard of XIB file - (void)awakeFromNib { if(!self.cbManager) self.cbManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil]; } - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { NSLog(@"hey I found %@",[advertisementData description]); } - (void)centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals { NSLog( @"I retrieved CONNECTED peripherals"); } -(void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals{ NSLog(@"This is it!"); } - (void)centralManagerDidUpdateState:(CBCentralManager *)central{ NSString *messtoshow; switch (central.state) { case CBCentralManagerStateUnknown: { messtoshow=@"State unknown, update imminent."; break; } case CBCentralManagerStateResetting: { messtoshow=@"The connection with the system service was momentarily lost, update imminent."; break; } case CBCentralManagerStateUnsupported: { messtoshow=@"The platform doesn't support Bluetooth Low Energy"; break; } case CBCentralManagerStateUnauthorized: { messtoshow=@"The app is not authorized to use Bluetooth Low Energy"; break; } case CBCentralManagerStatePoweredOff: { messtoshow=@"Bluetooth is currently powered off."; break; } case CBCentralManagerStatePoweredOn: { messtoshow=@"Bluetooth is currently powered on and available to use."; NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], CBCentralManagerScanOptionAllowDuplicatesKey, nil]; [_cbManager scanForPeripheralsWithServices:nil options:options]; break; } } NSLog(@"%@", messtoshow); } @end 

首先,您需要configuration您的应用程序audio会话以允许支持audio的蓝牙连接。 例如,您可以在应用程序委托 – (BOOL)应用程序中执行此操作:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法。 确保链接AVFoundation框架并导入将使用它的标头。

 #import <AVFoundation/AVFoundation.h>// place in .h [self prepareAudioSession];// called from application didFinishLaunchingWithOptions - (BOOL)prepareAudioSession { // deactivate session BOOL success = [[AVAudioSession sharedInstance] setActive:NO error: nil]; if (!success) { NSLog(@"deactivationError"); } // set audio session category AVAudioSessionCategoryPlayAndRecord options AVAudioSessionCategoryOptionAllowBluetooth success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil]; if (!success) { NSLog(@"setCategoryError"); } // activate audio session success = [[AVAudioSession sharedInstance] setActive:YES error: nil]; if (!success) { NSLog(@"activationError"); } return success; } 

每个应用程序都有一个可configuration的audio会话单例。 会话类别和模式(在这个例子中,我没有设置模式,所以它恢复到默认模式)声明您的应用程序的意图,如何处理audio路由。 它遵循胜利最后一个重要规则。 这意味着如果用户插入耳机或在这种情况下是免提外设(HFP)的蓝牙设备,则系统将自动将audio路由到耳机或蓝牙设备。 用户物理动作用于确定audio路由。 但是,如果你想给用户一个可用路线列表苹果build议使用MPVolumeView类。

添加MPVolumeView的示例可以放在UIViewController的子类viewDidLoad方法中。

 #import <MediaPlayer/MediaPlayer.h> // place in .h // prefered way using MPVolumeView for user selecting audio routes self.view.backgroundColor = [UIColor clearColor]; CGRect frameForMPVV = CGRectMake(50.0, 50.0, 100.0, 100.0); MPVolumeView *routeView = [[MPVolumeView alloc] initWithFrame:frameForMPVV]; [routeView setShowsVolumeSlider:NO]; [routeView setShowsRouteButton:YES]; [self.view addSubview: routeView]; 

从iOS 7开始,你可以得到像这样的所有input

 // portDesc.portType could be for example - BluetoothHFP, MicrophoneBuiltIn, MicrophoneWired NSArray *availInputs = [[AVAudioSession sharedInstance] availableInputs]; int count = [availInputs count]; for (int k = 0; k < count; k++) { AVAudioSessionPortDescription *portDesc = [availInputs objectAtIndex:k]; NSLog(@"input%i port type %@", k+1, portDesc.portType); NSLog(@"input%i port name %@", k+1, portDesc.portName); } 

您将感兴趣的portType是“BluetoothHFP”。 portName属性通常是制造商/型号,这是你将显示给用户。 (我已经检查了非LE蓝牙摩托罗拉恐龙,它的工作原理)

由于最后的胜利规则,您将需要观察这两个通知(包括iOS 7)。 一个用于处理中断(如电话或报警),另一个用于通知路由改变。 路线变更通知是与这个问题有关的。

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myInterruptionSelector:) name:AVAudioSessionInterruptionNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myRouteChangeSelector:) name:AVAudioSessionRouteChangeNotification object:nil]; 

对于iOS 6.x,您可以读取myRouteChange:select器内AVAudioSession的currentRoute属性以获取新路由,因为在连接耳机或蓝牙设备时会调用此路由。

 - (void)myRouteChangeSelector:(NSNotification*)notification { AVAudioSessionRouteDescription *currentRoute = [[AVAudioSession sharedInstance] currentRoute]; NSArray *inputsForRoute = currentRoute.inputs; NSArray *outputsForRoute = currentRoute.outputs; AVAudioSessionPortDescription *outPortDesc = [outputsForRoute objectAtIndex:0]; NSLog(@"current outport type %@", outPortDesc.portType); AVAudioSessionPortDescription *inPortDesc = [inputsForRoute objectAtIndex:0]; NSLog(@"current inPort type %@", inPortDesc.portType); } 

任何iOS版本<6.0,您将需要现在不赞成的AudioSessionServices类。 这个类是一个C API,而不是通知,它允许你添加属性监听器。

我会完成这个笔记 – 你不会总是从系统中得到你想要的。 有中断处理通知要观察和大量的错误检查需要。 我认为这是一个非常好的问题,我希望这能够说明你正在努力实现的目标。