zego_pip 0.0.3 copy "zego_pip: ^0.0.3" to clipboard
zego_pip: ^0.0.3 copied to clipboard

A Flutter Picture-in-Picture (PIP) plugin based on `zego_express_engine`, supporting iOS and Android platforms .

zego_pip #

A Flutter Picture-in-Picture (PIP) plugin based on zego_express_engine, supporting iOS and Android platforms.

English | δΈ­ζ–‡

Demo #

iOS Platform #

iOS PIP Demo

Android Platform #

Android PIP Demo

Features #

  • πŸŽ₯ Cross-platform Support: Supports iOS 15.0+ and Android 8.0+
  • πŸš€ Ready to Use: Zero configuration, one-click PIP enablement
  • πŸ”„ Auto Switching: Intelligent PIP mode switching
  • 🎯 Performance Optimized: Built-in video rendering optimization and memory management

Installation #

1. Add Dependencies #

Add to pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  zego_pip: ^0.0.1
  zego_express_engine: ^3.21.0

2. Install Dependencies #

flutter pub get

3. iOS Configuration #

Set minimum version in ios/Podfile:

platform :ios, '13.0'

Then run:

cd ios
pod install
cd ..

4. Android Configuration #

Ensure minSdkVersion in android/app/build.gradle is at least 21:

android {
    defaultConfig {
        minSdkVersion 21
    }
}

Add android:supportsPictureInPicture="true" to the <activity> tag in android/app/src/main/AndroidManifest.xml:

<manifest>
  <application>
    <activity
      android:name=".MainActivity"
      android:supportsPictureInPicture="true"
      ...
    />
  </application>
</manifest>

Android Permissions

The plugin automatically adds the following necessary permissions to your app:

Permission Category Permission Name Purpose Minimum API Level
Network Permissions android.permission.INTERNET Network access for video streaming API 1
android.permission.ACCESS_NETWORK_STATE Network state access API 1
android.permission.ACCESS_WIFI_STATE WiFi state access API 1
Audio Permissions android.permission.RECORD_AUDIO Audio recording for audio capture API 1
android.permission.MODIFY_AUDIO_SETTINGS Audio settings modification API 1
Camera Permissions android.permission.CAMERA Camera access for video capture API 1
Foreground Service Permissions android.permission.FOREGROUND_SERVICE Foreground service for background PIP API 26
android.permission.FOREGROUND_SERVICE_MICROPHONE Foreground service microphone API 34
android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION Foreground service media projection API 34
System Permissions android.permission.SYSTEM_ALERT_WINDOW System overlay for PIP window display API 1

Quick Start #

1. Initialize #

Method 1: zego_pip Internal Engine Creation

import 'package:zego_pip/zego_pip.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await ZegoPIP().init(
    /// zego_pip internally creates the express engine, listens for events, and logs into the room
    expressConfig: ZegoPIPExpressConfig(
      create: ZegoPIPExpressCreateConfig(
        // Please fill in your own app id
        appID: 1234567890,
        // Please fill in your own app sign
        appSign: 'your_app_sign_here',
      ),
      room: ZegoPIPExpressRoomConfig(
        // Please fill in your own room id
        roomID: 'test_room_id',
        // Please fill in your own room login user info
        userID: 'test_user_id',
        userName: 'test_user_name',
      ),
    ),
  );

  runApp(
    const MaterialApp(
      home: Scaffold(
        // Please fill in your own stream id
        body: Center(child: ZegoPIPVideoView(streamID: 'test_stream_id')),
      ),
    ),
  );
}

Method 2: External Engine Creation(Recommended)

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:zego_express_engine/zego_express_engine.dart';
import 'package:zego_pip/zego_pip.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await ZegoExpressManager().init();

  /// Before ZegoPIP.init, you must first create the express engine
  await ZegoPIP().init(
    expressConfig: ZegoPIPExpressConfig(
      event: ZegoExpressManager().pipExpressEvent,
    ),
  );

  /// ZegoPIPVideoView can only be rendered after logging into the room from other parts of the app
  await ZegoExpressManager().loginRoom();

  runApp(
    const MaterialApp(
      home: Scaffold(
        /// Please fill in your own stream id
        body: Center(child: ZegoPIPVideoView(streamID: 'test_stream_id')),
      ),
    ),
  );
}

class ZegoExpressManager {
  factory ZegoExpressManager() {
    return shared;
  }

  static final ZegoExpressManager shared = ZegoExpressManager._internal();
  ZegoExpressManager._internal();

  var pipExpressEvent = ZegoPIPExpressEvent();

  Future<void> init() async {
    ZegoExpressEngine.onEngineStateUpdate = onEngineStateUpdate;
    ZegoExpressEngine.onDebugError = onDebugError;
    ZegoExpressEngine.onRoomStreamUpdate = onRoomStreamUpdate;
    ZegoExpressEngine.onRoomStateChanged = onRoomStateChanged;
    ZegoExpressEngine.onPlayerStateUpdate = onPlayerStateUpdate;
    ZegoExpressEngine.onRemoteCameraStateUpdate = onRemoteCameraStateUpdate;
    ZegoExpressEngine.onRemoteMicStateUpdate = onRemoteMicStateUpdate;

    await ZegoExpressEngine.createEngineWithProfile(
      ZegoEngineProfile(
        1234567890,
        ZegoScenario.Default,
        appSign: 'your app sign',
        /// Please ensure that `enablePlatformView` is set to true
        enablePlatformView: true,
      ),
    );
  }

  Future<bool> loginRoom() async {
    final result = await ZegoExpressEngine.instance.loginRoom(
      /// Please fill in your own room id
      'test_room_id',
      ZegoUser(
        /// Please fill in your own room login user info
        'test_user_id',
        'test_user_name',
      ),
      config: ZegoRoomConfig(0, true, ''),
    );

    return 0 == result.errorCode;
  }

  /// Forward express event to zego_pip
  void onEngineStateUpdate(ZegoEngineState state) {
    pipExpressEvent.onEngineStateUpdate?.call(state);
  }

  void onDebugError(int errorCode, String funcName, String info) {
    pipExpressEvent.onDebugError?.call(errorCode, funcName, info);
  }

  void onRoomStreamUpdate(
    String roomID,
    ZegoUpdateType updateType,
    List<ZegoStream> streamList,
    Map<String, dynamic> extendedData,
  ) {
    pipExpressEvent.onRoomStreamUpdate?.call(
      roomID,
      updateType,
      streamList,
      extendedData,
    );
  }

  void onRoomStateChanged(
    String roomID,
    ZegoRoomStateChangedReason reason,
    int errorCode,
    Map<String, dynamic> extendedData,
  ) {
    pipExpressEvent.onRoomStateChanged?.call(
      roomID,
      reason,
      errorCode,
      extendedData,
    );
  }

  void onPlayerStateUpdate(
    String streamID,
    ZegoPlayerState state,
    int errorCode,
    Map<String, dynamic> extendedData,
  ) {
    pipExpressEvent.onPlayerStateUpdate?.call(
      streamID,
      state,
      errorCode,
      extendedData,
    );
  }

  void onRemoteCameraStateUpdate(String streamID, ZegoRemoteDeviceState state) {
    pipExpressEvent.onRemoteCameraStateUpdate?.call(streamID, state);
  }

  void onRemoteMicStateUpdate(String streamID, ZegoRemoteDeviceState state) {
    pipExpressEvent.onRemoteMicStateUpdate?.call(streamID, state);
  }
}

2. Use Video Component #

class VideoPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Video Room')),
      body: ZegoPIPVideoView(
        streamID: 'stream_id',
        // PIP functionality automatically enabled
      ),
    );
  }
}

3. Manual PIP Control (Optional) #

class PIPController {
  final zegoPIP = ZegoPIP();
  
  // Enable PIP
  Future<void> enablePIP() async {
    await zegoPIP.enable();
  }
  
  // Update PIP source
  Future<void> updatePIPSource(String streamID) async {
    await zegoPIP.updateIOSPIPSource(streamID);
  }
  
  // Stop PIP
  Future<bool> stopPIP() async {
    return await zegoPIP.stopPIP();
  }
  
  // Check if in PIP mode
  Future<bool> isInPIP() async {
    return await zegoPIP.isInPIP();
  }
}

πŸ“– API Documentation

Platform Support #

iOS #

  • Minimum Version: iOS 13.0
  • PIP Support: iOS 15.0+
  • Features: Native AVPictureInPictureController support

Android #

  • Minimum Version: Android 8.0 (API 26)
  • PIP Support: Android 8.0+
  • Features: Native PictureInPicture mode support

FAQ #

Q: Why doesn't PIP functionality work? #

A: Please check:

  1. Whether the plugin is properly initialized
  2. Whether iOS version supports PIP (iOS 15.0+)
  3. Whether Android version supports PIP (Android 8.0+)
  4. Whether zego_express_engine dependency is added

Q: How to handle PIP mode switching? #

A: The plugin automatically handles mode switching, no manual intervention required.

Q: How to customize PIP interface? #

  • Android: You can use ZegoPIPVideoView as a normal Widget in your widget tree.
  • iOS: Currently the plugin uses system default PIP interface, customization is not supported yet.

Known Issues #

  • When the remote stream camera is not enabled and ZegoPIPVideoView is rendered, the first desktop minimization after the remote stream enables camera will not show PIP window

Contributing #

Issues and Pull Requests are welcome!

License #

This project is licensed under the MIT License.

1
likes
160
points
199
downloads
screenshot

Publisher

unverified uploader

Weekly Downloads

A Flutter Picture-in-Picture (PIP) plugin based on `zego_express_engine`, supporting iOS and Android platforms .

Homepage
Repository (GitHub)

Topics

#pip

Documentation

API reference

License

MIT (license)

Dependencies

floating, flutter, plugin_platform_interface, zego_express_engine

More

Packages that depend on zego_pip