【发布时间】:2020-05-20 05:45:27
【问题描述】:
似乎有很多解决方案可以解决这个问题,但这些解决方案都没有对我有用。我目前正在使用 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()
}
以下是我尝试过的所有解决方案:
- Waiting two seconds before calling
self.avPlayer.play()inif options.contains(.shouldResume){} -
Setting
AVAudioSession.sharedInstance().setActiveto false when interruption begins and then setting it ot true when interruption ends。这种方法的问题是if interruption == .ended {}块并不总是被调用,因此设置setActive没有效果。 -
Setting
AVAudioSessionplayback category toAVAudioSessionCategoryOptions.MixWithOthers。反正我的动画没有音频。
我在applicationDidBecomeActive(_:) 中看到过关于恢复播放的提及,但有些人建议不要这样做。这会被认为是好的做法吗?
有没有办法确保else if type == .ended {} 块被执行?或者可能是比观察AVAudioSession.interruptionNotification 更可靠的解决方法?
【问题讨论】:
-
你试过
viewWillAppear或viewDidAppear吗? -
"不能保证开始中断一定会有相应的结束中断。您的应用需要注意切换到前台运行状态或用户按下播放按钮。在任何一种情况下,确定您的应用是否应重新激活其音频会话。” – developer.apple.com/library/archive/documentation/Audio/…
-
@FrankSchlegel 我也尝试了 viewWillAppear 和 vewDidAppear,但它们没有用。
标签: ios avfoundation avplayer swift5 avaudiosession