Skip to content

Commit 7c87a8c

Browse files
authored
[video_player] add http headers (flutter#3671)
This enables to pass HTTP headers to VideoPlayerController.network. Fixes: flutter/flutter#16466
1 parent 809d0de commit 7c87a8c

11 files changed

Lines changed: 144 additions & 44 deletions

File tree

packages/video_player/video_player/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.1.0
2+
3+
* Add `httpHeaders` option to `VideoPlayerController.network`
4+
15
## 2.0.2
26

37
* Fix `VideoPlayerValue` size and aspect ratio documentation

packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
// Autogenerated from Pigeon (v0.1.19), do not edit directly.
5+
// Autogenerated from Pigeon (v0.1.21), do not edit directly.
66
// See also: https://pub.dev/packages/pigeon
77

88
package io.flutter.plugins.videoplayer;
@@ -87,12 +87,23 @@ public void setFormatHint(String setterArg) {
8787
this.formatHint = setterArg;
8888
}
8989

90+
private HashMap httpHeaders;
91+
92+
public HashMap getHttpHeaders() {
93+
return httpHeaders;
94+
}
95+
96+
public void setHttpHeaders(HashMap setterArg) {
97+
this.httpHeaders = setterArg;
98+
}
99+
90100
HashMap toMap() {
91101
HashMap<String, Object> toMapResult = new HashMap<>();
92102
toMapResult.put("asset", asset);
93103
toMapResult.put("uri", uri);
94104
toMapResult.put("packageName", packageName);
95105
toMapResult.put("formatHint", formatHint);
106+
toMapResult.put("httpHeaders", httpHeaders);
96107
return toMapResult;
97108
}
98109

@@ -106,6 +117,8 @@ static CreateMessage fromMap(HashMap map) {
106117
fromMapResult.packageName = (String) packageName;
107118
Object formatHint = map.get("formatHint");
108119
fromMapResult.formatHint = (String) formatHint;
120+
Object httpHeaders = map.get("httpHeaders");
121+
fromMapResult.httpHeaders = (HashMap) httpHeaders;
109122
return fromMapResult;
110123
}
111124
}

packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ final class VideoPlayer {
6565
TextureRegistry.SurfaceTextureEntry textureEntry,
6666
String dataSource,
6767
String formatHint,
68+
Map<String, String> httpHeaders,
6869
VideoPlayerOptions options) {
6970
this.eventChannel = eventChannel;
7071
this.textureEntry = textureEntry;
@@ -76,13 +77,17 @@ final class VideoPlayer {
7677

7778
DataSource.Factory dataSourceFactory;
7879
if (isHTTP(uri)) {
79-
dataSourceFactory =
80+
DefaultHttpDataSourceFactory httpDataSourceFactory =
8081
new DefaultHttpDataSourceFactory(
8182
"ExoPlayer",
8283
null,
8384
DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
8485
DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS,
8586
true);
87+
if (httpHeaders != null && !httpHeaders.isEmpty()) {
88+
httpDataSourceFactory.getDefaultRequestProperties().set(httpHeaders);
89+
}
90+
dataSourceFactory = httpDataSourceFactory;
8691
} else {
8792
dataSourceFactory = new DefaultDataSourceFactory(context, "ExoPlayer");
8893
}

packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import io.flutter.view.TextureRegistry;
2424
import java.security.KeyManagementException;
2525
import java.security.NoSuchAlgorithmException;
26+
import java.util.Map;
2627
import javax.net.ssl.HttpsURLConnection;
2728

2829
/** Android platform implementation of the VideoPlayerPlugin. */
@@ -138,15 +139,19 @@ public TextureMessage create(CreateMessage arg) {
138139
handle,
139140
"asset:///" + assetLookupKey,
140141
null,
142+
null,
141143
options);
142144
} else {
145+
@SuppressWarnings("unchecked")
146+
Map<String, String> httpHeaders = arg.getHttpHeaders();
143147
player =
144148
new VideoPlayer(
145149
flutterState.applicationContext,
146150
eventChannel,
147151
handle,
148152
arg.getUri(),
149153
arg.getFormatHint(),
154+
httpHeaders,
150155
options);
151156
}
152157
videoPlayers.put(handle.id(), player);

packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ @interface FLTVideoPlayer : NSObject <FlutterTexture, FlutterStreamHandler>
4646
@property(nonatomic, readonly) bool isPlaying;
4747
@property(nonatomic) bool isLooping;
4848
@property(nonatomic, readonly) bool isInitialized;
49-
- (instancetype)initWithURL:(NSURL*)url frameUpdater:(FLTFrameUpdater*)frameUpdater;
49+
- (instancetype)initWithURL:(NSURL*)url
50+
frameUpdater:(FLTFrameUpdater*)frameUpdater
51+
httpHeaders:(NSDictionary<NSString*, NSString*>*)headers;
5052
- (void)play;
5153
- (void)pause;
5254
- (void)setIsLooping:(bool)isLooping;
@@ -62,7 +64,7 @@ - (void)updatePlayingState;
6264
@implementation FLTVideoPlayer
6365
- (instancetype)initWithAsset:(NSString*)asset frameUpdater:(FLTFrameUpdater*)frameUpdater {
6466
NSString* path = [[NSBundle mainBundle] pathForResource:asset ofType:nil];
65-
return [self initWithURL:[NSURL fileURLWithPath:path] frameUpdater:frameUpdater];
67+
return [self initWithURL:[NSURL fileURLWithPath:path] frameUpdater:frameUpdater httpHeaders:nil];
6668
}
6769

6870
- (void)addObservers:(AVPlayerItem*)item {
@@ -162,8 +164,15 @@ - (void)createVideoOutputAndDisplayLink:(FLTFrameUpdater*)frameUpdater {
162164
_displayLink.paused = YES;
163165
}
164166

165-
- (instancetype)initWithURL:(NSURL*)url frameUpdater:(FLTFrameUpdater*)frameUpdater {
166-
AVPlayerItem* item = [AVPlayerItem playerItemWithURL:url];
167+
- (instancetype)initWithURL:(NSURL*)url
168+
frameUpdater:(FLTFrameUpdater*)frameUpdater
169+
httpHeaders:(NSDictionary<NSString*, NSString*>*)headers {
170+
NSDictionary<NSString*, id>* options = nil;
171+
if (headers != nil && [headers count] != 0) {
172+
options = @{@"AVURLAssetHTTPHeaderFieldsKey" : headers};
173+
}
174+
AVURLAsset* urlAsset = [AVURLAsset URLAssetWithURL:url options:options];
175+
AVPlayerItem* item = [AVPlayerItem playerItemWithAsset:urlAsset];
167176
return [self initWithPlayerItem:item frameUpdater:frameUpdater];
168177
}
169178

@@ -522,7 +531,8 @@ - (FLTTextureMessage*)create:(FLTCreateMessage*)input error:(FlutterError**)erro
522531
return [self onPlayerSetup:player frameUpdater:frameUpdater];
523532
} else if (input.uri) {
524533
player = [[FLTVideoPlayer alloc] initWithURL:[NSURL URLWithString:input.uri]
525-
frameUpdater:frameUpdater];
534+
frameUpdater:frameUpdater
535+
httpHeaders:input.httpHeaders];
526536
return [self onPlayerSetup:player frameUpdater:frameUpdater];
527537
} else {
528538
*error = [FlutterError errorWithCode:@"video_player" message:@"not implemented" details:nil];

packages/video_player/video_player/ios/Classes/messages.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
// Autogenerated from Pigeon (v0.1.19), do not edit directly.
5+
// Autogenerated from Pigeon (v0.1.21), do not edit directly.
66
// See also: https://pub.dev/packages/pigeon
77
#import <Foundation/Foundation.h>
88
@protocol FlutterBinaryMessenger;
@@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
2828
@property(nonatomic, copy, nullable) NSString *uri;
2929
@property(nonatomic, copy, nullable) NSString *packageName;
3030
@property(nonatomic, copy, nullable) NSString *formatHint;
31+
@property(nonatomic, strong, nullable) NSDictionary *httpHeaders;
3132
@end
3233

3334
@interface FLTLoopingMessage : NSObject

packages/video_player/video_player/ios/Classes/messages.m

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
// Autogenerated from Pigeon (v0.1.19), do not edit directly.
5+
// Autogenerated from Pigeon (v0.1.21), do not edit directly.
66
// See also: https://pub.dev/packages/pigeon
77
#import "messages.h"
88
#import <Flutter/Flutter.h>
@@ -11,18 +11,19 @@
1111
#error File requires ARC to be enabled.
1212
#endif
1313

14-
#ifndef __clang_analyzer__
15-
static NSDictionary *wrapResult(NSDictionary *result, FlutterError *error) {
14+
static NSDictionary<NSString *, id> *wrapResult(NSDictionary *result, FlutterError *error) {
1615
NSDictionary *errorDict = (NSDictionary *)[NSNull null];
1716
if (error) {
18-
errorDict = [NSDictionary
19-
dictionaryWithObjectsAndKeys:(error.code ? error.code : [NSNull null]), @"code",
20-
(error.message ? error.message : [NSNull null]), @"message",
21-
(error.details ? error.details : [NSNull null]), @"details",
22-
nil];
17+
errorDict = @{
18+
@"code" : (error.code ? error.code : [NSNull null]),
19+
@"message" : (error.message ? error.message : [NSNull null]),
20+
@"details" : (error.details ? error.details : [NSNull null]),
21+
};
2322
}
24-
return [NSDictionary dictionaryWithObjectsAndKeys:(result ? result : [NSNull null]), @"result",
25-
errorDict, @"error", nil];
23+
return @{
24+
@"result" : (result ? result : [NSNull null]),
25+
@"error" : errorDict,
26+
};
2627
}
2728

2829
@interface FLTTextureMessage ()
@@ -89,6 +90,10 @@ + (FLTCreateMessage *)fromMap:(NSDictionary *)dict {
8990
if ((NSNull *)result.formatHint == [NSNull null]) {
9091
result.formatHint = nil;
9192
}
93+
result.httpHeaders = dict[@"httpHeaders"];
94+
if ((NSNull *)result.httpHeaders == [NSNull null]) {
95+
result.httpHeaders = nil;
96+
}
9297
return result;
9398
}
9499
- (NSDictionary *)toMap {
@@ -98,7 +103,9 @@ - (NSDictionary *)toMap {
98103
(self.packageName ? self.packageName : [NSNull null]),
99104
@"packageName",
100105
(self.formatHint ? self.formatHint : [NSNull null]),
101-
@"formatHint", nil];
106+
@"formatHint",
107+
(self.httpHeaders ? self.httpHeaders : [NSNull null]),
108+
@"httpHeaders", nil];
102109
}
103110
@end
104111

@@ -221,8 +228,8 @@ void FLTVideoPlayerApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<FLTVi
221228
binaryMessenger:binaryMessenger];
222229
if (api) {
223230
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
224-
FlutterError *error;
225231
FLTCreateMessage *input = [FLTCreateMessage fromMap:message];
232+
FlutterError *error;
226233
FLTTextureMessage *output = [api create:input error:&error];
227234
callback(wrapResult([output toMap], error));
228235
}];
@@ -236,8 +243,8 @@ void FLTVideoPlayerApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<FLTVi
236243
binaryMessenger:binaryMessenger];
237244
if (api) {
238245
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
239-
FlutterError *error;
240246
FLTTextureMessage *input = [FLTTextureMessage fromMap:message];
247+
FlutterError *error;
241248
[api dispose:input error:&error];
242249
callback(wrapResult(nil, error));
243250
}];
@@ -251,8 +258,8 @@ void FLTVideoPlayerApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<FLTVi
251258
binaryMessenger:binaryMessenger];
252259
if (api) {
253260
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
254-
FlutterError *error;
255261
FLTLoopingMessage *input = [FLTLoopingMessage fromMap:message];
262+
FlutterError *error;
256263
[api setLooping:input error:&error];
257264
callback(wrapResult(nil, error));
258265
}];
@@ -266,8 +273,8 @@ void FLTVideoPlayerApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<FLTVi
266273
binaryMessenger:binaryMessenger];
267274
if (api) {
268275
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
269-
FlutterError *error;
270276
FLTVolumeMessage *input = [FLTVolumeMessage fromMap:message];
277+
FlutterError *error;
271278
[api setVolume:input error:&error];
272279
callback(wrapResult(nil, error));
273280
}];
@@ -281,8 +288,8 @@ void FLTVideoPlayerApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<FLTVi
281288
binaryMessenger:binaryMessenger];
282289
if (api) {
283290
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
284-
FlutterError *error;
285291
FLTPlaybackSpeedMessage *input = [FLTPlaybackSpeedMessage fromMap:message];
292+
FlutterError *error;
286293
[api setPlaybackSpeed:input error:&error];
287294
callback(wrapResult(nil, error));
288295
}];
@@ -296,8 +303,8 @@ void FLTVideoPlayerApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<FLTVi
296303
binaryMessenger:binaryMessenger];
297304
if (api) {
298305
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
299-
FlutterError *error;
300306
FLTTextureMessage *input = [FLTTextureMessage fromMap:message];
307+
FlutterError *error;
301308
[api play:input error:&error];
302309
callback(wrapResult(nil, error));
303310
}];
@@ -311,8 +318,8 @@ void FLTVideoPlayerApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<FLTVi
311318
binaryMessenger:binaryMessenger];
312319
if (api) {
313320
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
314-
FlutterError *error;
315321
FLTTextureMessage *input = [FLTTextureMessage fromMap:message];
322+
FlutterError *error;
316323
FLTPositionMessage *output = [api position:input error:&error];
317324
callback(wrapResult([output toMap], error));
318325
}];
@@ -326,8 +333,8 @@ void FLTVideoPlayerApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<FLTVi
326333
binaryMessenger:binaryMessenger];
327334
if (api) {
328335
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
329-
FlutterError *error;
330336
FLTPositionMessage *input = [FLTPositionMessage fromMap:message];
337+
FlutterError *error;
331338
[api seekTo:input error:&error];
332339
callback(wrapResult(nil, error));
333340
}];
@@ -341,8 +348,8 @@ void FLTVideoPlayerApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<FLTVi
341348
binaryMessenger:binaryMessenger];
342349
if (api) {
343350
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
344-
FlutterError *error;
345351
FLTTextureMessage *input = [FLTTextureMessage fromMap:message];
352+
FlutterError *error;
346353
[api pause:input error:&error];
347354
callback(wrapResult(nil, error));
348355
}];
@@ -356,8 +363,8 @@ void FLTVideoPlayerApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<FLTVi
356363
binaryMessenger:binaryMessenger];
357364
if (api) {
358365
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
359-
FlutterError *error;
360366
FLTMixWithOthersMessage *input = [FLTMixWithOthersMessage fromMap:message];
367+
FlutterError *error;
361368
[api setMixWithOthers:input error:&error];
362369
callback(wrapResult(nil, error));
363370
}];
@@ -366,4 +373,3 @@ void FLTVideoPlayerApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<FLTVi
366373
}
367374
}
368375
}
369-
#endif

packages/video_player/video_player/lib/video_player.dart

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
187187
{this.package, this.closedCaptionFile, this.videoPlayerOptions})
188188
: dataSourceType = DataSourceType.asset,
189189
formatHint = null,
190+
httpHeaders = const {},
190191
super(VideoPlayerValue(duration: Duration.zero));
191192

192193
/// Constructs a [VideoPlayerController] playing a video from obtained from
@@ -196,9 +197,15 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
196197
/// null.
197198
/// **Android only**: The [formatHint] option allows the caller to override
198199
/// the video format detection code.
199-
VideoPlayerController.network(this.dataSource,
200-
{this.formatHint, this.closedCaptionFile, this.videoPlayerOptions})
201-
: dataSourceType = DataSourceType.network,
200+
/// [httpHeaders] option allows to specify HTTP headers
201+
/// for the request to the [dataSource].
202+
VideoPlayerController.network(
203+
this.dataSource, {
204+
this.formatHint,
205+
this.closedCaptionFile,
206+
this.videoPlayerOptions,
207+
this.httpHeaders = const {},
208+
}) : dataSourceType = DataSourceType.network,
202209
package = null,
203210
super(VideoPlayerValue(duration: Duration.zero));
204211

@@ -212,12 +219,18 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
212219
dataSourceType = DataSourceType.file,
213220
package = null,
214221
formatHint = null,
222+
httpHeaders = const {},
215223
super(VideoPlayerValue(duration: Duration.zero));
216224

217225
/// The URI to the video file. This will be in different formats depending on
218226
/// the [DataSourceType] of the original video.
219227
final String dataSource;
220228

229+
/// HTTP headers used for the request to the [dataSource].
230+
/// Only for [VideoPlayerController.network].
231+
/// Always empty for other video types.
232+
final Map<String, String> httpHeaders;
233+
221234
/// **Android only**. Will override the platform's generic file format
222235
/// detection with whatever is set here.
223236
final VideoFormat? formatHint;
@@ -276,6 +289,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
276289
sourceType: DataSourceType.network,
277290
uri: dataSource,
278291
formatHint: formatHint,
292+
httpHeaders: httpHeaders,
279293
);
280294
break;
281295
case DataSourceType.file:

packages/video_player/video_player/pigeons/messages.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class CreateMessage {
3535
String uri;
3636
String packageName;
3737
String formatHint;
38+
Map<String, String> httpHeaders;
3839
}
3940

4041
class MixWithOthersMessage {

0 commit comments

Comments
 (0)