微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

iOS 14在后台播放视频中的音频

如何解决iOS 14在后台播放视频中的音频

iOS 14在后台播放视频中的音频: 应用进入背景时音频被暂停。甚至我在“功能”中打开了后台模式。 如果播放器正在播放,请按锁定按钮,然后发生

解决方法

如果您正在使用avplayer播放视频,并且还希望在应用程序处于后台时播放音频。

尝试以下代码,它可以在我的机器上运行:

  • Xcode版本:12.0
  • iOS版本:iOS 14
//first,observe the relative notification
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationWillResignActive:)
                                                 name:UIApplicationWillResignActiveNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationWillEnterForeground:)
                                                 name:UIApplicationWillEnterForegroundNotification object:nil];


    //Add an observer to AVPlayerItem,this is the key point!!!
    [playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];

-(void)applicationWillResignActive:(NSNotification *)notification{
    //1 make sure the category of AVAudioSession is AVAudioSessionCategoryPlayback
    AVAudioSession *session=[AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayback  error:nil];
    [session setActive:YES error:nil];
    
    //2 This is important!!!
    //set the avplayerlayer.player = nil.
    mavPlayerLayer.player = nil;
}


//when app becomes active,we should add the player to the avplayerlayer.
-(void)applicationWillEnterForeground:(NSNotification *)notification{
    // restore the avPlayerLayer.player
    mavPlayerLayer.player = mavPlayer;
}


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) {
        NSLog(@"playbackLikelyToKeepUp");
        [mavPlayer play];
    }
}


当然,不要忘记在info.plist文件中添加相关属性以支持后台播放。

info.plist

,

在等待苹果修复它的同时,我有一个临时解决方案:

  1. 请勿使用 UIApplication.didEnterBackgroundNotification UIApplication.willEnterForegroundNotification

  2. 使用 UIApplicationWillResignActiveNotification UIApplication.didBecomeActiveNotification

现在,在“更改应用程序”(向下滑动,将应用程序移至后台)的情况下,它可以正常运行。

但是,当应用程序通过按“锁定按钮”直接进入时不起作用->播放器将暂停音乐,用户必须单击lockScreen上的playButton才能继续(这使用户感到恼火)

-> ***我通过设置autoPlay(应用程序进入后台1次)解决了恼人的问题:

var didEnterBackground:Bool =假,canSkipPausing:Bool =真

//在timerDuration块中(timerDuration用于计算播放秒数):

        if self.didEnterBackground && self.canSkipPausing == true {
            //fix player auto-paused when enter background
            self.canSkipPausing = false
            if self.playerPlayer?.rate == 0.0 {
                self.playerPlayer?.play()
            }
        }

//处理'didEnterBackground'和'canSkipPausing':

@objc
func applicationDidEnterBackground(_ notification: Notification) {
    didEnterBackground = true
    // canSkipPausing = false // remember don't set this here,set it before entering background
    playerLayer?.player = nil
}

@objc
func applicationWillEnterForeground(_ notification: Notification) {
    didEnterBackground = false
    canSkipPausing = true
    playerLayer?.player = playerPlayer
}

//通过这种技巧,当按下设备锁定按钮时,音乐仍然暂停了一点,并在0.5秒后再次自动播放,但至少用户不需要执行任何操作。

,

我终于找到了解决方案。不确定这是iOS 14的bug还是仅是设计缺陷。根据Apple的文档(Special Considerations for Video Media),您需要在进入背景时禁用视频轨道,而在进入前景时将其重新启用。但是我认为他们直到iOS14才真正实施了此建议。这是我完整的示例。

import UIKit
import AVKit

class ViewController: UIViewController
{
    var aPlayer: AVPlayer! = AVPlayer()
    var playButton: UIButton!
    var videoView: UIView!
    var videoFrame: CGRect!
    var active: Bool! = false
    
    override func viewDidLoad()
    {
        super.viewDidLoad()
        videoFrame = CGRect(x: 100,y: 100,width: 640,height: 480)
        self.view.backgroundColor = .blue
        
        // These notifications were send from AppDelegate accordingly.
        NotificationCenter.default.addObserver(self,selector: #selector(fromApplicationWillResignActive),name: NSNotification.Name(rawValue: "ApplicationWillResignActive"),object: nil)
        NotificationCenter.default.addObserver(self,selector: #selector(fromApplicaitonWillEnterForeground),name: NSNotification.Name(rawValue: "ApplicationWillEnterForeground"),object: nil)
        setupUI()
    }
    
    func setupUI()
    {
        playButton = UIButton(type: .custom)
        playButton.frame = CGRect(x: 50,y: 50,width: 100,height: 40)
        playButton.setTitle("Play",for: .normal)
        playButton.showsTouchWhenHighlighted = true
        playButton.addTarget(self,action: #selector(playButtonPressed),for: .touchUpInside)
        self.view.addSubview(playButton)
    }
    
    @objc func playButtonPressed(button: UIButton)
    {
        self.active = true
        
        videoView = UIView(frame: videoFrame)
        videoView.backgroundColor = .purple
        videoView.frame = videoFrame
        self.view.addSubview(videoView)
        
        let videoURL: URL = (Bundle.main.resourceURL?.appendingPathComponent("myfavor1.mp4"))!
        let item = AVPlayerItem(url: videoURL)
        self.aPlayer.replaceCurrentItem(with: item)
        
        let aLayerPlayer = AVPlayerLayer(player: self.aPlayer)
        aLayerPlayer.frame = self.videoView.bounds
        self.videoView.layer.addSublayer(aLayerPlayer)
        self.aPlayer.play()
    }
    
    @objc func fromApplicationWillResignActive(aNotification: NSNotification)
    {
        if self.active
        {
            self.videoView.removeFromSuperview()
            self.videoView = nil
            
            // For iOS 14
            let tracks = self.aPlayer.currentItem!.tracks
            for playerItemTrack in tracks
            {
                if playerItemTrack.assetTrack!.hasMediaCharacteristic(AVMediaCharacteristic.visual)
                {
                    // Disable the track.
                    playerItemTrack.isEnabled = false
                }
            }
        }
    }
    
    @objc func fromApplicaitonWillEnterForeground(aNotification: NSNotification)
    {
        if self.active
        {
            self.videoView = UIView(frame: self.videoFrame)
            self.videoView.backgroundColor = .purple
            let aLayerPlayer = AVPlayerLayer(player: self.aPlayer)
            aLayerPlayer.frame = self.videoView.bounds
            self.videoView.layer.addSublayer(aLayerPlayer)
            self.view.addSubview(self.videoView)
            
//            For iOS 14
            let tracks = self.aPlayer.currentItem!.tracks
            for playerItemTrack in tracks
            {
                if playerItemTrack.assetTrack!.hasMediaCharacteristic(AVMediaCharacteristic.visual)
                {
                    // Disable the track.
                    playerItemTrack.isEnabled = true
                }
            }
        }
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。