I wrote a method using Flutter MethodChannel to call iOS pip to play videos. It can be played, but the pip window does not appear proactively. When I manually put the app in the background, the pip window appears. So I write a background method to make app enter background(I call it in pictureInPictureControllerDidStartPictureInPicture callback), but it did not execute.
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
let enableControls = true
pipController!.setValue(0, forKey: "controlsStyle")
let enablePlayback = true
pipController!.setValue(0, forKey: "requiresLinearPlayback")
if #available(iOS 14.2, *) {
pipController!.canStartPictureInPictureAutomaticallyFromInline = true
} else {
}
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
}
}
The pip window automatically appears(App enter background automatically)