Polyv Flutter Media Player - Project Documentation
A Flutter video player plugin based on the Polyv iOS VOD Player SDK, supporting both iOS and Android platforms.
Table of Contents
- Project Overview
- Architecture Design
- Features
- Project Structure
- Quick Integration
- API Reference
- UI Components
- Platform Native Layer
- Business Service Module
- Demo Application
- Development Guide
- FAQ
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:
- iOS VOD SDK Documentation: https://help.polyv.net/index.html#/vod/ios_player_sdk/
- iOS SDK Demo: https://github.com/polyv/polyv-ios-vod-sdk
- Android SDK: Distributed via Alibaba Cloud private Maven repository
- Developer Center: https://www.polyv.net/dev/
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
- Plugin provides only core capabilities: Playback control, state management, Platform Channel encapsulation
- Business logic implemented uniformly in Dart layer: No Polyv business HTTP API calls in the native layer
- Native layer only wraps the player SDK: Exposes underlying capabilities (playback, download, subtitles, etc.), no business decisions
- 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 APIHttpDanmakuSendService- Sends danmaku via Polyv APIMockDanmakuService- 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 测试
