5

I'm building an OTT video streaming app using Flutter and the video_player package. I want to implement Picture-in-Picture (PiP) on iOS.

Flutter doesn’t provide native PiP support for iOS directly, so I implemented it using Swift native code through a custom plugin.

The issue I’m facing is:

When I manually tap my custom PiP button, PiP starts successfully and works fine.

But when I put the app in the background (home button / swipe up) and try to start PiP automatically, PiP doesn’t appear — even though it seems to start internally.

This is my IosPipManager(swift)

import Foundation
import AVKit
import Flutter
public class IosPipManager: NSObject, FlutterPlugin {
private var pipController: AVPictureInPictureController?
private var playerLayer: AVPlayerLayer?
private var methodChannel: FlutterMethodChannel?
 public static func register(with registrar: FlutterPluginRegistrar) {
 let instance = IosPipManager()
 let channel = FlutterMethodChannel(name: "ios_pip_manager", binaryMessenger: registrar.messenger())
 instance.methodChannel = channel
 registrar.addMethodCallDelegate(instance, channel: channel)
 
 NotificationCenter.default.addObserver(
 instance,
 selector: #selector(instance.appDidEnterBackground),
 name: UIApplication.didEnterBackgroundNotification,
 object: nil
 )
 }
 
 @objc private func appDidEnterBackground() {
 guard let controller = pipController else {
 print("❌ No PiP controller when entering background")
 return
 }
 
 DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
 if !controller.isPictureInPictureActive {
 print("🎥 Starting PiP automatically on background")
 controller.startPictureInPicture()
 }
 }
 }
 
 public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
 switch call.method {
 case "initializePip":
 print("🎬 Initializing PiP from Flutter video_player")
 
 guard let viewController = UIApplication.shared.delegate?.window??.rootViewController else {
 result(FlutterError(code: "NO_VIEW", message: "No root view controller", details: nil))
 return
 }
 
 if let playerLayer = findPlayerLayer(in: viewController.view.layer) {
 print("✅ Found AVPlayerLayer from Flutter player")
 self.playerLayer = playerLayer
 self.pipController = AVPictureInPictureController(playerLayer: playerLayer)
 result(true)
 } else {
 print("❌ Couldn’t find AVPlayerLayer from Flutter video player")
 result(FlutterError(code: "NO_PLAYER_LAYER", message: "Couldn't find AVPlayerLayer from Flutter video player", details: nil))
 }
 
 case "startPip":
 print("▶️ startPip called")
 startPip(result: result)
 
 case "stopPip":
 print("⏹ stopPip called")
 stopPip(result: result)
 
 default:
 result(FlutterMethodNotImplemented)
 }
 }
 
 private func startPip(result: @escaping FlutterResult) {
 guard let controller = pipController else {
 result(FlutterError(code: "NOT_INITIALIZED", message: "PiP controller not initialized", details: nil))
 return
 }
 
 if !controller.isPictureInPictureActive {
 controller.startPictureInPicture()
 }
 result(true)
 }
 
 private func stopPip(result: @escaping FlutterResult) {
 guard let controller = pipController else {
 result(FlutterError(code: "NOT_INITIALIZED", message: "PiP controller not initialized", details: nil))
 return
 }
 
 if controller.isPictureInPictureActive {
 controller.stopPictureInPicture()
 }
 result(true)
 }
 
 private func findPlayerLayer(in layer: CALayer) -> AVPlayerLayer? {
 if let playerLayer = layer as? AVPlayerLayer {
 return playerLayer
 }
 for sublayer in layer.sublayers ?? [] {
 if let found = findPlayerLayer(in: sublayer) {
 return found
 }
 }
 return nil
 }
}
extension IosPipManager: AVPictureInPictureControllerDelegate {
public func pictureInPictureControllerDidStartPictureInPicture(\_ pictureInPictureController: AVPictureInPictureController) {
methodChannel?.invokeMethod("onPipStarted", arguments: nil)
}
 public func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
 methodChannel?.invokeMethod("onPipStopped", arguments: nil)
 }
 
 public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) {
 methodChannel?.invokeMethod("onPipError", arguments: error.localizedDescription)
 }
}
Akhil George
9701 gold badge10 silver badges33 bronze badges
asked 2 days ago
New contributor
Rupam Das is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
1
  • For android some packages are there, but in ios no package is working Commented yesterday

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.