iOS开发|iOS开发-airpods的音频event适配


文章目录

  • 单耳机拿下
    • iOS 7.1 Before
    • MPRemoteCommandCenter
  • 双耳机取下

对于airpods的适配,主要适配其单耳机拿下pause,以及恢复和双耳机取下等情景的适配。
单耳机拿下 对于这些事件,airpods单耳机拿下属于pause事件Event,我们使用MediaPlayer框架。
iOS 7.1 Before 在iOS 7.1之前,系统提供了
#import
//开始接收远程控制事件 - UIApplication实例方法 - (void)beginReceivingRemoteControlEvents; //结束接收远程控制事件 - (void)endReceivingRemoteControlEvents; //远程控制事件的捕获处理 - (void)remoteControlReceivedWithEvent:(UIEvent *)event

代码实现:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 在App启动后开启远程控制事件, 接收来自锁屏界面和上拉菜单的控制 [application beginReceivingRemoteControlEvents]; return YES; }- (void)applicationWillTerminate:(UIApplication *)application { // 在App要终止前结束接收远程控制事件, 也可以在需要终止时调用该方法终止 [application endReceivingRemoteControlEvents]; }// 在具体的控制器或其它类中捕获处理远程控制事件 - (void)remoteControlReceivedWithEvent:(UIEvent *)event { // 根据事件的子类型(subtype) 来判断具体的事件类型, 并做出处理 switch (event.subtype) { case UIEventSubtypeRemoteControlPlay: case UIEventSubtypeRemoteControlPause: { // 执行播放或暂停的相关操作 (锁屏界面和上拉快捷功能菜单处的播放按钮) break; } case UIEventSubtypeRemoteControlPreviousTrack: { // 执行上一曲的相关操作 (锁屏界面和上拉快捷功能菜单处的上一曲按钮) break; } case UIEventSubtypeRemoteControlNextTrack: { // 执行下一曲的相关操作 (锁屏界面和上拉快捷功能菜单处的下一曲按钮) break; } case UIEventSubtypeRemoteControlTogglePlayPause: { // 进行播放/暂停的相关操作 (耳机的播放/暂停按钮) break; } default: break; } }

这里由于系统iOS13的适配,MPCommand的结果往往都需要返回一个MPRemoteCommandHandlerStatus,开发者需要注意,不然会有偶发的崩溃。
MPRemoteCommandCenter 我们使用iOS 7.1之后系统提供的MPRemoteCommandCenter
- (void)startCommandMonitor { dispatch_async(dispatch_get_main_queue(), ^{ [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; }); MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter]; commandCenter.pauseCommand.enabled = YES; [commandCenter.pauseCommand addTarget:self action:@selector(commandPause)]; commandCenter.playCommand.enabled = YES; [commandCenter.playCommand addTarget:self action:@selector(commandPlay)]; }

  • beginReceivingRemoteControlEvents必须要在主线程调用
  • MPRemoteCommand要起作用的话,我这里设置的ModeAVAudioSessionCategoryPlaybackAVAudioSessionCategoryPlayAndRecord模式下回调是不走的。
- (MPRemoteCommandHandlerStatus)commandPause { BOOL result = [self pause]; if (result) { return MPRemoteCommandHandlerStatusSuccess; }else { return MPRemoteCommandHandlerStatusCommandFailed; } }- (MPRemoteCommandHandlerStatus)commandPlay { BOOL result = [self resume]; if (result) { return MPRemoteCommandHandlerStatusSuccess; }else { return MPRemoteCommandHandlerStatusCommandFailed; } }- (void)stopCommandMonitor { MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter]; commandCenter.pauseCommand.enabled = NO; [commandCenter.pauseCommand removeTarget:self]; commandCenter.playCommand.enabled = NO; [commandCenter.playCommand removeTarget:self]; dispatch_async(dispatch_get_main_queue(), ^{ [[UIApplication sharedApplication] endReceivingRemoteControlEvents]; }); }

这样就处理了单耳机拿下pause的情景。
双耳机取下 双耳机取下属于routeChange通知的部分,代表设备已经断开。
进行监听通知:
NSNotificationCenter *noficationCenter = [NSNotificationCenter defaultCenter]; [noficationCenter addObserver: self selector: @selector(handleRouteChange:) name: AVAudioSessionRouteChangeNotification object: session];

在回调中处理AVAudioSessionRouteChangeReasonOldDeviceUnavailableAVAudioSessionRouteChangeReasonNewDeviceAvailable的情况即可
- (void)handleRouteChange:(NSNotification *)notification { AVAudioSession *session = [AVAudioSession sharedInstance]; NSString *seccReason = @""; NSInteger reason = [[[notification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey] integerValue]; //AVAudioSessionRouteDescription* prevRoute = [[notification userInfo] objectForKey:AVAudioSessionRouteChangePreviousRouteKey]; switch (reason) { case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory: seccReason = @"The route changed because no suitable route is now available for the specified category."; break; case AVAudioSessionRouteChangeReasonWakeFromSleep: seccReason = @"The route changed when the device woke up from sleep."; break; case AVAudioSessionRouteChangeReasonRouteConfigurationChange: seccReason = @"The output route configuration changed."; break; case AVAudioSessionRouteChangeReasonOverride: seccReason = @"The output route was overridden by the app."; break; case AVAudioSessionRouteChangeReasonCategoryChange:{ seccReason = @"The output route category changed."; } break; case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:{ //可以进行判断设备类型,这里仅pause了 [self pause]; } break; case AVAudioSessionRouteChangeReasonNewDeviceAvailable:{ //可以进行判断设备类型 [self resume]; } break; case AVAudioSessionRouteChangeReasonUnknown:{ seccReason = [NSString stringWithFormat:@"AVAudioSession Route change Reason is %ld (oldUnavailiable:2,newDevice:1,unknown:0)",(long)reason]; } break; default: seccReason = [NSString stringWithFormat:@"The reason invalidate enum value : %ld",(long)reason]; break; }AVAudioSessionRouteDescription *currentRoute = session.currentRoute; for (AVAudioSessionPortDescription *output in currentRoute.outputs) { if (output.portType == AVAudioSessionPortBluetoothA2DP || output.portType == AVAudioSessionPortBluetoothLE || output.portType == AVAudioSessionPortBluetoothHFP ) { //耳机 _isBlueTooth = YES; }else { _isBlueTooth = NO; } } GSLog(@"handleRouteChange reason is %@,mode:%@,category:%@", seccReason,session.mode,session.category); }

这里需要注意的以下几点:
  • beginReceivingRemoteControlEvents必须要在主线程调用
  • MPRemoteCommand要起作用的话,我这里设置的CategoryAVAudioSessionCategoryPlaybackAVAudioSessionCategoryPlayAndRecord模式下回调是不走的。你可以进行两种Category的切换来达到你想要的效果。 微信在开启视频语音时,也是无法响应airpods的事件的。
  • 事件返回类型需要是MPRemoteCommandHandlerStatus
  • 双击下一首等事件处理和pause事件一样,参考下面的文章就好了
参考文章:
http://blog.cocoachina.com/article/29610
https://blog.csdn.net/shengpeng3344/article/details/96424515
【iOS开发|iOS开发-airpods的音频event适配】有时候人就喜欢给自己添堵啊,有些东西别招惹,有些人你撼动不了

    推荐阅读