提交 e712b7a8 authored 作者: dokieyang's avatar dokieyang

1、update version to 1.0.3

2、add PIP for iOS
上级 7a9e68c5
#### Version: 1.0.2 当前最新版本
#### Version: 1.0.3 当前最新版本
##### 分支描述:
......@@ -6,8 +6,20 @@ main 分支:Android & iOS 端集成TXLiteAVSDK_Player lastest版本
Professional 分支:Android & iOS 端集成TXLiteAVSDK_Professional lastest版本
版本特性:
- iOS 端新增画中画(PIP) 功能
#### Version: 1.0.2 2022.07.05
##### 版本特性:
- Android 端新增画中画(PIP) 功能
- 播放器组件(superplayer)用Dart重写,方便自定义集成
- 修复通过appId 、fileId和 psign 播放失败问题
- set Android TXLiteAVSDK_Professional to 10.2.0.11131,tag:release_player_v1.0.2
- set iOS TXLiteAVSDK_Professional to 10.2.11418, tag:release_pro_v1.0.2
group 'com.tencent.vod.flutter'
apply from:'config.gradle'
version '1.0.2'
version '1.0.3'
buildscript {
repositories {
......
......@@ -564,23 +564,24 @@ loader.getVideoData(model, (resultModel) {
#### 画中画模式的使用
##### android平台
1. 安卓平台配置
1. 添加原生配置
1.1 在自己项目的android包下,找到 AndroidManifest.xml ,在项目入口activity节点下,增加如下配置
在自己项目的android包下,找到 AndroidManifest.xml ,在项目入口activity节点下,增加如下配置
```xml
android:supportsPictureInPicture="true"
android:resizeableActivity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
```
```xml
android:supportsPictureInPicture="true"
android:resizeableActivity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
```
在自己项目android包下,找到build.gralde,确认 compileSdkVersion 和 targetSdkVersion 的版本为31或以上
在自己项目android包下,找到build.gralde,确认 compileSdkVersion 和 targetSdkVersion 的版本为31或以上
1.2 继承pip activity
2. 继承pip activity
将github项目中example/android 中的 FTXFlutterPipActivity.java 复制到自己入口 Activity 的同目录下,并将自己 Activity 的父类修改为该类。
将github项目中example/android 中的 FTXFlutterPipActivity.java 复制到自己入口 Activity 的同目录下,并将自己 Activity 的父类修改为该类。
2. iOS平台配置
2.1 在自己项目的target下选择Signing & Capabilities 添加Background Modes,勾选Audio,AirPlay,and Picture in Picture
3. 复制superPlayer示例代码
......@@ -600,7 +601,11 @@ SuperPlayerPlugin.instance.onExtraEventBroadcast.listen((event) {
// enter pip mode
} else if (eventCode == TXVodPlayEvent.EVENT_PIP_MODE_ALREADY_ENTER) {
// already enter pip mode
}
} else if (eventCode == TXVodPlayEvent.EVENT_IOS_PIP_MODE_WILL_EXIT) {
// will exit pip mode
} else if (eventCode == TXVodPlayEvent.EVENT_IOS_PIP_MODE_RESTORE_UI) {
// restore UI only support iOS
}
});
```
......@@ -614,6 +619,14 @@ SuperPlayerPlugin.instance.onExtraEventBroadcast.listen((event) {
| ERROR_PIP_LOWER_VERSION | -101 | android版本过低,不支持画中画模式 |
| ERROR_PIP_DENIED_PERMISSION | -102 | 画中画模式权限未打开,或者当前设备不支持画中画 |
| ERROR_PIP_ACTIVITY_DESTROYED | -103 | 当前界面已经销毁 |
| ERROR_IOS_PIP_DEVICE_NOT_SUPPORT | -104 | 设备或系统版本不支持(iPad iOS9+ 才支持PIP) | only support iOS
| ERROR_IOS_PIP_PLAYER_NOT_SUPPORT | -105 | 播放器不支持 | only support iOS
| ERROR_IOS_PIP_VIDEO_NOT_SUPPORT | -106 | 视频不支持 | only support iOS
| ERROR_IOS_PIP_IS_NOT_POSSIBLE | -107 | PIP控制器不可用 | only support iOS
| ERROR_IOS_PIP_FROM_SYSTEM | -108 | PIP控制器报错 | only support iOS
| ERROR_IOS_PIP_PLAYER_NOT_EXIST | -109 | 播放器对象不存在 | only support iOS
| ERROR_IOS_PIP_IS_RUNNING | -110 | PIP功能已经运行 | only support iOS
| ERROR_IOS_PIP_NOT_RUNNING | -111 | PIP功能没有启动 | only support iOS
6. 判断当前设备是否支持画中画
......@@ -628,5 +641,3 @@ if(result == TXVodPlayEvent.NO_ERROR) {
result的返回结果的含义和画中画模式错误码一致
......@@ -150,6 +150,7 @@
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
54EBAF69D81CC6E332D3F9A7 /* [CP] Embed Pods Frameworks */,
5DC08EF8B29C582221073CEB /* [CP] Copy Pods Resources */,
);
buildRules = (
);
......@@ -260,6 +261,23 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
5DC08EF8B29C582221073CEB /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
......
......@@ -27,6 +27,10 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
......
......@@ -16,4 +16,8 @@ class StringResource {
static const BRIGHTNESS_LABEL = "亮度";
static const MULITIPE_SPEED_PLAY_LABEL = "多倍速播放";
static const HARDWARE_ACCE_LABEL = "硬件加速";
static const OPEN_PIP = "正在开启画中画";
static const CLOSE_PIP = "正在关闭画中画";
static const ERROR_PIP = "画中画开启失败";
}
......@@ -11,6 +11,7 @@ import 'package:auto_orientation/auto_orientation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:super_player/super_player.dart';
part 'superplayer_observer.dart';
......
......@@ -90,27 +90,51 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
}
});
// only register listen once
_pipSubscription = SuperPlayerPlugin.instance.onExtraEventBroadcast.listen((event) {
_pipSubscription =
SuperPlayerPlugin.instance.onExtraEventBroadcast.listen((event) {
int eventCode = event["event"];
if (eventCode == TXVodPlayEvent.EVENT_PIP_MODE_ALREADY_EXIT) {
// exit floatingMode
Navigator.of(context).pop();
_isFloatingMode = false;
if (_isPlaying) {
// pause play when exit PIP, prevent user just close PIP, but not back to app
_playController._vodPlayerController?.pause();
if (Platform.isAndroid) {
Navigator.of(context).pop();
if (_isPlaying) {
// pause play when exit PIP, prevent user just close PIP, but not back to app
_playController._vodPlayerController?.pause();
}
} else if (Platform.isIOS) {
EasyLoading.dismiss();
}
_isFloatingMode = false;
} else if (eventCode == TXVodPlayEvent.EVENT_PIP_MODE_REQUEST_START) {
// EVENT_PIP_MODE_ALREADY_ENTER 的状态变化有滞后性,进入PIP之后才会通知,这里需要监听EVENT_PIP_MODE_REQUEST_START,
// 在即将进入PIP模式下就要开始进行PIP模式的UI准备
// enter floatingMode
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return SuperPlayerFloatView(_playController, _aspectRatio);
}));
if (Platform.isAndroid) {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return SuperPlayerFloatView(_playController, _aspectRatio);
}));
} else if (Platform.isIOS) {
EasyLoading.showToast(StringResource.OPEN_PIP);
}
_isFloatingMode = true;
} else if (eventCode == TXVodPlayEvent.EVENT_PIP_MODE_ALREADY_ENTER) {
if (Platform.isIOS) {
EasyLoading.dismiss();
}
} else if (eventCode == TXVodPlayEvent.EVENT_IOS_PIP_MODE_WILL_EXIT) {
if (Platform.isIOS) {
EasyLoading.showToast(StringResource.CLOSE_PIP);
}
} else {
if (Platform.isIOS) {
EasyLoading.showToast(StringResource.ERROR_PIP);
}
_isFloatingMode = false;
print('$eventCode');
}
});
_volumeSubscription = SuperPlayerPlugin.instance.onEventBroadcast.listen((event) {
_volumeSubscription =
SuperPlayerPlugin.instance.onEventBroadcast.listen((event) {
int eventCode = event["event"];
if (_isFloatingMode && _isPlaying) {
if (eventCode == TXVodPlayEvent.EVENT_AUDIO_FOCUS_PAUSE) {
......@@ -327,7 +351,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
Widget _getPipEnterView() {
return Visibility(
visible: _isShowControlView && !_isFullScreen && Platform.isAndroid, // PIP 暂时只支持Android
visible: _isShowControlView && !_isFullScreen,
child: Positioned(
right: 10,
top: 0,
......
......@@ -7,6 +7,27 @@
#define EVENT_AUDIO_FOCUS_PAUSE 0x02
#define EVENT_AUDIO_FOCUS_PLAY 0x03
// 画中画事件code
#define EVENT_PIP_MODE_ALREADY_ENTER 1
#define EVENT_PIP_MODE_ALREADY_EXIT 2
#define EVENT_PIP_MODE_REQUEST_START 3
#define EVENT_PIP_MODE_UI_STATE_CHANGED 4
#define EVENT_PIP_MODE_RESTORE_UI 5
#define EVENT_PIP_MODE_WILL_EXIT 6
// 画中画错误事件code
#define NO_ERROR 0 ///< 无错误
#define ERROR_IOS_PIP_DEVICE_NOT_SUPPORT -104 ///< 设备或系统版本不支持(iPad iOS9+ 才支持PIP)
#define ERROR_IOS_PIP_PLAYER_NOT_SUPPORT -105 ///< 播放器不支持
#define ERROR_IOS_PIP_VIDEO_NOT_SUPPORT -106 ///< 视频不支持
#define ERROR_IOS_PIP_IS_NOT_POSSIBLE -107 ///< PIP控制器不可用
#define ERROR_IOS_PIP_FROM_SYSTEM -108 ///< PIP控制器报错
#define ERROR_IOS_PIP_PLAYER_NOT_EXIST -109 ///< 播放器对象不存在
#define ERROR_IOS_PIP_IS_RUNNING -110 ///< PIP功能已经运行
#define ERROR_IOS_PIP_NOT_RUNNING -111 ///< PIP功能没有启动
// 视频预下载完成
#define EVENT_PREDOWNLOAD_ON_COMPLETE 200
// 视频预下载出错
......
......@@ -7,8 +7,26 @@
NS_ASSUME_NONNULL_BEGIN
@protocol FTXVodPlayerDelegate <NSObject>
- (void)onPlayerPipRequestStart;
- (void)onPlayerPipStateDidStart;
- (void)onPlayerPipStateWillStop;
- (void)onPlayerPipStateDidStop;
- (void)onPlayerPipStateRestoreUI;
- (void)onPlayerPipStateError:(NSInteger)errorId;
@end
@interface FTXVodPlayer : FTXBasePlayer
@property (nonatomic, weak) id<FTXVodPlayerDelegate> delegate;
- (instancetype)initWithRegistrar:(id<FlutterPluginRegistrar>)registrar;
@end
......
......@@ -10,7 +10,7 @@
#import "FTXAudioManager.h"
#import "FTXDownloadManager.h"
@interface SuperPlayerPlugin ()<FlutterStreamHandler>
@interface SuperPlayerPlugin ()<FlutterStreamHandler,FTXVodPlayerDelegate>
@property (nonatomic, strong) NSObject<FlutterPluginRegistrar>* registrar;
@property (nonatomic, strong) NSMutableDictionary *players;
......@@ -20,7 +20,9 @@
@implementation SuperPlayerPlugin {
float orginBrightness;
FlutterEventChannel *_eventChannel;
FlutterEventChannel *_pipEventChannel;
FTXPlayerEventSinkQueue *_eventSink;
FTXPlayerEventSinkQueue *_pipEventSink;
FTXAudioManager *audioManager;
FTXDownloadManager *_FTXDownloadManager;
}
......@@ -57,8 +59,11 @@ SuperPlayerPlugin* instance;
audioManager = [[FTXAudioManager alloc] init];
// volume event stream
_eventSink = [FTXPlayerEventSinkQueue new];
_pipEventSink = [FTXPlayerEventSinkQueue new];
_eventChannel = [FlutterEventChannel eventChannelWithName:@"cloud.tencent.com/playerPlugin/event" binaryMessenger:[registrar messenger]];
_pipEventChannel = [FlutterEventChannel eventChannelWithName:@"cloud.tencent.com/playerPlugin/pipEvent" binaryMessenger:[registrar messenger]];
[_eventChannel setStreamHandler:self];
[_pipEventChannel setStreamHandler:self];
[audioManager registerVolumeChangeListener:self selector:@selector(systemVolumeDidChangeNoti:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
_FTXDownloadManager = [[FTXDownloadManager alloc] initWithRegistrar:registrar];
......@@ -79,6 +84,7 @@ SuperPlayerPlugin* instance;
result(playerId);
}else if([@"createVodPlayer" isEqualToString:call.method]){
FTXVodPlayer* player = [[FTXVodPlayer alloc] initWithRegistrar:self.registrar];
player.delegate = self;
NSNumber *playerId = player.playerId;
_players[playerId] = player;
result(playerId);
......@@ -167,8 +173,11 @@ SuperPlayerPlugin* instance;
int logLevel = [args[@"logLevel"] intValue];
[TXLiveBase setLogLevel:logLevel];
result(nil);
} else if([@"getLiteAVSDKVersion" isEqualToString:call.method]) {
} else if([@"getLiteAVSDKVersion" isEqualToString:call.method]) {
result([TXLiveBase getSDKVersionStr]);
} else if ([@"isDeviceSupportPip" isEqualToString:call.method]) {
BOOL isSupport = [TXVodPlayer isSupportPictureInPicture];
result([NSNumber numberWithBool:isSupport]);
} else {
result(FlutterMethodNotImplemented);
}
......@@ -195,6 +204,7 @@ SuperPlayerPlugin* instance;
if ([arguments isKindOfClass:NSString.class]) {
if ([arguments isEqualToString:@"event"]) {
[_eventSink setDelegate:events];
[_pipEventSink setDelegate:events];
}
}
......@@ -206,10 +216,36 @@ SuperPlayerPlugin* instance;
if ([arguments isKindOfClass:NSString.class]) {
if ([arguments isEqualToString:@"event"]) {
[_eventSink setDelegate:nil];
[_pipEventSink setDelegate:nil];
}
}
return nil;
}
#pragma mark - FTXVodPlayerDelegate
- (void)onPlayerPipRequestStart {
[_pipEventSink success:@{@"event" : @(EVENT_PIP_MODE_REQUEST_START)}];
}
- (void)onPlayerPipStateDidStart {
[_pipEventSink success:@{@"event" : @(EVENT_PIP_MODE_ALREADY_ENTER)}];
}
- (void)onPlayerPipStateWillStop {
[_pipEventSink success:@{@"event" : @(EVENT_PIP_MODE_WILL_EXIT)}];
}
- (void)onPlayerPipStateDidStop {
[_pipEventSink success:@{@"event" : @(EVENT_PIP_MODE_ALREADY_EXIT)}];
}
- (void)onPlayerPipStateError:(NSInteger)errorId {
[_pipEventSink success:@{@"event" : @(errorId)}];
}
- (void)onPlayerPipStateRestoreUI {
[_pipEventSink success:@{@"event" : @(EVENT_PIP_MODE_RESTORE_UI)}];
}
@end
......@@ -4,7 +4,7 @@
#
Pod::Spec.new do |s|
s.name = 'super_player'
s.version = '1.0.2'
s.version = '1.0.3'
s.summary = 'player plugin.'
s.description = <<-DESC
player plugin.
......@@ -20,6 +20,7 @@ player plugin.
s.ios.framework = ['MobileCoreServices']
s.platform = :ios, '9.0'
s.static_framework = true
s.resources = ['Classes/TXResource/**/*']
# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
......
......@@ -94,11 +94,23 @@ abstract class TXVodPlayEvent {
static const EVENT_PIP_MODE_ALREADY_EXIT = 2; // 已经退出画中画模式
static const EVENT_PIP_MODE_REQUEST_START = 3; // 开始请求进入画中画模式
static const EVENT_PIP_MODE_UI_STATE_CHANGED = 4; // pip UI状态发生变动,only support android > 31
static const EVENT_IOS_PIP_MODE_RESTORE_UI = 5; // 重置UI only support iOS
static const EVENT_IOS_PIP_MODE_WILL_EXIT = 6; // 将要退出画中画 only support iOS
static const NO_ERROR = 0;
static const ERROR_PIP_LOWER_VERSION = -101; // pip 错误,android版本过低
static const ERROR_PIP_DENIED_PERMISSION = -102; // pip 错误,画中画权限关闭/设备不支持画中画
static const ERROR_PIP_ACTIVITY_DESTROYED = -103; // pip 错误,当前界面已销毁
static const ERROR_PIP_LOWER_VERSION = -101; // pip 错误,android版本过低
static const ERROR_PIP_DENIED_PERMISSION = -102; // pip 错误,画中画权限关闭/设备不支持画中画
static const ERROR_PIP_ACTIVITY_DESTROYED = -103; // pip 错误,当前界面已销毁
static const ERROR_IOS_PIP_DEVICE_NOT_SUPPORT = -104; // pip 错误,设备或系统版本不支持(iPad iOS9+ 才支持PIP)
static const ERROR_IOS_PIP_PLAYER_NOT_SUPPORT = -105; // pip 错误,播放器不支持 only support iOS
static const ERROR_IOS_PIP_VIDEO_NOT_SUPPORT = -106; // pip 错误,视频不支持 only support iOS
static const ERROR_IOS_PIP_IS_NOT_POSSIBLE = -107; // pip 错误,PIP控制器不可用 only support iOS
static const ERROR_IOS_PIP_FROM_SYSTEM = -108; // pip 错误,PIP控制器报错 only support iOS
static const ERROR_IOS_PIP_PLAYER_NOT_EXIST = -109; // pip 错误,播放器对象不存在 only support iOS
static const ERROR_IOS_PIP_IS_RUNNING = -110; // pip 错误,PIP功能已经运行 only support iOS
static const ERROR_IOS_PIP_NOT_RUNNING = -111; // pip 错误,PIP功能没有启动 only support iOS
/// 视频下载相关事件
static const int EVENT_PREDOWNLOAD_ON_COMPLETE = 200; // 视频预下载完成
......
name: super_player
description: player plugin.
version: 1.0.2
version: 1.0.3
author:
homepage:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论