對於airpods
的適配,主要適配其單耳機拿下pause
,以及恢復和雙耳機取下
等情景的適配。
單耳機拿下
對於這些事件,airpods單耳機拿下
屬於pause
事件Event,我們使用MediaPlayer
框架。
iOS 7.1 Before
在iOS 7.1
之前,系統提供了
#import <MediaPlayer/MediaPlayer.h>
//開始接收遠程控制事件 - 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
要起作用的話,我這裏設置的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
有時候人就喜歡給自己添堵啊,有些東西別招惹,有些人你撼動不了