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
要起作用的话,我这里设置的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事件
一样,参考下面的文章就好了
参考文章:【iOS开发|iOS开发-airpods的音频event适配】
http://blog.cocoachina.com/article/29610
https://blog.csdn.net/shengpeng3344/article/details/96424515
有时候人就喜欢给自己添堵啊,有些东西别招惹,有些人你撼动不了
推荐阅读
- 深入理解Go之generate
- 2020-04-07vue中Axios的封装和API接口的管理
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。
- iOS中的Block
- 记录iOS生成分享图片的一些问题,根据UIView生成固定尺寸的分享图片
- 2019-08-29|2019-08-29 iOS13适配那点事
- Hacking|Hacking with iOS: SwiftUI Edition - SnowSeeker 项目(一)
- iOS面试题--基础
- 我的软件测试开发工程师书单
- echart|echart 双轴图开发