iOS自定义视频播放器启动画中画(PiP)后立刻停止失效问题求助
问题根因定位
1. PiP启动阶段错误销毁播放器视图
你在playerViewControllerWillStartPictureInPicture(PiP将要启动的回调)中直接调用了playerViewController.dismiss,这个操作会将AVPlayerLayer从视图层级中移除,而PiP和系统Pegasus服务的连接依赖AVPlayerLayer的有效实例,启动流程未完成就移除layer会直接导致XPC连接失效,也就是你控制台输出的4099错误。
2. 未执行PiP恢复回调的completionHandler
pictureInPictureController(_:restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:)方法要求必须调用传入的completionHandler闭包,告知系统恢复操作是否完成,你当前实现完全没有调用这个闭包,系统会判定PiP流程异常,主动终止PiP会话。
修复方案
步骤1:调整PiP启动后的dismiss时机
首先给CustomVideoPlayerViewController的AVPictureInPictureControllerDelegate扩展新增启动完成的回调,把dismiss逻辑移到这个回调里:
extension CustomVideoPlayerViewController: AVPictureInPictureControllerDelegate { func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { videoPlayerDelegate?.playerViewControllerWillStartPictureInPicture(self) } // 新增启动完成回调 func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { videoPlayerDelegate?.playerViewControllerDidStartPictureInPicture(self) } func pictureInPictureControllerWillStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { videoPlayerDelegate?.playerViewControllerWillStopPictureInPicture(self) } func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) { videoPlayerDelegate?.playerViewController(self, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler: completionHandler) }}
步骤2:修改CustomVideoPlayerDelegate的实现
首先把dismiss逻辑移到启动完成的回调里,然后在恢复方法里补全completionHandler的调用:
extension TabBarViewController: CustomVideoPlayerDelegate { func playerViewController(_ playerViewController: UHVideoPlayerViewController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) { shouldReleaseVideoPlayer = false let currentviewController = navigationController?.visibleViewController var restoreSuccess = false if currentviewController != playerViewController, currentviewController != nil { if !(currentviewController?.isKind(of: CustomVideoPlayerViewController.self) ?? false) { currentviewController?.present(playerViewController, animated: false) { restoreSuccess = true // 界面恢复完成后调用completionHandler completionHandler(restoreSuccess) } return } } // 不需要跳转的情况也要调用completionHandler completionHandler(true) } func playerViewControllerWillStartPictureInPicture(_ playerViewController: UHVideoPlayerViewController) { // 移除这里的dismiss逻辑 } // 新增启动完成的代理方法实现 func playerViewControllerDidStartPictureInPicture(_ playerViewController: UHVideoPlayerViewController) { playerViewController.dismiss(animated: true, completion: nil) } func playerViewControllerWillStopPictureInPicture(_ playerViewController: UHVideoPlayerViewController) { if shouldReleaseVideoPlayer { currentVideoPlayer = nil } shouldReleaseVideoPlayer = true }}
步骤3:补充代理方法声明
在CustomVideoPlayerDelegate的协议定义里补充playerViewControllerDidStartPictureInPicture的方法声明即可。
内容的提问来源于stack exchange,提问作者SPS
相关产品推荐
相关产品推荐

