Polyv Help Center

Help Center

Polyv Flutter Media Player - Project Documentation

Updated: 2026-05-14 11:19:41

A Flutter video player plugin based on the Polyv iOS VOD Player SDK, supporting both iOS and Android platforms.

Table of Contents


Project Overview

polyv-flutter-media-player-demo is a Flutter Plugin project that wraps the Polyv native player SDK (iOS PolyvMediaPlayerSDK, Android media-player-full) into a unified Dart API for cross-platform calls from Flutter applications.

The project is divided into two layers:

Layer Directory Responsibility
Plugin Layer polyv_media_player/ Core playback capabilities + shareable business service modules, no business UI
Demo App Layer example/ Complete UI implementation (player skin, control bar, danmaku, subtitles, etc.), for customer reference and copying

Tech Stack

Category Technology
Framework Flutter (Dart SDK ^3.9.0)
State Management Provider (ChangeNotifier pattern)
iOS Native SDK PolyvMediaPlayerSDK ~> 2.7.2 (Objective-C)
Android Native SDK net.polyv.android:media-player-full:2.7.2 (Kotlin)
Cross-platform Communication Flutter Platform Channel (MethodChannel + EventChannel)
Dependencies http, crypto, shared_preferences, provider

Underlying SDK Reference

Documentation for the Polyv native SDK wrapped by this plugin:


Architecture Design

┌─────────────────────────────────────────────────────────┐
│                    Demo App (example/)                    │
│  ┌──────────┐ ┌──────────────┐ ┌────────────────────┐   │
│  │ HomePage │ │ LongVideoPage│ │ DownloadCenterPage │   │
│  └──────────┘ └──────────────┘ └────────────────────┘   │
└────────────────────────┬────────────────────────────────┘
                         │ 依赖
┌────────────────────────▼────────────────────────────────┐
│                Plugin (polyv_media_player/)               │
│                                                          │
│  ┌─────────────────────────────────────────────────┐     │
│  │  Widgets Layer                                   │     │
│  │  PolyvVideoPlayer · PolyvVideoView               │     │
│  └───────────────────┬─────────────────────────────┘     │
│                      │                                    │
│  ┌───────────────────▼─────────────────────────────┐     │
│  │  UI Components                                   │     │
│  │  ControlBar · ProgressSlider · QualitySelector   │     │
│  │  SpeedSelector · Danmaku · Gestures · Settings   │     │
│  └───────────────────┬─────────────────────────────┘     │
│                      │                                    │
│  ┌───────────────────▼─────────────────────────────┐     │
│  │  Core Layer                                      │     │
│  │  PlayerController · PlayerState · PlayerEvents   │     │
│  └───────────────────┬─────────────────────────────┘     │
│                      │                                    │
│  ┌───────────────────▼─────────────────────────────┐     │
│  │  Platform Channel                                │     │
│  │  MethodChannel · EventChannel · PlayerAPI        │     │
│  └───────────────────┬─────────────────────────────┘     │
│                      │                                    │
│  ┌───────────────────▼─────────────────────────────┐     │
│  │  Infrastructure (共享业务服务)                     │     │
│  │  DanmakuService · VideoListService · Download     │     │
│  └─────────────────────────────────────────────────┘     │
└──────────────────────────────────────────────────────────┘
                         │ Platform Channel
            ┌────────────┴────────────┐
            ▼                         ▼
   ┌────────────────┐      ┌────────────────┐
   │  iOS Native    │      │ Android Native  │
   │  (Objective-C) │      │   (Kotlin)      │
   │                │      │                 │
   │ PolyvMedia     │      │ PolyvMedia      │
   │ PlayerSDK      │      │ PlayerSDK       │
   └────────────────┘      └────────────────┘

Core Design Principles

  1. Plugin provides only core capabilities: Playback control, state management, Platform Channel encapsulation
  2. Business logic implemented uniformly in Dart layer: No Polyv business HTTP API calls in the native layer
  3. Native layer only wraps the player SDK: Exposes underlying capabilities (playback, download, subtitles, etc.), no business decisions
  4. Resolution switching progress restoration: Handled by the native layer (Dart layer only triggers switching and consumes events)

Features

Playback Core

Feature Description
Video Playback Play Polyv VOD videos via VID
Playback Control Play, pause, stop, replay
Progress Control Seek to a specific position, real-time progress callback
Speed Control Supports 0.5x ~ 2.0x variable speed playback
Resolution Switching Multi-bitrate switching (smooth, HD, UHD, etc.), automatic progress restoration
Subtitle System Multi-language subtitle tracks, bilingual subtitles, subtitle toggle
Offline Playback Automatically detect downloaded videos, prioritize local playback
Playback Progress Memory Automatically save and restore last playback progress

Video Download

Feature Description
Download Management Create, pause, resume, retry, delete download tasks
State Persistence Automatically sync download state after app restart
Progress Callback Real-time download progress notification

Danmaku System

Feature Description
Danmaku Rendering Supports scrolling danmaku layer
Danmaku Service Interface Pluggable DanmakuService / DanmakuSendService
HTTP Danmaku Built-in Polyv danmaku API implementation
Danmaku Settings Transparency, speed, font size, etc.
Danmaku Sending Danmaku input box in fullscreen mode

Interactive Experience

Feature Description
Gesture Control Swipe to adjust progress/volume/brightness
Double Tap Fullscreen Double tap playback area to toggle fullscreen
Lock Screen Mode Lock control bar when in fullscreen
Control Bar Auto-hide Configurable hide delay
Portrait/Landscape Adaptation Fullscreen/non-fullscreen layout auto-adaptation

Project Structure

polyv-flutter-media-player-demo/          # Git 仓库根目录
├── polyv_media_player/                   # Flutter Plugin 插件
│   ├── lib/
│   │   ├── polyv_media_player.dart       # 主入口(导出所有公共 API)
│   │   ├── core/                         # 核心层
│   │   │   ├── player_controller.dart    # 播放器控制器(ChangeNotifier)
│   │   │   ├── player_state.dart         # 播放器状态模型
│   │   │   ├── player_events.dart        # 事件类型定义
│   │   │   ├── player_event_parser.dart  # 原生事件解析器
│   │   │   ├── player_exception.dart     # 异常类
│   │   │   ├── player_config.dart        # 配置类
│   │   │   ├── subtitle_selection_policy.dart  # 字幕自动选择策略
│   │   │   ├── offline_playback_decider.dart   # 离线播放决策
│   │   │   └── system_locale_provider.dart     # 系统语言检测
│   │   ├── platform_channel/             # Platform Channel 封装
│   │   │   ├── player_api.dart           # Channel 名称 + 方法常量
│   │   │   ├── method_channel_handler.dart  # MethodChannel 处理
│   │   │   └── event_channel_handler.dart   # EventChannel 处理
│   │   ├── services/                     # 服务层
│   │   │   ├── polyv_config_service.dart # 账号配置管理
│   │   │   ├── player_initializer.dart   # 播放器初始化
│   │   │   ├── video_progress_service.dart  # 播放进度记忆
│   │   │   └── subtitle_preference_service.dart  # 字幕偏好
│   │   ├── infrastructure/               # 基础设施(共享业务服务)
│   │   │   ├── danmaku/                  # 弹幕系统
│   │   │   │   ├── danmaku_model.dart    # 弹幕数据模型
│   │   │   │   └── danmaku_service.dart  # 弹幕服务接口 + 实现
│   │   │   ├── download/                 # 下载管理
│   │   │   │   ├── download_task.dart    # 下载任务模型
│   │   │   │   ├── download_task_status.dart  # 下载状态枚举
│   │   │   │   ├── download_state_manager.dart  # 下载状态管理
│   │   │   │   ├── download_event_handler.dart  # 下载事件处理
│   │   │   │   └── download_native_repository.dart  # 原生下载能力封装
│   │   │   ├── video_list/               # 视频列表
│   │   │   │   ├── video_list_models.dart  # 视频列表数据模型
│   │   │   │   ├── video_list_service.dart  # 视频列表服务
│   │   │   │   └── video_list_api_client.dart  # API 客户端
│   │   │   └── polyv_api_client.dart     # Polyv API 通用客户端
│   │   ├── widgets/                      # Widget 层
│   │   │   ├── polyv_video_player.dart   # 全功能播放器 Widget
│   │   │   └── polyv_video_view.dart     # 原生视频视图(PlatformView)
│   │   ├── ui/                           # 内置 UI 组件
│   │   │   ├── control_bar.dart          # 控制栏
│   │   │   ├── control_bar_state_machine.dart  # 控制栏状态机
│   │   │   ├── player_colors.dart        # 播放器颜色常量
│   │   │   ├── double_tap_detector.dart  # 双击检测
│   │   │   ├── progress_slider/          # 进度条组件
│   │   │   ├── quality_selector/         # 清晰度选择器
│   │   │   ├── speed_selector/           # 倍速选择器
│   │   │   ├── subtitle_toggle.dart      # 字幕开关
│   │   │   ├── danmaku/                  # 弹幕 UI 组件
│   │   │   │   ├── danmaku_layer.dart    # 弹幕渲染层
│   │   │   │   ├── danmaku_toggle.dart   # 弹幕开关
│   │   │   │   ├── danmaku_input_overlay.dart  # 弹幕输入浮层
│   │   │   │   └── danmaku_settings.dart # 弹幕设置面板
│   │   │   ├── gestures/                 # 手势系统
│   │   │   │   ├── player_gesture_controller.dart
│   │   │   │   ├── player_gesture_detector.dart
│   │   │   │   └── seek_preview_overlay.dart
│   │   │   └── settings_menu/            # 设置菜单
│   │   └── utils/                        # 工具类
│   │       └── plv_logger.dart           # 日志工具
│   ├── ios/                              # iOS 原生代码
│   │   ├── Classes/
│   │   │   ├── PolyvMediaPlayerPlugin.m  # 插件入口
│   │   │   ├── PLVFlutterMethodRouter.m  # Method 路由分发
│   │   │   ├── PLVFlutterPlayerSession.m # 播放器会话管理
│   │   │   ├── PLVFlutterEventEmitter.m  # 事件发射器
│   │   │   ├── PLVFlutterDownloadMonitor.m # 下载监控
│   │   │   ├── PLVFlutterSubtitleCoordinator.m  # 字幕协调
│   │   │   ├── PLVVideoViewFactory.m     # PlatformView 工厂
│   │   │   └── ...字幕解析相关文件
│   │   └── polyv_media_player.podspec    # CocoaPods 配置
│   ├── android/                          # Android 原生代码
│   │   └── src/main/kotlin/
│   │       ├── PolyvMediaPlayerPlugin.kt # 插件入口
│   │       ├── MethodRouter.kt           # Method 路由
│   │       ├── PlayerCoordinator.kt      # 播放协调
│   │       ├── DownloadCoordinator.kt    # 下载协调
│   │       ├── SubtitleCoordinator.kt    # 字幕协调
│   │       ├── PlaybackEventEmitter.kt   # 播放事件发射
│   │       ├── DownloadEventEmitter.kt   # 下载事件发射
│   │       └── PolyvVideoViewFactory.kt  # PlatformView 工厂
│   └── test/                             # 单元测试
├── example/                              # Demo App
│   ├── lib/
│   │   ├── main.dart                     # 应用入口
│   │   ├── config/
│   │   │   └── app_config.dart           # 账号配置(环境变量注入)
│   │   ├── pages/
│   │   │   ├── home_page.dart            # 首页(长视频/下载中心入口)
│   │   │   ├── long_video_page.dart      # 长视频播放页
│   │   │   └── download_center/          # 下载中心
│   │   │       ├── download_center_page.dart
│   │   │       └── downloading_task_item.dart
│   │   └── player_skin/
│   │       └── video_list/               # 视频列表组件
│   └── pubspec.yaml
└── docs/                                 # 项目文档

Quick Integration

Environment Requirements

Requirement Version
Flutter >= 3.3.0
Dart SDK ^3.9.0
iOS >= 13.0
Android minSdk >= 21

Step 1: Add Dependency

Copy the polyv_media_player directory into your project (at the same level as lib/), then add to pubspec.yaml:

dependencies:
  polyv_media_player:
    path: polyv_media_player

Execute:

flutter pub get

Step 2: iOS Configuration

In the iOS project's Podfile, ensure the platform version is >= 13.0:

platform :ios, '13.0'

Then execute:

cd ios && pod install

The plugin will automatically import the following dependencies via CocoaPods:

PolyvMediaPlayerSDK (~> 2.7.2)
PLVFoundationSDK/AbstractBase (~> 1.30.2)
PLVFDB (~> 1.0.5)
PLVLOpenSSL (~> 1.1.12101)
SSZipArchive (~> 2.0)

Step 3: Initialize SDK

Initialize the Polyv account configuration in main.dart:

import 'package:flutter/material.dart';
import 'package:polyv_media_player/polyv_media_player.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await PolyvMediaPlayer.initialize(
    userId: 'your_user_id',
    secretKey: 'your_secret_key',
    readToken: 'your_read_token',   // 可选
    writeToken: 'your_write_token', // 可选
  );

  runApp(const MyApp());
}

Account configuration information can be obtained after registering on the Polyv Admin Console.

Step 4: Use the Player

Simplest usage, play a video with a single line of code:

PolyvVideoPlayer(
  vid: 'your_video_id',
  autoPlay: true,
)

API Reference

SDK Initialization

await PolyvMediaPlayer.initialize(
  userId: String,     // 必填:保利威用户 ID
  secretKey: String,  // 必填:密钥
  readToken: String?, // 可选:读取 Token
  writeToken: String?,// 可选:写入 Token
);

// 检查是否已初始化
bool initialized = PolyvMediaPlayer.isInitialized;

// 获取用户 ID
String userId = await PolyvMediaPlayer.userId;

PlayerController

PlayerController is the core control class for the player, inheriting from ChangeNotifier, driving UI updates via the Provider pattern.

Playback Control

Method / Property Description
loadVideo(vid, {autoPlay}) Load video
play() Play
pause() Pause
stop() Stop
replay() Replay (go back to the beginning and replay)
seekTo(position) Seek to a specific position (milliseconds)

Settings

Method Description
setPlaybackSpeed(speed) Set playback speed (0.5 ~ 2.0)
setQuality(index) Switch resolution
setSubtitle(index) Set subtitle (-1 to disable)
toggleSubtitle() Toggle subtitle on/off
setSubtitleWithKey({enabled, trackKey}) Set subtitle by key

State

Property Type Description
state PlayerState Current complete player state
qualities List<QualityItem> List of available resolutions
availableSubtitles List<SubtitleItem> List of available subtitles
effectiveIsPlaying bool Playback state (recommended for UI)

Lifecycle

Method Description
dispose() Release resources (must be called when Widget is disposed)

PlayerState

class PlayerState {
  PlayerLoadingState loadingState;  // idle/loading/prepared/playing/paused/buffering/completed/error
  int position;           // 当前位置(毫秒)
  int duration;           // 总时长(毫秒)
  int bufferedPosition;   // 缓冲位置(毫秒)
  double playbackSpeed;   // 播放速度
  String? errorMessage;   // 错误信息
  String? vid;            // 当前视频 VID
  bool subtitleEnabled;   // 字幕是否开启
  String? currentSubtitleId;  // 当前字幕 ID
  List<SubtitleItem> availableSubtitles;  // 可用字幕列表
}

Event Types

Event Description Data
stateChanged Playback state change New state (playing/paused/buffering...)
progress Progress update position, duration, bufferedPosition
error Error code, message
qualityChanged Resolution change qualities[], currentIndex
subtitleChanged Subtitle change subtitles[], currentIndex
playbackSpeedChanged Speed change speed
completed Playback complete -

Platform Channel Constants

MethodChannel: com.polyv.media_player/player
EventChannel:  com.polyv.media_player/events
DownloadEvent: com.polyv.media_player/download_events

PolyvVideoPlayer Widget

Parameter Type Default Description
vid String Required Video ID
autoPlay bool true Whether to auto-play
showControls bool true Whether to show control bar
enableDanmaku bool true Whether to enable danmaku
enableGestures bool true Whether to enable gestures
enableDoubleTapFullscreen bool true Whether to enable double-tap fullscreen
isFullscreen bool false Whether in fullscreen mode
showLockButton bool false Show lock screen button in fullscreen
showDanmakuSend bool false Show danmaku sending in fullscreen
showTopBar bool false Show top bar in fullscreen
videoTitle String? null Fullscreen top bar title
aspectRatio double 16/9 Video aspect ratio
backgroundColor Color Colors.black Background color
autoHideDuration Duration 3s Control bar auto-hide duration
controller PlayerController? null External controller
danmakuService DanmakuService? null Danmaku data service
danmakuSendService DanmakuSendService? null Danmaku sending service
danmakuHeightFactor double 0.6 Danmaku display area height ratio
onFullscreenChanged Function? null Fullscreen toggle callback
onLoaded Function? null Load complete callback
onPlayingChanged Function? null Playback state change callback
onCompleted Function? null Playback complete callback
onError Function? null Error callback

UI Components

The plugin includes a complete library of player UI components that can be used independently or combined.

Available Components

Component Import Path Description
ControlBar ui/control_bar.dart Complete control bar (progress bar + play button + speed + resolution)
ProgressSlider ui/progress_slider/ Progress bar component (with buffer progress)
QualitySelector ui/quality_selector/ Resolution selector
SpeedSelector ui/speed_selector/ Speed selector
SubtitleToggle ui/subtitle_toggle.dart Subtitle toggle
DanmakuLayer ui/danmaku/danmaku.dart Danmaku rendering layer
DanmakuToggle ui/danmaku/danmaku_toggle.dart Danmaku toggle
DanmakuInputOverlay ui/danmaku/danmaku_input_overlay.dart Danmaku sending input box
DanmakuSettings ui/danmaku/danmaku_settings.dart Danmaku settings panel
SettingsMenu ui/settings_menu/ Settings menu (resolution + speed + danmaku)
PlayerGestureDetector ui/gestures/gestures.dart Gesture detection (swipe progress/volume/brightness)
SeekPreviewOverlay ui/gestures/seek_preview_overlay.dart Seek preview overlay
PlayerColors ui/player_colors.dart Player color constants

Custom UI Example

Assemble a custom player using underlying components:

class CustomVideoPage extends StatefulWidget {
  @override
  State<CustomVideoPage> createState() => _CustomVideoPageState();
}

class _CustomVideoPageState extends State<CustomVideoPage> {
  late final PlayerController _controller;

  @override
  void initState() {
    super.initState();
    _controller = PlayerController();
    _controller.loadVideo('your_video_id');
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Stack(
        children: [
          // 原生视频视图
          const PolyvVideoView(),
          // 自定义控制栏
          Align(
            alignment: Alignment.bottomCenter,
            child: ControlBar(controller: _controller),
          ),
        ],
      ),
    );
  }
}

Platform Native Layer

iOS Native Architecture

iOS native code uses modular decomposition, each component has a single responsibility:

Component File Responsibility
Plugin Entry PolyvMediaPlayerPlugin.m Holds Flutter registrar/channel, registers Plugin
Method Routing PLVFlutterMethodRouter MethodChannel method dispatching
Player Session PLVFlutterPlayerSession Player instance lifecycle management, SDK call encapsulation
Event Emission PLVFlutterEventEmitter Unified encapsulation of player/download EventChannel event sending
Download Monitoring PLVFlutterDownloadMonitor Download state polling and download event sending
Subtitle Coordination PLVFlutterSubtitleCoordinator Subtitle track events, label maintenance
Video View PLVVideoViewFactory PlatformView factory, creates native video rendering view
Subtitle Parsing PLVVodMediaSubtitleParser etc. SRT/ASS subtitle file parsing

iOS Dependencies (via CocoaPods)

s.dependency 'PolyvMediaPlayerSDK', '~> 2.7.2'
s.dependency 'PLVFoundationSDK/AbstractBase', '~> 1.30.2'
s.dependency 'PLVFDB', '~> 1.0.5'
s.dependency 'PLVLOpenSSL', '~> 1.1.12101'
s.dependency 'SSZipArchive', '~> 2.0'
s.platform = :ios, '13.0'

Android Native Architecture

Component File Responsibility
Plugin Entry PolyvMediaPlayerPlugin.kt Registers MethodChannel, EventChannel
Method Routing MethodRouter.kt Method dispatching
Playback Coordination PlayerCoordinator.kt Player instance management
Download Coordination DownloadCoordinator.kt Download task management
Subtitle Coordination SubtitleCoordinator.kt Subtitle track management
Playback Events PlaybackEventEmitter.kt Sends playback events to Flutter
Download Events DownloadEventEmitter.kt Sends download events to Flutter
Video View PolyvVideoViewFactory.kt PlatformView factory

Android Dependencies

implementation("net.polyv.android:media-player-full:2.7.2")
implementation("net.polyv.android:media-player-sdk-addon-business:2.7.2")
implementation("net.polyv.android:media-player-sdk-addon-download:2.7.2")

Business Service Module

The plugin provides cross-platform shareable business services in the infrastructure/ directory:

Danmaku Service

// 弹幕数据模型
class Danmaku {
  final String id;
  final String content;
  final int time;       // 毫秒
  final String color;
  final String type;    // scroll/top/bottom
}

// 弹幕服务接口
abstract class DanmakuService {
  Future<List<Danmaku>> fetchDanmakus(String vid);
}

// 弹幕发送服务接口
abstract class DanmakuSendService {
  Future<void> sendDanmaku(String vid, String content, {String? color});
}

Built-in implementations:

  • HttpDanmakuService - Fetches danmaku via Polyv danmaku API
  • HttpDanmakuSendService - Sends danmaku via Polyv API
  • MockDanmakuService - Mock implementation (for debugging)

Video List Service

class VideoListService {
  Future<VideoListResult> fetchVideoList({
    int? page,
    int? pageSize,
    String? categoryId,
  });
}

Download Management

// 下载任务状态
enum DownloadTaskStatus { pending, downloading, paused, completed, failed, canceled }

// 下载状态管理(单例)
class DownloadStateManager extends ChangeNotifier {
  static final DownloadStateManager instance = DownloadStateManager._();
  Future<void> syncFromNative();  // 从原生层同步下载列表
  List<DownloadTask> get tasks;
}

// 通过 PlayerController 的 Platform Channel 调用原生下载能力
// startDownload / pauseDownload / resumeDownload / retryDownload / deleteDownload

Demo Application

The example/ directory contains a complete example application showcasing all plugin features.

Page Structure

Page File Functionality
Home pages/home_page.dart Dark gradient background, two entry buttons for long video/download center
Long Video Page pages/long_video_page.dart Video playback + video list + danmaku + control bar
Download Center pages/download_center/ Download task list, state management, operation control

Account Configuration

The Demo injects account configuration via the --dart-define environment variable:

flutter run \
  --dart-define=POLYV_USER_ID=your_user_id \
  --dart-define=POLYV_SECRET_KEY=your_secret_key \
  --dart-define=POLYV_READ_TOKEN=your_read_token \
  --dart-define=POLYV_WRITE_TOKEN=your_write_token

The configuration is read by config/app_config.dart and injected into PolyvConfigService.

Running the Demo

cd polyv_media_player
fvm flutter pub run example  # 或 flutter run

Development Guide

Naming Conventions

Type Convention Example
Class PascalCase PlayerController
Method camelCase seekTo()
Variable camelCase currentPosition
Private Prefix _ _nativeChannel
File snake_case player_controller.dart

State Management

Uses Provider + ChangeNotifier pattern:

// 在 Widget 中监听 PlayerController
Consumer<PlayerController>(
  builder: (context, controller, child) {
    return Text('${controller.state.position}');
  },
)

Error Handling

All Platform Channel calls must catch exceptions:

try {
  await _channel.invokeMethod('playVideo', {'vid': vid});
} on PlatformException catch (e) {
  throw PlayerException(
    code: e.code ?? 'UNKNOWN_ERROR',
    message: e.message ?? 'An error occurred',
  );
}

Running Tests

cd polyv_media_player
fvm flutter test           # 插件单元测试
fvm flutter test example   # Demo 测试
联系客服,在线咨询