在iOS中实现和解决背景音频问题

15

在StackOverflow上有很多关于iOS背景音乐播放的问题。没有一个能够完全探索所有边角案例,这个问题的目的是成为iOS背景音频问题的最终答案。

定义和假设

所有代码、问题和示例均指向

"后台" — 当用户按下主页键或电源键(使设备显示锁屏)时,应用程序进入的状态。也可以使用多任务切换器或iPad上的多任务手势将应用程序置于后台。

"音频" — 使用AudioQueue(包括AVAudioPlayer)播放的音频。

前提条件

据我所知,要使应用程序在后台播放音频,需要满足以下两个要求:

  1. Info.plist中设置UIBackgroundModesaudio
  2. [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];

需求

我的用例是在后台播放相对较长的音频(如音乐)。有可能有数百个轨道,应用程序将按顺序播放它们。可以认为音频将无限期地播放。

应用程序将通过暂停播放来处理中断。

问题

我在尝试使用以下方法时遇到了一些问题:

[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:...];

允许音频在后台播放。但我不确定是否需要以及它与以下内容有何不同:

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];

边缘情况

  1. 中断。如果你注册了成为 AVAudioPlayer 的代理来接收音频中断通知(如电话等),例如当中断开始时暂停或停止音频,当中断结束后恢复播放,那么如果中断超过10分钟(后台任务完成的最大时间),你的应用程序会被挂起吗?

  2. 在使用中,模拟器如果锁定或者按下 Home 键,会停止音频播放:

    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    
    但是这在设备上可以工作。这是否是已知的问题?

你想在后台播放短音频(例如少于10秒)还是长音频? - yonel
你想要在后台播放音乐,并处理中断吗? - Sanoj Kashyap
@yonel 我已经添加了需求部分来回答你的问题。 - Richard Stelling
我已经处理了这个问题,通过双击主屏幕按钮来控制一个带有播放和暂停按钮的滚动视图。我也已经处理了屏幕锁定时的播放暂停控制。如果需要帮助,请告诉我。 - Sanoj Kashyap
请查看这里,也许能帮到你。我在那里提供了答案。 - Sanoj Kashyap
显示剩余3条评论
2个回答

5

我有一些GPS后台模式和后台音频的经验。虽然这与你的情况不完全相同(你想播放长音频文件,而我播放短消息),但以下是我可以告诉你的:

  • beginBackgroundTaskWithExpirationHandler这个方法在后台有一个目的:避免应用程序返回到被冻结状态,无法再调用任何代码。只要调用了beginBackgroundTaskWithExpirationHandler并在使用beginBackgroundTaskWithExpirationHandler终止长时间运行的任务之前,您就可以使用CPU并消耗电池。
    我真的怀疑在后台播放文件会像运行应用程序一样使用iPhone的电池,因此我怀疑beginBackgroundTaskWithExpirationHandler是否确实涉及您的流程。

  • 模拟器:不要依赖模拟器:它没有完全实现后台模式。实际上,当您单击主屏幕按钮时,您的应用程序进入后台,但是在此阶段,您仍然可以执行应用程序中的代码。过一段时间,您的应用程序将被暂停(=冻结),为了节省电池而暂停您的代码执行。 这种暂停状态永远不会发生在模拟器上。

  • 中断。当电话呼入时,暂停/恢复播放不取决于您。平台负责此操作,您只能使用AVAudioSessionDelegate对其进行反应。但是,您可以通过在音频会话上设置属性(例如kAudioSessionProperty_OverrideCategoryMixWithOthers)来影响您的会话与其他音频声音的交互方式。 因此,流程更多是:您描述音频会话应该如何与系统的其余部分交互,系统将根据此混合声音,如果您的会话被中断,则会通过AVAudioSessionDelegate通知您。

希望这有所帮助。

3
我已经使用以下代码进行设备控制 -
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];

用于注册监听远程控制。

完成后请删除它 -

[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];

使App能够成为第一响应者 -

- (BOOL)canBecomeFirstResponder {
    return YES;
}

使用委托方法处理 iPhone 控制,例如在双击主页按钮时播放和暂停。
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
    //if it is a remote control event handle it correctly
    if (event.type == UIEventTypeRemoteControl) {
        if (event.subtype == UIEventSubtypeRemoteControlPlay) {
           [audioPlayer play];
            NSLog(@"play");
        } else if (event.subtype == UIEventSubtypeRemoteControlPause) {
           [audioPlayer stop];
             NSLog(@"pause");
        } else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause) {
            NSLog(@"toggle");
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接