我有一个简单的应用程序,其中有一个播放 M3U8 内容的 AVPlayer。在应用程序中,我执行以下操作以允许背景音频:
NSError *audioError;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&audioError];
if (audioError == nil)
{
[[AVAudioSession sharedInstance] setActive:YES error:nil];
}
当我按下手机上的锁定按钮时,音频暂停。如果我再次按下锁定按钮(查看锁定屏幕),我会看到媒体控件,并且可以取消暂停内容以收听音频。
我的问题是,如何防止这种自动暂停,以便在首次按下锁定按钮时继续播放?我尝试了类似以下的方法:
- (id) init
{
// ...
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleEnteredBackground) name: UIApplicationDidEnterBackgroundNotification object: nil];
// ...
}
- (void) handleEnteredBackground
{
// [player play];
[player performSelector:@selector(play) withObject:nil afterDelay:1];
}
但这似乎不起作用。
经过一番搜索,我找到了我的问题:
如果您正在播放纯音频资源,例如 MP3 或 M4A 文件,则您的设置已完成,您的应用程序可以播放背景音频。 如果您需要播放视频资源的音频部分,则需要执行额外的步骤。 如果播放器的当前项目正在设备上显示视频,则当应用程序发送到后台时,AVPlayer 实例的播放会自动暂停. 如果您想继续播放音频,请在进入后台时断开 AVPlayer 实例与演示文稿的连接,并在返回前台时重新连接。
他们的(Swift)示例代码如下所示:
func applicationDidEnterBackground(_ application: UIApplication) {
// Disconnect the AVPlayer from the presentation when entering background
// If presenting video with AVPlayerViewController
playerViewController.player = nil
// If presenting video with AVPlayerLayer
playerLayer.player = nil
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Reconnect the AVPlayer to the presentation when returning to foreground
// If presenting video with AVPlayerViewController
playerViewController.player = player
// If presenting video with AVPlayerLayer
playerLayer.player = player
}
Objective-C 的等价物是:
- (void) applicationDidEnterBackground:(UIApplication*)application
{
playerViewController.player = nil;
}
- (void) applicationWillEnterForeground:(UIApplication*)application
{
playerViewController.player = player;
}
或者在我的例子中,播放器嵌入到视图中,并且不直接由应用程序委托或视图控制器控制,因此我使用了以下内容:
- (id) init
{
// ...
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleEnteredBackground) name: UIApplicationDidEnterBackgroundNotification object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleEnteredForeground) name: UIApplicationDidBecomeActiveNotification object: nil];
// ...
}
- (void) handleEnteredBackground
{
controller.player = nil;
}
- (void) handleEnteredForeground
{
controller.player = player;
}
很快就可能是这样的
private func setupPlayInBackground() {
NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main, using: { [weak self] _ in
self?.playerLayer?.player = nil
})
NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main, using: { [weak self] _ in
self?.playerLayer?.player = self?.player
})
// Add controls to lock screen if needed
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.isEnabled = true
commandCenter.pauseCommand.isEnabled = true
commandCenter.playCommand.addTarget { [weak self] _ -> MPRemoteCommandHandlerStatus in
self?.player?.play()
return MPRemoteCommandHandlerStatus.success
}
commandCenter.pauseCommand.addTarget { [weak self] _ -> MPRemoteCommandHandlerStatus in
self?.player?.pause()
return MPRemoteCommandHandlerStatus.success
}
}