Flutter PiP Plugin Usage Guide
Introduction
pip is a Flutter plugin that supports Picture in Picture (PiP) functionality for both Android and iOS. It allows applications to continue displaying content in a small window while in the background.
Preview


Installation
Add the dependency in your pubspec.yaml:
dependencies:
  pip: ^latest_version
Platform Specific Setup
Android
Add the following permission to your AndroidManifest.xml:
<activity android:name="VideoActivity"
    android:supportsPictureInPicture="true"
    android:configChanges=
        "screenSize|smallestScreenSize|screenLayout|orientation"
    ...
Basic Usage
import 'package:pip/pip.dart';
final _pip = Pip();
1. Initialization and Feature Check
// Check if device supports PiP
bool isPipSupported = await _pip.isSupported();
// Check if auto-enter PiP mode is supported
bool isPipAutoEnterSupported = await _pip.isAutoEnterSupported();
// Check if currently in PiP mode
bool isPipActived = await _pip.isActived();
2. PiP Configuration
final options = PipOptions(
  autoEnterEnabled: true,      // Enable/disable auto-enter PiP mode
  // Android specific options
  aspectRatioX: 16,           // Aspect ratio X value
  aspectRatioY: 9,            // Aspect ratio Y value
  sourceRectHintLeft: 0,      // Source rectangle left position
  sourceRectHintTop: 0,       // Source rectangle top position
  sourceRectHintRight: 1080,  // Source rectangle right position
  sourceRectHintBottom: 720,  // Source rectangle bottom position
  // iOS specific options
  sourceContentView: 0,        // Source content view
  contentView: 0,             // Content view to be displayed in PiP
  preferredContentWidth: 480,  // Preferred content width
  preferredContentHeight: 270, // Preferred content height
  controlStyle: 2,            // Control style for PiP window
);
await _pip.setup(options);
3. PiP State Monitoring
await _pip.registerStateChangedObserver(
  PipStateChangedObserver(
    onPipStateChanged: (state, error) {
      switch (state) {
        case PipState.pipStateStarted:
          print('PiP started successfully');
          break;
        case PipState.pipStateStopped:
          print('PiP stopped');
          break;
        case PipState.pipStateFailed:
          print('PiP failed: $error');
          break;
      }
    },
  )
);
4. PiP Lifecycle Management
// Start PiP mode
await _pip.start();
// Stop PiP mode
await _pip.stop();
// Release PiP resources
await _pip.dispose();
API Reference
PipOptions
PipOptions({
  bool? autoEnterEnabled,      // Enable/disable auto-enter PiP mode (default: false)
  
  // Android specific options
  int? aspectRatioX,          // Aspect ratio X value
  int? aspectRatioY,          // Aspect ratio Y value
  int? sourceRectHintLeft,    // Source rectangle left position
  int? sourceRectHintTop,     // Source rectangle top position
  int? sourceRectHintRight,   // Source rectangle right position
  int? sourceRectHintBottom,  // Source rectangle bottom position
  bool? seamlessResizeEnabled, // Enable/disable seamless resize (default: false)
  bool? useExternalStateMonitor, // Use external state monitor (default: false)
  int? externalStateMonitorInterval, // External state monitor interval in milliseconds (default: 100)
  
  // iOS specific options
  int? sourceContentView,      // Source content view
  int? contentView,           // Content view to be displayed in PiP
  int? preferredContentWidth, // Preferred content width
  int? preferredContentHeight,// Preferred content height
  int? controlStyle,          // Control style for PiP window
                              // 0: default show all system controls
                              // 1: hide forward and backward button
                              // 2: hide play pause button and the progress bar including forward and backward button (recommended)
                              // 3: hide all system controls including the close and restore button
})
PiP States
enum PipState {
  pipStateStarted,  // PiP mode is active
  pipStateStopped,  // PiP mode is stopped
  pipStateFailed    // PiP operation failed
}
Core Methods
Check PiP Support
// Check basic PiP support
Future<bool> isSupported()
// Check auto-enter PiP support
Future<bool> isAutoEnterSupported()
// Check if PiP is currently active
Future<bool> isActived()
PiP Lifecycle Management
// Setup or update PiP configuration
Future<bool> setup(PipOptions options)
// Start PiP mode
Future<bool> start()
// Stop PiP mode
Future<void> stop()
// Clean up PiP resources
Future<void> dispose()
State Management
// Register state change observer
Future<void> registerStateChangedObserver(
  PipStateChangedObserver observer
)
// Unregister state change observer
Future<void> unregisterStateChangedObserver()
Platform-Specific Considerations
Android
- All aspect ratio and source rectangle configurations are Android-specific
- Source rectangle hints help smooth transitions into PiP mode
- pipStop()operation only switches the app to background
- Ensure necessary permissions are declared in the app
- Additional Android-specific features:
- seamlessResizeEnabled: Enable smooth resizing of PiP window
- useExternalStateMonitor: Use external thread to monitor PiP state
- externalStateMonitorInterval: Set monitoring interval in milliseconds
 
iOS
- Content view and dimension settings are iOS-specific
- Call pipStart()when the app enters background (AppLifecycleState.inactive)
- Call pipStop()when the app returns to foreground (AppLifecycleState.resumed)
- Recommended to use autoEnterEnabledfor automatic PiP mode entry
- The contentViewwill be added to the PiP view after setup, and you are responsible for rendering the content view
- Choose appropriate controlStylebased on your needs:- Style 0: Shows all system controls (default)
- Style 1: Hides forward and backward buttons
- Style 2: Hides play/pause button and progress bar (recommended)
- Style 3: Hides all system controls including close and restore buttons
 
- How to set the size of the PiP window? Just set the preferredContentWidthandpreferredContentHeightin thePipOptions
Best Practices
- Platform-Specific Configuration
if (Platform.isAndroid) {
  options = PipOptions(
    autoEnterEnabled: true,
    aspectRatioX: 16,
    aspectRatioY: 9,
  );
} else if (Platform.isIOS) {
  options = PipOptions(
    autoEnterEnabled: true,
    contentView: someView,
    sourceContentView: someOtherView,
    preferredContentWidth: 480,
    preferredContentHeight: 270,
    controlStyle: 2,
  );
}
- Proper Resource Management
@override
void dispose() {
  _pip.unregisterStateChangedObserver();
  _pip.dispose();
  super.dispose();
}
- Error Handling
try {
  await _pip.start();
} catch (e) {
  print('Error starting PiP: $e');
}
Common Issues
- 
PiP Won't Start - Verify device supports PiP
- Confirm PiP parameters are set correctly
- Check error callback messages
 
- 
Auto-Enter Mode Not Working - Confirm device supports auto-enter functionality
- Verify autoEnterEnabledsetting
 
- 
PiP Window Ratio Issues - Ensure correct aspect ratio settings
- Be aware of platform-specific limitations
 
Tips for Implementation
- Always check device compatibility before enabling PiP features
- Implement proper error handling for better user experience
- Consider platform differences when implementing PiP functionality
- Test thoroughly on both Android and iOS devices
- Handle app lifecycle changes appropriately