# flutter_pangle
**Repository Path**: DSRheart/flutter_pangle
## Basic Information
- **Project Name**: flutter_pangle
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-11-05
- **Last Updated**: 2025-12-12
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# flutter_pangle
[](https://pub.dev/packages/flutter_pangle)
A Flutter plugin for integrating Dramaverse Short Play SDK (Pangle ShortPlay SDK) on iOS and Android platforms.
## Features
- ✅ Full support for Dramaverse Short Play SDK APIs
- ✅ Native video player integration (Android Fragment & iOS UIView)
- ✅ Short play list fetching (default, popular, new, filtered by category/tag)
- ✅ Search functionality
- ✅ Playback controls (play, pause, seek, speed, play index)
- ✅ Event callbacks from native player
- ✅ Category and tag management
- ✅ Collection status management
- ✅ Local cache management
## Platform Support
- ✅ iOS 13.0+
- ✅ Android 5.0+ (minSdk 21)
## Installation
Add this to your package's `pubspec.yaml` file:
```yaml
dependencies:
flutter_pangle: ^0.0.3
```
Then run:
```bash
flutter pub get
```
## Setup
### Android Setup
1. **Add repositories** to your project's `build.gradle.kts`:
```kotlin
allprojects {
repositories {
maven {
url = uri("https://artifact.bytedance.com/repository/Volcengine/")
}
maven {
url = uri("https://artifact.byteplus.com/repository/public/")
}
maven {
url = uri("https://artifact.bytedance.com/repository/pangle/")
}
}
}
```
2. **Add permissions** to `AndroidManifest.xml`:
```xml
```
3. **Change MainActivity** to extend `FlutterFragmentActivity`:
```kotlin
import io.flutter.embedding.android.FlutterFragmentActivity
class MainActivity: FlutterFragmentActivity() {
// ...
}
```
4. **Add network security config** (`res/xml/network_security_config.xml`):
```xml
```
And reference it in `AndroidManifest.xml`:
```xml
```
5. **Add license file** to `app/src/main/assets/` directory (e.g., `vod_player.lic`)
### iOS Setup
1. **Add license file** (`xxx.lic`) to the `Runner` folder in your Xcode project
2. **Add to `Info.plist`**:
```xml
NSAppTransportSecurity
NSAllowsArbitraryLoads
NSAllowsLocalNetworking
NSCameraUsageDescription
需要访问相机以拍摄照片和视频
NSMicrophoneUsageDescription
需要访问麦克风以录制视频
NSPhotoLibraryAddUsageDescription
需要保存图片和视频到相册
NSPhotoLibraryUsageDescription
需要访问相册以选择图片和视频
UIApplicationSupportsIndirectInputEvents
```
3. **Update `Podfile`**:
```ruby
source 'https://cdn.cocoapods.org/'
source 'https://github.com/volcengine/volcengine-specs.git'
source 'https://github.com/byteplus-sdk/byteplus-specs.git'
use_frameworks! :linkage => :static
```
**Note:** Replace the original `use_frameworks!` with `use_frameworks! :linkage => :static`
4. **Run pod install**:
```bash
cd ios && pod install
```
## Usage
### Initialize SDK
```dart
import 'package:flutter_pangle/flutter_pangle.dart';
import 'dart:io';
final flutterPangle = FlutterPangle();
// Initialize SDK
final config = PAGSSDKConfig(
appId: Platform.isAndroid ? 'your_android_app_id' : 'your_ios_app_id',
vodAppId: Platform.isAndroid ? 'your_android_vod_app_id' : 'your_ios_vod_app_id',
securityKey: 'your_security_key',
licenseAssertPath: Platform.isAndroid ? 'vod_player.lic' : 'your_ios_license.lic',
userId: 'user123',
debug: false,
);
final success = await flutterPangle.initializeSDK(config);
if (success) {
print('SDK initialized successfully');
// Set eligible audience
await flutterPangle.setEligibleAudience(true);
// Set content languages
await flutterPangle.setContentLanguages(['zh_hans', 'en']);
}
```
### Fetch Short Play Lists
```dart
// Get default feed list
final response = await flutterPangle.requestFeedList(
index: 1,
count: 20,
);
for (var short in response.list) {
print('Title: ${short.title}');
print('Description: ${short.desc}');
print('ID: ${short.id}');
print('Total episodes: ${short.total}');
}
// Get popular dramas
final popularResponse = await flutterPangle.requestPopularDrama(
index: 1,
count: 10,
);
// Get new dramas
final newResponse = await flutterPangle.requestNewFeedList(
index: 1,
count: 10,
);
// Get dramas by category
final categoryResponse = await flutterPangle.requestFeedListWithFilters(
index: 1,
count: 10,
categoryIds: [1, 2], // Category IDs
);
// Get dramas by tag
final tagResponse = await flutterPangle.requestDramaWithTag(
tag: 4, // Tag ID (e.g., 4 = Collection Ranking)
index: 1,
count: 10,
);
// Search dramas
final searchResponse = await flutterPangle.requestSearchDrama(
index: 1,
count: 10,
keyword: '爱情',
isFuzzy: true,
);
// Get category list
final categories = await flutterPangle.getCategoryList('zh_hans');
for (var category in categories) {
print('Category: ${category.categoryName} (ID: ${category.categoryId})');
}
```
### Native Video Player
```dart
import 'dart:convert';
// Create controller
final controller = PangleDetailController(
playSingleItem: false, // Whether to play single item only
initialPlayIndex: 1, // Initial episode index (default: 1)
autoPlay: false, // Auto play on load (default: false)
onEvent: (event, data) {
switch (event) {
case 'onProgressChange':
final progress = data['progress'] as int;
final duration = data['duration'] as int;
print('Progress: $progress / $duration');
break;
case 'onPlayFailed':
print('Play failed: ${data['error']}');
break;
case 'onVideoPlayCompleted':
print('Video completed');
break;
case 'onItemSelected':
final index = data['index'] as int;
print('Selected episode: $index');
break;
// Other events: onShortPlayPlayed, onVideoPlayStateChanged,
// onEnterImmersiveMode, onExitImmersiveMode, onVideoInfoFetched, disposed
}
},
);
// Use in widget
PangleDetailAndroidView(
shortplayJson: jsonEncode(shortPlay.toMap()), // Convert PAGSShort to JSON
controller: controller,
);
// Control playback
await controller.play();
await controller.pause();
await controller.seekToSeconds(45); // Seek to 45 seconds
await controller.setSpeed(1.25); // Set playback speed (0.5, 1.0, 1.25, 1.5, 2.0)
await controller.startPlayIndex(3); // Start from episode 3
```
### Other Features
```dart
// Check play status
final playStatus = await flutterPangle.checkPlayStatus();
// Returns: 0 = Unknown, 1 = Supported, 2 = Not Supported
// Set collection status
await flutterPangle.setCollected(
collected: true,
shortplayId: 123456,
);
// Clear local cache
await flutterPangle.clearLocalCache();
// Get current language
final language = flutterPangle.getCurrentLanguage();
print('Current language: $language');
```
## API Reference
### SDK Initialization
- `initializeSDK(PAGSSDKConfig config)` - Initialize the SDK
- `warmUpPlayerEngine()` - Warm up the player engine (optional)
### Configuration
- `setEligibleAudience(bool eligible)` - Set eligible audience compliance
- `setContentLanguage(String language)` - Set single content language
- `setContentLanguages(List languages)` - Set multiple content languages
- `getCurrentLanguage()` - Get device's current language
### Short Play Lists
- `requestFeedList({required int index, required int count})` - Get default feed list
- `requestFeedListWithFilters({required int index, required int count, List? categoryIds})` - Get filtered list
- `requestPopularDrama({required int index, required int count})` - Get popular dramas
- `requestNewFeedList({required int index, required int count})` - Get new dramas
- `requestDramaWithTag({required int tag, required int index, required int count})` - Get dramas by tag
- `getCategoryList(String language)` - Get category list
- `requestSearchDrama({required int index, required int count, required String keyword, bool isFuzzy = false})` - Search dramas
### Playback Control
- `PangleDetailController.seekToSeconds(int seconds)` - Seek to specific time
- `PangleDetailController.pause()` - Pause playback
- `PangleDetailController.play()` - Start/resume playback
- `PangleDetailController.setSpeed(double speed)` - Set playback speed
- `PangleDetailController.startPlayIndex(int index)` - Start from specific episode
### Other
- `checkPlayStatus()` - Check if playback is supported in current region
- `setCollected({required bool collected, required int shortplayId})` - Set collection status
- `clearLocalCache()` - Clear local cache
## Event Callbacks
The `PangleDetailController.onEvent` callback receives the following events:
- `onProgressChange` - Playback progress changed (`progress`, `duration`)
- `onPlayFailed` - Playback failed (`error`)
- `onShortPlayPlayed` - Short play started playing
- `onItemSelected` - Episode selected (`index`)
- `onVideoPlayStateChanged` - Video play state changed (`state`)
- `onVideoPlayCompleted` - Video playback completed
- `onEnterImmersiveMode` - Entered immersive mode
- `onExitImmersiveMode` - Exited immersive mode
- `onVideoInfoFetched` - Video info fetched
- `disposed` - Player disposed
## Data Models
### PAGSShort
- `id` - Short play ID
- `title` - Title
- `desc` - Description
- `coverImage` - Cover image URL
- `total` - Total episodes
- `episodes` - List of episodes (`PAGSEpisode`)
- `categories` - List of categories (`PAGSCategory`)
- `tagList` - List of tags (`PAGSTag`)
- `totalCollectCount` - Total collection count
- `isCollected` - Is collected by user
- And more...
## Important Notes
1. **VPN Required**: During testing, you must use a VPN with nodes from SDK-supported countries/regions
2. **Credentials**: You need to obtain `appId` and `securityKey` from Dramaverse
3. **License**: You need to purchase a certificate from BytePlus to get `vodAppId` and license file
4. **Supported Regions**: Please refer to the official SDK documentation for supported countries and regions
5. **MainActivity**: Android apps must use `FlutterFragmentActivity` instead of `FlutterActivity` to support native Fragment embedding
## Example
See the `example` directory for a complete example app demonstrating:
- SDK initialization
- Fetching short play lists
- Using the native video player
- Vertical stream playback with PageView
- Playback controls and event handling
## License
See the LICENSE file for details.