如何实现iOS画中画(PiP)窗口自动弹出?Flutter调用iOS PiP问题求助
iOS Flutter MethodChannel PiP 自动弹出问题修复
问题现象
通过Flutter MethodChannel调用iOS PiP功能播放视频,视频可正常播放,但PiP窗口无法主动弹出;手动将App切换至后台时,PiP窗口才会出现。尝试在pictureInPictureControllerDidStartPictureInPicture回调中调用自定义的background()方法让App进入后台,但该回调未执行。
原代码片段
private var player: AVPlayer? private var playerLayer: AVPlayerLayer? private var pipController : AVPictureInPictureController? private var channel: FlutterMethodChannel private var flutterView: UIView? private var flutterWindow: UIWindow? public func background() { let targetSelect = #selector(NSXPCConnection.suspend) if UIApplication.shared.responds(to: targetSelect) { UIApplication.shared.perform(targetSelect) } } public func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { background() } public func enterPiPMode(arguments: Any?,result: @escaping FlutterResult){ dispose() if(isAvailable()){ flutterWindow = windows()?.filter { window in window.isKeyWindow }.first flutterView = flutterWindow?.rootViewController?.view if let args = arguments as? [String: Any] { let iOSPlayUrl = args["iOSPlayUrl"] as? String ?? "" if(iOSPlayUrl.isEmpty){ print("PiPVideoPlugin error : iOSPlayUrl is Empty") result(false) return } do { let audioSession = AVAudioSession.sharedInstance() try audioSession.setCategory(.playAndRecord, options:.mixWithOthers) try audioSession.setActive(true) } catch { print("PiPVideoPlugin error : AVAudioSession.sharedInstance") result(false) return } playerLayer = AVPlayerLayer() playerLayer!.frame = .init(x: 0, y: 0, width: 1, height: 1) player = AVPlayer(playerItem: AVPlayerItem(url: URL(string: iOSPlayUrl)!)) player!.isMuted = false player!.allowsExternalPlayback = true player!.accessibilityElementsHidden = true playerLayer!.player = player pipController = AVPictureInPictureController(playerLayer: playerLayer!) pipController!.delegate = self pipController!.setValue(0, forKey: "controlsStyle") pipController!.setValue(0, forKey: "requiresLinearPlayback") if #available(iOS 14.2, *) { pipController!.canStartPictureInPictureAutomaticallyFromInline = true } player!.play() flutterView?.layer.addSublayer(playerLayer!) DispatchQueue.main.async { self.pipController!.startPictureInPicture() result(true) } } else { print("PiPVideoPlugin error : arguments error") result(false) return } }else{ print("PiPVideoPlugin error : PiP is not available") result(false) return } }
问题分析
- 回调未触发:
pictureInPictureControllerDidStartPictureInPicture仅在PiP成功启动后回调,若前台启动PiP时系统未立即触发该状态(iOS前台默认不会自动显示PiP窗口),回调不会执行。 - 私有API风险:使用
NSXPCConnection.suspend强制后台是私有API行为,存在审核不通过风险,且执行不稳定。 - 系统限制:iOS默认要求用户主动切换后台才会显示PiP窗口,
canStartPictureInPictureAutomaticallyFromInline仅针对inline视频场景生效,无法直接触发App后台。
修复方案
1. 替换合规的后台触发方法
将私有API替换为公开的resignActive方法,合法让App进入非活跃状态:
public func background() { UIApplication.shared.perform(#selector(UIApplication.resignActive)) }
2. 调整PiP启动与后台触发时机
延迟调用startPictureInPicture()确保视频渲染完成,再延迟触发后台操作,避免PiP未启动时执行后台:
// 替换原DispatchQueue代码 DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.pipController?.startPictureInPicture() // 延迟确保PiP状态已激活 DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { self.background() } result(true) }
3. 优化音频会话配置
若无需录音功能,将音频会话类别改为.playback,减少权限依赖:
do { let audioSession = AVAudioSession.sharedInstance() try audioSession.setCategory(.playback, options: .mixWithOthers) try audioSession.setActive(true) } catch { print("PiPVideoPlugin error : AVAudioSession setup failed") result(false) return }
4. 监听PiP状态变化(可选)
添加状态监听确保PiP启动后再执行后台:
// 在初始化pipController后添加监听 if #available(iOS 13.0, *) { pipController?.addObserver(self, forKeyPath: "isPictureInPictureActive", options: [.new], context: nil) } // 实现监听方法 override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "isPictureInPictureActive", let isActive = change?[.newKey] as? Bool, isActive { background() // 移除监听避免内存泄漏 pipController?.removeObserver(self, forKeyPath: "isPictureInPictureActive") } }
内容的提问来源于stack exchange,提问作者lycstar
相关产品推荐
相关产品推荐

