在解决这一问题上似乎有许多解决办法,但这些解决办法对我都没有奏效。我现在正在使用Swift 5,我有一个AVPlayer在我的ViewController中播放一个动画(循环)。当调用通过CallKit进入时,无论我是响应还是拒绝调用,AVPlayer播放的动画在呼叫处理完毕后都不会恢复。中断处理程序似乎在中断之前被调用,但通常在中断之后不被调用。
override func viewDidLoad() {
super.viewDidLoad()
prepareBGVideo()
...
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationWillEnterForeground(notification:)),
name: UIApplication.willEnterForegroundNotification,
object: nil)
...
}
func prepareBGVideo() {
guard let path = Bundle.main.path(forResource: "animation", ofType:"mp4") else {
print("video not found")
return
}
let item = AVPlayerItem(url: URL(fileURLWithPath: path))
avPlayer = AVPlayer(playerItem: item)
NotificationCenter.default.addObserver(self,
selector: #selector(loopVideoBG),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: item)
NotificationCenter.default.addObserver(self, selector: #selector(handleInterruption(notification:)), name: AVAudioSession.interruptionNotification, object: nil)
avPlayerLayer = AVPlayerLayer(player: avPlayer)
avPlayerLayer.backgroundColor = UIColor.black.cgColor
avPlayer.volume = 0
avPlayer.actionAtItemEnd = .none
avPlayer.play()
view.backgroundColor = .clear
avPlayerLayer.frame = view.layer.bounds
view.layer.insertSublayer(avPlayerLayer, at: 0)
avPlayerLayer.videoGravity = isIPAD ? AVLayerVideoGravity.resize : AVLayerVideoGravity.resizeAspectFill // Changed from AVLayerVideoGravity.resizeAspect to AVLayerVideoGravity.resize so that video fits iPad screen
NotificationCenter.default.addObserver(self,
selector: #selector(willEnterForeground),
name: UIApplication.willEnterForegroundNotification,
object: nil)
}
@objc func handleInterruption(notification: Notification) {
guard let info = notification.userInfo,
let typeValue = info[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
return
}
if type == .began {
// Interruption began, take appropriate actions (save state, update user interface)
self.avPlayer.pause()
} else if type == .ended {
guard let optionsValue =
info[AVAudioSessionInterruptionOptionKey] as? UInt else {
return
}
let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
if options.contains(.shouldResume) {
// Interruption Ended - playback should resume
self.avPlayer.play()
}
}
}
/// Resume video while app wake up from background
@objc func willEnterForeground() {
avPlayer.seek(to: CMTime.zero)
JPUtility.shared.performOperation(0.1) {
self.avPlayer.play()
}
}
@objc func loopVideoBG() {
avPlayer.seek(to: CMTime.zero)
avPlayer.play()
}以下是我尝试过的所有解决方案:
self.avPlayer.play() in if options.contains(.shouldResume){}AVAudioSession.sharedInstance().setActive to false when interruption begins and then setting it ot true when interruption ends.这种方法的问题是,if interruption == .ended {}块并不总是被调用,所以设置setActive时没有反正我的动画没有音频。我在applicationDidBecomeActive(_:)中见过恢复播放的例子,但有些人建议不要这样做。这是否被视为良好做法?
是否有办法确保执行else if type == .ended {}块?或者是一个比观察AVAudioSession.interruptionNotification更可靠的解决方案。
发布于 2020-02-08 11:31:18
我解决了这个问题,但是创建了一个共享的VideoPlayer类,其中包含了对所有有动画的屏幕的引用。
import Foundation
import UIKit
import AVKit
class VideoPlayer: NSObject {
static var shared: VideoPlayer = VideoPlayer()
var avPlayer: AVPlayer!
var avPlayerLayer: AVPlayerLayer!
weak var vcForConnect:ConnectVC?
weak var vcForList:ListVC?
override init() {
super.init()
guard let path = Bundle.main.path(forResource: "animation", ofType:"mp4") else {
print("video not found")
return
}
avPlayer = AVPlayer(url: URL(fileURLWithPath: path))
avPlayerLayer = AVPlayerLayer(player: avPlayer)
avPlayerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
avPlayer.volume = 0
avPlayer.actionAtItemEnd = .none
loopVideo(videoPlayer: avPlayer)
avPlayer.play()
NotificationCenter.default.addObserver(self, selector: #selector(handleInterruption(notification:)), name: AVAudioSession.interruptionNotification, object: nil)
}
deinit {
avPlayer.pause()
}
@objc func handleInterruption(notification: Notification) {
guard let info = notification.userInfo,
let typeValue = info[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
return
}
if type == .began {
// Interruption began, take appropriate actions (save state, update user interface)
self.avPlayer.pause()
} else if type == .ended {
guard let optionsValue =
info[AVAudioSessionInterruptionOptionKey] as? UInt else {
return
}
let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
if options.contains(.shouldResume) {
// Interruption Ended - playback should resume
self.avPlayer.play()
}
}
}
func resumeAllAnimations() {
self.avPlayer.play()
if vcForList?.avPlayer != nil {
vcForList?.avPlayer.play()
}
if vcForConnect?.avPlayer != nil {
vcForConnect?.avPlayer.play()
}
if vcForConnect?.avPlayerBG != nil {
vcForConnect?.avPlayerBG.play()
}
}
...
}然后,通过在resumeAllAnimations()中调用applicationDidBecomeActive(_:)中的AppDelegate.swift来恢复动画,如下所示:
func applicationDidBecomeActive(_ application: UIApplication) {
VideoPlayer.shared.resumeAllAnimations()
...
}https://stackoverflow.com/questions/60056690
复制相似问题