From 223adef79930c219994b4a9e63a4a9cdbbe782de Mon Sep 17 00:00:00 2001 From: Ryan Cunningham Date: Thu, 29 Nov 2018 13:57:12 -0800 Subject: [PATCH 1/4] add http headers option when loading network data source --- .../videoplayer/VideoPlayerPlugin.java | 64 ++++++++++++++++++- .../ios/Classes/VideoPlayerPlugin.m | 15 +++-- packages/video_player/lib/video_player.dart | 10 ++- 3 files changed, 81 insertions(+), 8 deletions(-) diff --git a/packages/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java b/packages/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java index 2b730214068d..72f35c8ef92d 100644 --- a/packages/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java +++ b/packages/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java @@ -12,6 +12,7 @@ import android.net.Uri; import android.os.Build; import android.view.Surface; +import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayerFactory; @@ -33,6 +34,10 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.DefaultHttpDataSource; import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; +import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory; +import com.google.android.exoplayer2.upstream.HttpDataSource.Factory; +import com.google.android.exoplayer2.upstream.HttpDataSource.RequestProperties; +import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.util.Util; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodCall; @@ -51,6 +56,57 @@ public class VideoPlayerPlugin implements MethodCallHandler { + // near copy and paste from final class DefaultHttpDataSourceFactory + private static class VideoPlayerHttpDataSourceFactory extends BaseFactory { + private final String userAgent; + private final @Nullable TransferListener listener; + private final int connectTimeoutMillis; + private final int readTimeoutMillis; + private final boolean allowCrossProtocolRedirects; + + private final Map headers; + + public VideoPlayerHttpDataSourceFactory( + String userAgent, + @Nullable TransferListener listener, + int connectTimeoutMillis, + int readTimeoutMillis, + boolean allowCrossProtocolRedirects, + Map headers) { + this.userAgent = userAgent; + this.listener = listener; + this.connectTimeoutMillis = connectTimeoutMillis; + this.readTimeoutMillis = readTimeoutMillis; + this.allowCrossProtocolRedirects = allowCrossProtocolRedirects; + this.headers = headers; + } + + @Override + protected DefaultHttpDataSource createDataSourceInternal( + RequestProperties defaultRequestProperties) { + if (this.headers != null) { + if (defaultRequestProperties == null) { + defaultRequestProperties = new RequestProperties(); + } + for (Map.Entry header : this.headers.entrySet()) { + defaultRequestProperties.set(header.getKey(), header.getValue()); + } + } + DefaultHttpDataSource dataSource = + new DefaultHttpDataSource( + userAgent, + /* contentTypePredicate= */ null, + connectTimeoutMillis, + readTimeoutMillis, + allowCrossProtocolRedirects, + defaultRequestProperties); + if (listener != null) { + dataSource.addTransferListener(listener); + } + return dataSource; + } + } + private static class VideoPlayer { private SimpleExoPlayer exoPlayer; @@ -70,6 +126,7 @@ private static class VideoPlayer { EventChannel eventChannel, TextureRegistry.SurfaceTextureEntry textureEntry, String dataSource, + Map headers, Result result) { this.eventChannel = eventChannel; this.textureEntry = textureEntry; @@ -84,12 +141,13 @@ private static class VideoPlayer { dataSourceFactory = new DefaultDataSourceFactory(context, "ExoPlayer"); } else { dataSourceFactory = - new DefaultHttpDataSourceFactory( + new VideoPlayerHttpDataSourceFactory( "ExoPlayer", null, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, - true); + true, + headers); } MediaSource mediaSource = buildMediaSource(uri, dataSourceFactory, context); @@ -315,6 +373,7 @@ public void onMethodCall(MethodCall call, Result result) { eventChannel, handle, "asset:///" + assetLookupKey, + null, result); videoPlayers.put(handle.id(), player); } else { @@ -324,6 +383,7 @@ public void onMethodCall(MethodCall call, Result result) { eventChannel, handle, (String) call.argument("uri"), + (Map) call.argument("headers"), result); videoPlayers.put(handle.id(), player); } diff --git a/packages/video_player/ios/Classes/VideoPlayerPlugin.m b/packages/video_player/ios/Classes/VideoPlayerPlugin.m index aeec622ce7b6..b6f7726dfddb 100644 --- a/packages/video_player/ios/Classes/VideoPlayerPlugin.m +++ b/packages/video_player/ios/Classes/VideoPlayerPlugin.m @@ -52,17 +52,23 @@ - (void)updatePlayingState; @implementation FLTVideoPlayer - (instancetype)initWithAsset:(NSString*)asset frameUpdater:(FLTFrameUpdater*)frameUpdater { NSString* path = [[NSBundle mainBundle] pathForResource:asset ofType:nil]; - return [self initWithURL:[NSURL fileURLWithPath:path] frameUpdater:frameUpdater]; + return [self initWithURL:[NSURL fileURLWithPath:path] headers:nil frameUpdater:frameUpdater]; } -- (instancetype)initWithURL:(NSURL*)url frameUpdater:(FLTFrameUpdater*)frameUpdater { +- (instancetype)initWithURL:(NSURL*)url headers:(NSDictionary*)headers frameUpdater:(FLTFrameUpdater*)frameUpdater { self = [super init]; NSAssert(self, @"super init cannot be nil"); _isInitialized = false; _isPlaying = false; _disposed = false; - AVPlayerItem* item = [AVPlayerItem playerItemWithURL:url]; + AVPlayerItem* item; + if (headers) { + AVURLAsset * asset = [AVURLAsset URLAssetWithURL:url options:@{@"AVURLAssetHTTPHeaderFieldsKey" : headers}]; + item = [AVPlayerItem playerItemWithAsset:asset]; + } else { + item = [AVPlayerItem playerItemWithURL:url]; + } [item addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew @@ -340,7 +346,8 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { player = [[FLTVideoPlayer alloc] initWithAsset:assetPath frameUpdater:frameUpdater]; } else { dataSource = argsMap[@"uri"]; - player = [[FLTVideoPlayer alloc] initWithURL:[NSURL URLWithString:dataSource] + NSDictionary* headers = argsMap[@"headers"]; + player = [[FLTVideoPlayer alloc] initWithURL:[NSURL URLWithString:dataSource] headers:headers frameUpdater:frameUpdater]; } int64_t textureId = [_registry registerTexture:player]; diff --git a/packages/video_player/lib/video_player.dart b/packages/video_player/lib/video_player.dart index c297078bf8f9..0b1e5fb5fe06 100644 --- a/packages/video_player/lib/video_player.dart +++ b/packages/video_player/lib/video_player.dart @@ -148,6 +148,7 @@ class VideoPlayerController extends ValueNotifier { /// package and null otherwise. VideoPlayerController.asset(this.dataSource, {this.package}) : dataSourceType = DataSourceType.asset, + headers = null, super(VideoPlayerValue(duration: null)); /// Constructs a [VideoPlayerController] playing a video from obtained from @@ -155,7 +156,7 @@ class VideoPlayerController extends ValueNotifier { /// /// The URI for the video is given by the [dataSource] argument and must not be /// null. - VideoPlayerController.network(this.dataSource) + VideoPlayerController.network(this.dataSource, {this.headers}) : dataSourceType = DataSourceType.network, package = null, super(VideoPlayerValue(duration: null)); @@ -168,10 +169,12 @@ class VideoPlayerController extends ValueNotifier { : dataSource = 'file://${file.path}', dataSourceType = DataSourceType.file, package = null, + headers = null, super(VideoPlayerValue(duration: null)); int _textureId; final String dataSource; + final Map headers; /// Describes the type of data source this [VideoPlayerController] /// is constructed with. @@ -200,7 +203,10 @@ class VideoPlayerController extends ValueNotifier { }; break; case DataSourceType.network: - dataSourceDescription = {'uri': dataSource}; + dataSourceDescription = { + 'uri': dataSource, + 'headers': headers + }; break; case DataSourceType.file: dataSourceDescription = {'uri': dataSource}; From ed310b894d6b6bdd72881e444e88e330d95f0153 Mon Sep 17 00:00:00 2001 From: Ryan Cunningham Date: Sat, 1 Dec 2018 15:51:43 -0800 Subject: [PATCH 2/4] fix format and missing test impl member --- .../videoplayer/VideoPlayerPlugin.java | 19 ++++++++----------- .../ios/Classes/VideoPlayerPlugin.m | 12 ++++++++---- .../video_player/test/video_player_test.dart | 2 ++ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/packages/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java b/packages/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java index 72f35c8ef92d..4e7a975afd29 100644 --- a/packages/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java +++ b/packages/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java @@ -11,8 +11,8 @@ import android.media.AudioManager; import android.net.Uri; import android.os.Build; -import android.view.Surface; import android.support.annotation.Nullable; +import android.view.Surface; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayerFactory; @@ -33,9 +33,7 @@ import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.DefaultHttpDataSource; -import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory; -import com.google.android.exoplayer2.upstream.HttpDataSource.Factory; import com.google.android.exoplayer2.upstream.HttpDataSource.RequestProperties; import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.util.Util; @@ -63,7 +61,6 @@ private static class VideoPlayerHttpDataSourceFactory extends BaseFactory { private final int connectTimeoutMillis; private final int readTimeoutMillis; private final boolean allowCrossProtocolRedirects; - private final Map headers; public VideoPlayerHttpDataSourceFactory( @@ -93,13 +90,13 @@ protected DefaultHttpDataSource createDataSourceInternal( } } DefaultHttpDataSource dataSource = - new DefaultHttpDataSource( - userAgent, - /* contentTypePredicate= */ null, - connectTimeoutMillis, - readTimeoutMillis, - allowCrossProtocolRedirects, - defaultRequestProperties); + new DefaultHttpDataSource( + userAgent, + /* contentTypePredicate= */ null, + connectTimeoutMillis, + readTimeoutMillis, + allowCrossProtocolRedirects, + defaultRequestProperties); if (listener != null) { dataSource.addTransferListener(listener); } diff --git a/packages/video_player/ios/Classes/VideoPlayerPlugin.m b/packages/video_player/ios/Classes/VideoPlayerPlugin.m index b6f7726dfddb..dbb6fac9f70a 100644 --- a/packages/video_player/ios/Classes/VideoPlayerPlugin.m +++ b/packages/video_player/ios/Classes/VideoPlayerPlugin.m @@ -36,7 +36,7 @@ @interface FLTVideoPlayer : NSObject @property(nonatomic, readonly) bool isPlaying; @property(nonatomic, readonly) bool isLooping; @property(nonatomic, readonly) bool isInitialized; -- (instancetype)initWithURL:(NSURL*)url frameUpdater:(FLTFrameUpdater*)frameUpdater; +- (instancetype)initWithURL:(NSURL*)url headers:nil frameUpdater:(FLTFrameUpdater*)frameUpdater; - (void)play; - (void)pause; - (void)setIsLooping:(bool)isLooping; @@ -55,7 +55,9 @@ - (instancetype)initWithAsset:(NSString*)asset frameUpdater:(FLTFrameUpdater*)fr return [self initWithURL:[NSURL fileURLWithPath:path] headers:nil frameUpdater:frameUpdater]; } -- (instancetype)initWithURL:(NSURL*)url headers:(NSDictionary*)headers frameUpdater:(FLTFrameUpdater*)frameUpdater { +- (instancetype)initWithURL:(NSURL*)url + headers:(NSDictionary*)headers + frameUpdater:(FLTFrameUpdater*)frameUpdater { self = [super init]; NSAssert(self, @"super init cannot be nil"); _isInitialized = false; @@ -64,7 +66,8 @@ - (instancetype)initWithURL:(NSURL*)url headers:(NSDictionary*)headers frameUpda AVPlayerItem* item; if (headers) { - AVURLAsset * asset = [AVURLAsset URLAssetWithURL:url options:@{@"AVURLAssetHTTPHeaderFieldsKey" : headers}]; + AVURLAsset* asset = [AVURLAsset URLAssetWithURL:url + options:@{@"AVURLAssetHTTPHeaderFieldsKey" : headers}]; item = [AVPlayerItem playerItemWithAsset:asset]; } else { item = [AVPlayerItem playerItemWithURL:url]; @@ -347,7 +350,8 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { } else { dataSource = argsMap[@"uri"]; NSDictionary* headers = argsMap[@"headers"]; - player = [[FLTVideoPlayer alloc] initWithURL:[NSURL URLWithString:dataSource] headers:headers + player = [[FLTVideoPlayer alloc] initWithURL:[NSURL URLWithString:dataSource] + headers:headers frameUpdater:frameUpdater]; } int64_t textureId = [_registry registerTexture:player]; diff --git a/packages/video_player/test/video_player_test.dart b/packages/video_player/test/video_player_test.dart index 22dd9a2e3e67..1400d4a86858 100644 --- a/packages/video_player/test/video_player_test.dart +++ b/packages/video_player/test/video_player_test.dart @@ -19,6 +19,8 @@ class FakeController extends ValueNotifier @override String get dataSource => ''; @override + Map get headers => null; + @override DataSourceType get dataSourceType => DataSourceType.file; @override String get package => null; From 4a9d07b9af5e5a6abdae01e7a87c90b4df7a18a1 Mon Sep 17 00:00:00 2001 From: Ryan Cunningham Date: Sat, 1 Dec 2018 16:05:02 -0800 Subject: [PATCH 3/4] fix typo in initWithURL method declaration --- packages/video_player/ios/Classes/VideoPlayerPlugin.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/video_player/ios/Classes/VideoPlayerPlugin.m b/packages/video_player/ios/Classes/VideoPlayerPlugin.m index dbb6fac9f70a..4041c931cbdf 100644 --- a/packages/video_player/ios/Classes/VideoPlayerPlugin.m +++ b/packages/video_player/ios/Classes/VideoPlayerPlugin.m @@ -36,7 +36,7 @@ @interface FLTVideoPlayer : NSObject @property(nonatomic, readonly) bool isPlaying; @property(nonatomic, readonly) bool isLooping; @property(nonatomic, readonly) bool isInitialized; -- (instancetype)initWithURL:(NSURL*)url headers:nil frameUpdater:(FLTFrameUpdater*)frameUpdater; +- (instancetype)initWithURL:(NSURL*)url headers:(NSDictionary*)headers frameUpdater:(FLTFrameUpdater*)frameUpdater; - (void)play; - (void)pause; - (void)setIsLooping:(bool)isLooping; From 5cd8c57640a95aab75f66bc7a0414b2013b9c388 Mon Sep 17 00:00:00 2001 From: Ryan Cunningham Date: Sat, 1 Dec 2018 16:12:26 -0800 Subject: [PATCH 4/4] one more try on format --- packages/video_player/ios/Classes/VideoPlayerPlugin.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/video_player/ios/Classes/VideoPlayerPlugin.m b/packages/video_player/ios/Classes/VideoPlayerPlugin.m index 4041c931cbdf..5d936659f5f8 100644 --- a/packages/video_player/ios/Classes/VideoPlayerPlugin.m +++ b/packages/video_player/ios/Classes/VideoPlayerPlugin.m @@ -36,7 +36,9 @@ @interface FLTVideoPlayer : NSObject @property(nonatomic, readonly) bool isPlaying; @property(nonatomic, readonly) bool isLooping; @property(nonatomic, readonly) bool isInitialized; -- (instancetype)initWithURL:(NSURL*)url headers:(NSDictionary*)headers frameUpdater:(FLTFrameUpdater*)frameUpdater; +- (instancetype)initWithURL:(NSURL*)url + headers:(NSDictionary*)headers + frameUpdater:(FLTFrameUpdater*)frameUpdater; - (void)play; - (void)pause; - (void)setIsLooping:(bool)isLooping;