Polyv Flutter Media Player - 專案文件
更新時間:2026-05-14 11:19:41
基於 保利威 iOS 點播播放器 SDK 封裝的 Flutter 影片播放器插件,支援 iOS 和 Android 雙平台。
目錄
專案概述
polyv-flutter-media-player-demo 是一個 Flutter Plugin 專案,將保利威原生播放器 SDK(iOS PolyvMediaPlayerSDK、Android media-player-full)封裝為統一的 Dart API,供 Flutter 應用跨平台呼叫。
專案分為兩層:
| 層級 | 目錄 | 職責 |
|---|---|---|
| Plugin(插件層) | polyv_media_player/ |
播放核心能力 + 可共享業務服務模組,無業務 UI |
| Demo App(範例層) | example/ |
完整 UI 實作(播放器皮膚、控制欄、彈幕、字幕等),供客戶參考複製 |
技術棧
| 類別 | 技術 |
|---|---|
| 框架 | Flutter (Dart SDK ^3.9.0) |
| 狀態管理 | Provider (ChangeNotifier 模式) |
| iOS 原生 SDK | PolyvMediaPlayerSDK ~> 2.7.2 (Objective-C) |
| Android 原生 SDK | net.polyv.android:media-player-full:2.7.2 (Kotlin) |
| 跨平台通訊 | Flutter Platform Channel (MethodChannel + EventChannel) |
| 依賴 | http, crypto, shared_preferences, provider |
底層 SDK 參考
本插件封裝的保利威原生 SDK 文件:
- iOS 點播 SDK 文件: https://help.polyv.net/index.html#/vod/ios_player_sdk/
- iOS SDK Demo: https://github.com/polyv/polyv-ios-vod-sdk
- Android SDK: 透過阿里雲私有 Maven 倉庫分發
- 開發者中心: https://www.polyv.net/dev/
架構設計
┌─────────────────────────────────────────────────────────┐
│ 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 │
└────────────────┘ └────────────────┘
核心設計原則
- Plugin 只提供核心能力:播放控制、狀態管理、Platform Channel 封裝
- 業務邏輯在 Dart 層統一實作:不在原生層呼叫 Polyv 業務 HTTP 介面
- 原生層只封裝播放器 SDK:暴露底層能力(播放、下載、字幕等),不包含業務決策
- 清晰度切換進度恢復:由原生層負責(Dart 層僅觸發切換、消費事件)
功能特性
播放核心
| 功能 | 說明 |
|---|---|
| 影片播放 | 透過 VID 播放保利威點播影片 |
| 播放控制 | 播放、暫停、停止、重播 |
| 進度控制 | Seek 到指定位置,進度即時回呼 |
| 倍速播放 | 支援 0.5x ~ 2.0x 變速播放 |
| 清晰度切換 | 多碼率切換(流暢、高清、超清等),自動恢復進度 |
| 字幕系統 | 多語言字幕軌道、雙語字幕、字幕開關 |
| 離線播放 | 自動偵測已下載影片,優先本地播放 |
| 播放進度記憶 | 自動儲存和恢復上次播放進度 |
影片下載
| 功能 | 說明 |
|---|---|
| 下載管理 | 建立、暫停、繼續、重試、刪除下載任務 |
| 狀態持久化 | App 重啟後自動同步下載狀態 |
| 進度回呼 | 即時下載進度通知 |
彈幕系統
| 功能 | 說明 |
|---|---|
| 彈幕渲染 | 支援滾動彈幕層 |
| 彈幕服務介面 | 可插拔的 DanmakuService / DanmakuSendService |
| HTTP 彈幕 | 內建保利威彈幕 API 實作 |
| 彈幕設定 | 透明度、速度、字型大小等 |
| 彈幕發送 | 全螢幕模式下的彈幕輸入框 |
互動體驗
| 功能 | 說明 |
|---|---|
| 手勢控制 | 滑動調節進度/音量/亮度 |
| 雙擊全螢幕 | 雙擊播放區域切換全螢幕 |
| 鎖定螢幕模式 | 全螢幕時鎖定控制欄 |
| 控制欄自動隱藏 | 可設定隱藏延遲 |
| 橫直螢幕適配 | 全螢幕/非全螢幕佈局自適應 |
專案結構
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/ # 项目文档
快速整合
環境要求
| 要求 | 版本 |
|---|---|
| Flutter | >= 3.3.0 |
| Dart SDK | ^3.9.0 |
| iOS | >= 13.0 |
| Android minSdk | >= 21 |
步驟 1: 新增依賴
將 polyv_media_player 目錄複製到專案中(與 lib/ 平級),然後在 pubspec.yaml 中新增:
dependencies:
polyv_media_player:
path: polyv_media_player
執行:
flutter pub get
步驟 2: iOS 設定
在 iOS 專案的 Podfile 中確保平台版本 >= 13.0:
platform :ios, '13.0'
然後執行:
cd ios && pod install
插件會自動透過 CocoaPods 引入以下依賴:
PolyvMediaPlayerSDK (~> 2.7.2)
PLVFoundationSDK/AbstractBase (~> 1.30.2)
PLVFDB (~> 1.0.5)
PLVLOpenSSL (~> 1.1.12101)
SSZipArchive (~> 2.0)
步驟 3: 初始化 SDK
在 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());
}
帳號設定資訊可在 保利威後台 註冊後取得。
步驟 4: 使用播放器
最簡用法,一行程式碼即可播放影片:
PolyvVideoPlayer(
vid: 'your_video_id',
autoPlay: true,
)
API 參考
SDK 初始化
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 是播放器的核心控制類別,繼承自 ChangeNotifier,透過 Provider 模式驅動 UI 更新。
播放控制
| 方法 / 屬性 | 說明 |
|---|---|
loadVideo(vid, {autoPlay}) |
載入影片 |
play() |
播放 |
pause() |
暫停 |
stop() |
停止 |
replay() |
重播(回到開頭重新播放) |
seekTo(position) |
跳轉到指定位置(毫秒) |
設定
| 方法 | 說明 |
|---|---|
setPlaybackSpeed(speed) |
設定倍速(0.5 ~ 2.0) |
setQuality(index) |
切換清晰度 |
setSubtitle(index) |
設定字幕(-1 關閉) |
toggleSubtitle() |
切換字幕開關 |
setSubtitleWithKey({enabled, trackKey}) |
透過 key 設定字幕 |
狀態
| 屬性 | 類型 | 說明 |
|---|---|---|
state |
PlayerState |
目前播放器完整狀態 |
qualities |
List<QualityItem> |
可用清晰度列表 |
availableSubtitles |
List<SubtitleItem> |
可用字幕列表 |
effectiveIsPlaying |
bool |
播放狀態(推薦用於 UI) |
生命週期
| 方法 | 說明 |
|---|---|
dispose() |
釋放資源(必須在 Widget dispose 時呼叫) |
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; // 可用字幕列表
}
事件類型
| 事件 | 說明 | 資料 |
|---|---|---|
stateChanged |
播放狀態變化 | 新狀態 (playing/paused/buffering...) |
progress |
進度更新 | position, duration, bufferedPosition |
error |
錯誤 | code, message |
qualityChanged |
清晰度變化 | qualities[], currentIndex |
subtitleChanged |
字幕變化 | subtitles[], currentIndex |
playbackSpeedChanged |
倍速變化 | speed |
completed |
播放完成 | - |
Platform Channel 常數
MethodChannel: com.polyv.media_player/player
EventChannel: com.polyv.media_player/events
DownloadEvent: com.polyv.media_player/download_events
PolyvVideoPlayer Widget
| 參數 | 類型 | 預設值 | 說明 |
|---|---|---|---|
vid |
String |
必填 | 影片 ID |
autoPlay |
bool |
true |
是否自動播放 |
showControls |
bool |
true |
是否顯示控制欄 |
enableDanmaku |
bool |
true |
是否啟用彈幕 |
enableGestures |
bool |
true |
是否啟用手勢 |
enableDoubleTapFullscreen |
bool |
true |
是否啟用雙擊全螢幕 |
isFullscreen |
bool |
false |
是否全螢幕模式 |
showLockButton |
bool |
false |
全螢幕時顯示鎖定螢幕按鈕 |
showDanmakuSend |
bool |
false |
全螢幕時顯示彈幕發送 |
showTopBar |
bool |
false |
全螢幕時顯示頂部欄 |
videoTitle |
String? |
null |
全螢幕頂部欄標題 |
aspectRatio |
double |
16/9 |
影片寬高比 |
backgroundColor |
Color |
Colors.black |
背景色 |
autoHideDuration |
Duration |
3s |
控制欄自動隱藏時長 |
controller |
PlayerController? |
null |
外部控制器 |
danmakuService |
DanmakuService? |
null |
彈幕資料服務 |
danmakuSendService |
DanmakuSendService? |
null |
彈幕發送服務 |
danmakuHeightFactor |
double |
0.6 |
彈幕顯示區域高度比例 |
onFullscreenChanged |
Function? |
null |
全螢幕切換回呼 |
onLoaded |
Function? |
null |
載入完成回呼 |
onPlayingChanged |
Function? |
null |
播放狀態變化回呼 |
onCompleted |
Function? |
null |
播放完成回呼 |
onError |
Function? |
null |
錯誤回呼 |
UI 元件
插件內建了完整的播放器 UI 元件庫,可獨立使用或組合使用。
可用元件
| 元件 | 匯入路徑 | 說明 |
|---|---|---|
ControlBar |
ui/control_bar.dart |
完整控制欄(進度條 + 播放按鈕 + 倍速 + 清晰度) |
ProgressSlider |
ui/progress_slider/ |
進度條元件(含緩衝進度) |
QualitySelector |
ui/quality_selector/ |
清晰度選擇器 |
SpeedSelector |
ui/speed_selector/ |
倍速選擇器 |
SubtitleToggle |
ui/subtitle_toggle.dart |
字幕開關 |
DanmakuLayer |
ui/danmaku/danmaku.dart |
彈幕渲染層 |
DanmakuToggle |
ui/danmaku/danmaku_toggle.dart |
彈幕開關 |
DanmakuInputOverlay |
ui/danmaku/danmaku_input_overlay.dart |
彈幕發送輸入框 |
DanmakuSettings |
ui/danmaku/danmaku_settings.dart |
彈幕設定面板 |
SettingsMenu |
ui/settings_menu/ |
設定選單(清晰度 + 倍速 + 彈幕) |
PlayerGestureDetector |
ui/gestures/gestures.dart |
手勢偵測(滑動進度/音量/亮度) |
SeekPreviewOverlay |
ui/gestures/seek_preview_overlay.dart |
Seek 預覽浮層 |
PlayerColors |
ui/player_colors.dart |
播放器顏色常數 |
自訂 UI 範例
使用底層元件組裝自訂播放器:
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),
),
],
),
);
}
}
平台原生層
iOS 原生架構
iOS 原生程式碼採用模組化拆分,每個元件職責單一:
| 元件 | 檔案 | 職責 |
|---|---|---|
| Plugin 入口 | PolyvMediaPlayerPlugin.m |
持有 Flutter registrar/channel,註冊 Plugin |
| Method 路由 | PLVFlutterMethodRouter |
MethodChannel 方法分發 |
| 播放器會話 | PLVFlutterPlayerSession |
播放器實例生命週期管理、SDK 呼叫封裝 |
| 事件發射 | PLVFlutterEventEmitter |
統一封裝 player/download EventChannel 事件發送 |
| 下載監控 | PLVFlutterDownloadMonitor |
下載狀態輪詢與下載事件發送 |
| 字幕協調 | PLVFlutterSubtitleCoordinator |
字幕軌道事件、label 維護 |
| 影片視圖 | PLVVideoViewFactory |
PlatformView 工廠,建立原生影片渲染視圖 |
| 字幕解析 | PLVVodMediaSubtitleParser 等 |
SRT/ASS 字幕檔案解析 |
iOS 依賴(透過 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 原生架構
| 元件 | 檔案 | 職責 |
|---|---|---|
| Plugin 入口 | PolyvMediaPlayerPlugin.kt |
註冊 MethodChannel、EventChannel |
| Method 路由 | MethodRouter.kt |
方法分發 |
| 播放協調 | PlayerCoordinator.kt |
播放器實例管理 |
| 下載協調 | DownloadCoordinator.kt |
下載任務管理 |
| 字幕協調 | SubtitleCoordinator.kt |
字幕軌道管理 |
| 播放事件 | PlaybackEventEmitter.kt |
播放事件發送到 Flutter |
| 下載事件 | DownloadEventEmitter.kt |
下載事件發送到 Flutter |
| 影片視圖 | PolyvVideoViewFactory.kt |
PlatformView 工廠 |
Android 依賴
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")
業務服務模組
插件在 __PLV_K
