native_picture_in_picture 1.0.1 copy "native_picture_in_picture: ^1.0.1" to clipboard
native_picture_in_picture: ^1.0.1 copied to clipboard

A Flutter plugin for native Picture-in-Picture (PiP) on Android and iOS. Uses ExoPlayer and AVKit for smooth, reliable PiP with full lifecycle events and auto-PiP support.

native_picture_in_picture #

pub package Platform License: MIT

A Flutter plugin for native Picture-in-Picture (PiP) on Android (API 26+) and iOS (14+).

    

  • 🤖 Android uses ExoPlayer with a hardware-accelerated full-screen SurfaceView overlay.
  • 🍎 iOS uses AVKit (AVPictureInPictureController).
  • 🔄 Full sync API: seek, play, pause the native player to match your Flutter video player.
  • 📡 Lifecycle events stream: willStart, didStart, willStop, didStop, restoreUI.
  • 🏠 Auto-PiP on iOS when the user swipes home.
  • 🎵 No double audio — native player is carefully managed to never clash with your Flutter player.

Platform Requirements #

Platform Minimum Version
Android API 26 (Android 8.0)
iOS 14.0

Setup #

iOS #

Add the audio background mode to your Info.plist. This is required by iOS for the PiP session to stay active when the app is in the background:

<key>UIBackgroundModes</key>
<array>
    <string>audio</string>
</array>

Android #

1. Use FlutterFragmentActivity

Important: This plugin uses addOnPictureInPictureModeChangedListener, which is only available on ComponentActivity. The default MainActivity extends FlutterActivity, which does not inherit from ComponentActivity. You must change your MainActivity to extend FlutterFragmentActivity, otherwise no PiP events will be emitted.

In android/app/src/main/kotlin/.../MainActivity.kt:

-import io.flutter.embedding.android.FlutterActivity
-class MainActivity : FlutterActivity()
+import io.flutter.embedding.android.FlutterFragmentActivity
+class MainActivity : FlutterFragmentActivity()

2. Declare PiP support in AndroidManifest.xml

<activity
    android:name=".MainActivity"
    android:supportsPictureInPicture="true"
    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
    ...>

Usage #

Basic Example #

import 'dart:io';
import 'package:native_picture_in_picture/native_picture_in_picture.dart';
import 'package:native_picture_in_picture/pip_event.dart';

final pip = NativePictureInPicture();

// 1. Check support
final supported = await pip.isPipSupported();
if (!supported) return;

// 2. Initialize with your video URL
await pip.initialize('https://example.com/video.mp4');

// 3. Disable auto-PiP on Android (recommended — see notes below)
if (Platform.isAndroid) {
  await pip.setAutoPipEnabled(false);
}

// 4. Listen to lifecycle events
pip.onPipEvent.listen((event) async {
  if (event == PipEvent.willStart) {
    // Pause your Flutter video player here
    _videoController.pause();
  } else if (event == PipEvent.restoreUI || event == PipEvent.didStop) {
    // Get the position the native player stopped at
    final position = await pip.getPosition();
    await pip.pause(); // silence native player
    await _videoController.seekTo(position);
    _videoController.play();
  }
});

// 5. Sync position and start PiP
await pip.seekTo(_videoController.value.position);
await pip.startPiP();

// 6. Dispose when done
await pip.dispose();

Keeping the Native Player in Sync #

To ensure Auto-PiP on iOS always starts from the right position, add a listener to your Flutter video controller:

_videoController.addListener(() {
  if (_isPipActive) return; // don't interfere while PiP is running
  if (!_videoController.value.isPlaying) {
    pip.pause();
    pip.seekTo(_videoController.value.position);
  }
});

API Reference #

NativePictureInPicture #

Method Returns Description
isPipSupported() Future<bool> Returns true if the device supports PiP
initialize(url) Future<void> Loads the video URL into the native player
startPiP() Future<void> Enters Picture-in-Picture mode
stopPiP() Future<void> Exits Picture-in-Picture mode
isPipActive() Future<bool> Returns true if PiP is currently active
seekTo(Duration) Future<void> Seeks the native player to a position
getPosition() Future<Duration> Gets the current native player position
play() Future<void> Plays the native player
pause() Future<void> Pauses the native player
setAutoPipEnabled(bool) Future<void> Enables/disables auto-PiP on home swipe
dispose() Future<void> Releases all native resources
onPipEvent Stream<PipEvent> Stream of PiP lifecycle events

PipEvent #

Event iOS Android Description
willStart PiP window is about to appear
didStart PiP window is now active
willStop PiP window is about to close
didStop PiP window has fully closed (app is finishing)
restoreUI User tapped the expand button to return to the app

Notes #

Android Auto-PiP #

Android Auto-PiP (via setAutoEnterEnabled) shows whatever the Activity looks like at the moment of backgrounding — which would be the Flutter UI, not your video. For this reason, setAutoPipEnabled(false) is recommended on Android. Use the manual startPiP() button instead.

iOS Auto-PiP #

On iOS, setAutoPipEnabled(true) (the default) enables seamless Auto-PiP when the user swipes home. The plugin handles this automatically via the willResignActive notification.

Why a separate native player? #

Flutter's video_player uses a platform texture that cannot be displayed inside a system PiP window. This plugin runs a second, native player (ExoPlayer / AVPlayer) that provides the video surface for the PiP window. Use the sync API (seekTo, getPosition, play, pause) to keep both players in lockstep.

9
likes
160
points
182
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin for native Picture-in-Picture (PiP) on Android and iOS. Uses ExoPlayer and AVKit for smooth, reliable PiP with full lifecycle events and auto-PiP support.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on native_picture_in_picture

Packages that implement native_picture_in_picture