# 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 [![pub package](https://img.shields.io/pub/v/flutter_pangle.svg)](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.