对于airpods
的适配,主要适配其单耳机拿下pause
,以及恢复和双耳机取下
等情景的适配。
对于这些事件,airpods单耳机拿下
属于pause
事件Event,我们使用MediaPlayer
框架。
在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
,开发者需要注意,不然会有偶发的崩溃。
我们使用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
要起作用的话,我这里设置的Mode
是AVAudioSessionCategoryPlayback
,AVAudioSessionCategoryPlayAndRecord
模式下回调是不走的。- (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];
在回调中处理AVAudioSessionRouteChangeReasonOldDeviceUnavailable
和AVAudioSessionRouteChangeReasonNewDeviceAvailable
的情况即可
- (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
要起作用的话,我这里设置的Category
是AVAudioSessionCategoryPlayback
,AVAudioSessionCategoryPlayAndRecord
模式下回调是不走的。你可以进行两种Category
的切换来达到你想要的效果。 微信在开启视频语音时,也是无法响应airpods
的事件的。MPRemoteCommandHandlerStatus
双击下一首
等事件处理和pause事件
一样,参考下面的文章就好了参考文章:
http://blog.cocoachina.com/article/29610
https://blog.csdn.net/shengpeng3344/article/details/96424515
有时候人就喜欢给自己添堵啊,有些东西别招惹,有些人你撼动不了