added optional request headers for remote assests (android & ios)

This commit is contained in:
Emrah Kaya 2017-10-02 20:11:41 +02:00
parent f73b7a0484
commit 270fdfb657
7 changed files with 119 additions and 19 deletions

View File

@ -24,6 +24,16 @@ export default class Video extends Component {
this._root.setNativeProps(nativeProps); this._root.setNativeProps(nativeProps);
} }
stringsOnlyObject(obj) {
const strObj = {};
Object.keys(obj).forEach(x => {
strObj[x] = obj[x].toString();
});
return strObj;
}
seek = (time) => { seek = (time) => {
this.setNativeProps({ seek: time }); this.setNativeProps({ seek: time });
}; };
@ -190,6 +200,7 @@ export default class Video extends Component {
type: source.type || '', type: source.type || '',
mainVer: source.mainVer || 0, mainVer: source.mainVer || 0,
patchVer: source.patchVer || 0, patchVer: source.patchVer || 0,
requestHeaders: source.headers ? this.stringsOnlyObject(source.headers) : {}
}, },
onVideoLoadStart: this._onLoadStart, onVideoLoadStart: this._onLoadStart,
onVideoLoad: this._onLoad, onVideoLoad: this._onLoad,

View File

@ -1,7 +1,10 @@
package com.brentvatne.exoplayer; package com.brentvatne.exoplayer;
import android.content.Context; import android.content.Context;
import android.util.ArrayMap;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableNativeMap;
import com.facebook.react.modules.network.OkHttpClientProvider; import com.facebook.react.modules.network.OkHttpClientProvider;
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSourceFactory; import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSourceFactory;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
@ -10,6 +13,10 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class DataSourceUtil { public class DataSourceUtil {
private DataSourceUtil() { private DataSourceUtil() {
@ -41,9 +48,9 @@ public class DataSourceUtil {
DataSourceUtil.rawDataSourceFactory = factory; DataSourceUtil.rawDataSourceFactory = factory;
} }
public static DataSource.Factory getDefaultDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter) { public static DataSource.Factory getDefaultDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter, Map<String, String> requestHeaders) {
if (defaultDataSourceFactory == null) { if (defaultDataSourceFactory == null) {
defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter); defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter, requestHeaders);
} }
return defaultDataSourceFactory; return defaultDataSourceFactory;
} }
@ -56,14 +63,18 @@ public class DataSourceUtil {
return new RawResourceDataSourceFactory(context.getApplicationContext()); return new RawResourceDataSourceFactory(context.getApplicationContext());
} }
private static DataSource.Factory buildDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter) { private static DataSource.Factory buildDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter, Map<String, String> requestHeaders) {
Context appContext = context.getApplicationContext(); Context appContext = context.getApplicationContext();
return new DefaultDataSourceFactory(appContext, bandwidthMeter, return new DefaultDataSourceFactory(appContext, bandwidthMeter,
buildHttpDataSourceFactory(appContext, bandwidthMeter)); buildHttpDataSourceFactory(appContext, bandwidthMeter, requestHeaders));
} }
private static HttpDataSource.Factory buildHttpDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter) { private static HttpDataSource.Factory buildHttpDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter, Map<String, String> requestHeaders) {
return new OkHttpDataSourceFactory(OkHttpClientProvider.getOkHttpClient(), getUserAgent(context), bandwidthMeter); OkHttpDataSourceFactory okHttpDataSourceFactory = new OkHttpDataSourceFactory(OkHttpClientProvider.getOkHttpClient(), getUserAgent(context), bandwidthMeter);
}
if (requestHeaders != null)
okHttpDataSourceFactory.getDefaultRequestProperties().set(requestHeaders);
return okHttpDataSourceFactory;
}
} }

View File

@ -14,6 +14,7 @@ import com.brentvatne.react.R;
import com.brentvatne.receiver.AudioBecomingNoisyReceiver; import com.brentvatne.receiver.AudioBecomingNoisyReceiver;
import com.brentvatne.receiver.BecomingNoisyListener; import com.brentvatne.receiver.BecomingNoisyListener;
import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ThemedReactContext;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl; import com.google.android.exoplayer2.DefaultLoadControl;
@ -52,6 +53,7 @@ import java.net.CookieHandler;
import java.net.CookieManager; import java.net.CookieManager;
import java.net.CookiePolicy; import java.net.CookiePolicy;
import java.lang.Math; import java.lang.Math;
import java.util.Map;
@SuppressLint("ViewConstructor") @SuppressLint("ViewConstructor")
class ReactExoplayerView extends FrameLayout implements class ReactExoplayerView extends FrameLayout implements
@ -96,6 +98,7 @@ class ReactExoplayerView extends FrameLayout implements
private boolean disableFocus; private boolean disableFocus;
private float mProgressUpdateInterval = 250.0f; private float mProgressUpdateInterval = 250.0f;
private boolean playInBackground = false; private boolean playInBackground = false;
private Map<String, String> requestHeaders;
// \ End props // \ End props
// React // React
@ -353,7 +356,7 @@ class ReactExoplayerView extends FrameLayout implements
* @return A new DataSource factory. * @return A new DataSource factory.
*/ */
private DataSource.Factory buildDataSourceFactory(boolean useBandwidthMeter) { private DataSource.Factory buildDataSourceFactory(boolean useBandwidthMeter) {
return DataSourceUtil.getDefaultDataSourceFactory(getContext(), useBandwidthMeter ? BANDWIDTH_METER : null); return DataSourceUtil.getDefaultDataSourceFactory(getContext(), useBandwidthMeter ? BANDWIDTH_METER : null, requestHeaders);
} }
// AudioManager.OnAudioFocusChangeListener implementation // AudioManager.OnAudioFocusChangeListener implementation
@ -537,14 +540,15 @@ class ReactExoplayerView extends FrameLayout implements
// ReactExoplayerViewManager public api // ReactExoplayerViewManager public api
public void setSrc(final Uri uri, final String extension) { public void setSrc(final Uri uri, final String extension, Map<String, String> headers) {
if (uri != null) { if (uri != null) {
boolean isOriginalSourceNull = srcUri == null; boolean isOriginalSourceNull = srcUri == null;
boolean isSourceEqual = uri.equals(srcUri); boolean isSourceEqual = uri.equals(srcUri);
this.srcUri = uri; this.srcUri = uri;
this.extension = extension; this.extension = extension;
this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(getContext(), BANDWIDTH_METER); this.requestHeaders = headers;
this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(getContext(), BANDWIDTH_METER, requestHeaders);
if (!isOriginalSourceNull && !isSourceEqual) { if (!isOriginalSourceNull && !isSourceEqual) {
reloadSource(); reloadSource();

View File

@ -11,6 +11,7 @@ import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.annotations.ReactProp;
import com.google.android.exoplayer2.upstream.RawResourceDataSource; import com.google.android.exoplayer2.upstream.RawResourceDataSource;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -22,6 +23,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
private static final String PROP_SRC = "src"; private static final String PROP_SRC = "src";
private static final String PROP_SRC_URI = "uri"; private static final String PROP_SRC_URI = "uri";
private static final String PROP_SRC_TYPE = "type"; private static final String PROP_SRC_TYPE = "type";
private static final String PROP_SRC_HEADERS = "headers";
private static final String PROP_RESIZE_MODE = "resizeMode"; private static final String PROP_RESIZE_MODE = "resizeMode";
private static final String PROP_REPEAT = "repeat"; private static final String PROP_REPEAT = "repeat";
private static final String PROP_PAUSED = "paused"; private static final String PROP_PAUSED = "paused";
@ -72,6 +74,8 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
Context context = videoView.getContext().getApplicationContext(); Context context = videoView.getContext().getApplicationContext();
String uriString = src.hasKey(PROP_SRC_URI) ? src.getString(PROP_SRC_URI) : null; String uriString = src.hasKey(PROP_SRC_URI) ? src.getString(PROP_SRC_URI) : null;
String extension = src.hasKey(PROP_SRC_TYPE) ? src.getString(PROP_SRC_TYPE) : null; String extension = src.hasKey(PROP_SRC_TYPE) ? src.getString(PROP_SRC_TYPE) : null;
Map<String, String> headers = src.hasKey(PROP_SRC_HEADERS) ? toStringMap(src.getMap(PROP_SRC_HEADERS)) : null;
if (TextUtils.isEmpty(uriString)) { if (TextUtils.isEmpty(uriString)) {
return; return;
@ -81,7 +85,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
Uri srcUri = Uri.parse(uriString); Uri srcUri = Uri.parse(uriString);
if (srcUri != null) { if (srcUri != null) {
videoView.setSrc(srcUri, extension); videoView.setSrc(srcUri, extension, headers);
} }
} else { } else {
int identifier = context.getResources().getIdentifier( int identifier = context.getResources().getIdentifier(
@ -170,4 +174,28 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
} }
return ResizeMode.RESIZE_MODE_FIT; return ResizeMode.RESIZE_MODE_FIT;
} }
/**
* toStringMap converts a {@link ReadableMap} into a HashMap.
*
* @param readableMap The ReadableMap to be conveted.
* @return A HashMap containing the data that was in the ReadableMap.
* @see 'Adapted from https://github.com/artemyarulin/react-native-eval/blob/master/android/src/main/java/com/evaluator/react/ConversionUtil.java'
*/
public static Map<String, String> toStringMap(@Nullable ReadableMap readableMap) {
if (readableMap == null)
return null;
com.facebook.react.bridge.ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
if (!iterator.hasNextKey())
return null;
Map<String, String> result = new HashMap<>();
while (iterator.hasNextKey()) {
String key = iterator.nextKey();
result.put(key, readableMap.getString(key));
}
return result;
}
} }

View File

@ -15,6 +15,7 @@ import com.android.vending.expansion.zipfile.APKExpansionSupport;
import com.android.vending.expansion.zipfile.ZipResourceFile; import com.android.vending.expansion.zipfile.ZipResourceFile;
import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.events.RCTEventEmitter; import com.facebook.react.uimanager.events.RCTEventEmitter;
@ -28,6 +29,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.lang.Math; import java.lang.Math;
import javax.annotation.Nullable;
@SuppressLint("ViewConstructor") @SuppressLint("ViewConstructor")
public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnPreparedListener, MediaPlayer public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnPreparedListener, MediaPlayer
.OnErrorListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnInfoListener, LifecycleEventListener, MediaController.MediaPlayerControl { .OnErrorListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnInfoListener, LifecycleEventListener, MediaController.MediaPlayerControl {
@ -86,6 +89,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
private String mSrcUriString = null; private String mSrcUriString = null;
private String mSrcType = "mp4"; private String mSrcType = "mp4";
private ReadableMap mRequestHeaders = null;
private boolean mSrcIsNetwork = false; private boolean mSrcIsNetwork = false;
private boolean mSrcIsAsset = false; private boolean mSrcIsAsset = false;
private ScalableType mResizeMode = ScalableType.LEFT_TOP; private ScalableType mResizeMode = ScalableType.LEFT_TOP;
@ -201,16 +205,17 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
} }
} }
public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset) { public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final ReadableMap requestHeaders) {
setSrc(uriString,type,isNetwork,isAsset,0,0); setSrc(uriString, type, isNetwork, isAsset, requestHeaders, 0, 0);
} }
public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final int expansionMainVersion, final int expansionPatchVersion) { public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final ReadableMap requestHeaders, final int expansionMainVersion, final int expansionPatchVersion) {
mSrcUriString = uriString; mSrcUriString = uriString;
mSrcType = type; mSrcType = type;
mSrcIsNetwork = isNetwork; mSrcIsNetwork = isNetwork;
mSrcIsAsset = isAsset; mSrcIsAsset = isAsset;
mRequestHeaders = requestHeaders;
mMainVer = expansionMainVersion; mMainVer = expansionMainVersion;
mPatchVer = expansionPatchVersion; mPatchVer = expansionPatchVersion;
@ -239,6 +244,10 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
headers.put("Cookie", cookie); headers.put("Cookie", cookie);
} }
if (mRequestHeaders != null) {
headers.putAll(toStringMap(mRequestHeaders));
}
setDataSource(uriString); setDataSource(uriString);
} else if (isAsset) { } else if (isAsset) {
if (uriString.startsWith("content://")) { if (uriString.startsWith("content://")) {
@ -285,8 +294,13 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
} }
WritableMap src = Arguments.createMap(); WritableMap src = Arguments.createMap();
WritableMap wRequestHeaders = Arguments.createMap();
wRequestHeaders.merge(mRequestHeaders);
src.putString(ReactVideoViewManager.PROP_SRC_URI, uriString); src.putString(ReactVideoViewManager.PROP_SRC_URI, uriString);
src.putString(ReactVideoViewManager.PROP_SRC_TYPE, type); src.putString(ReactVideoViewManager.PROP_SRC_TYPE, type);
src.putMap(ReactVideoViewManager.PROP_SRC_HEADERS, wRequestHeaders);
src.putBoolean(ReactVideoViewManager.PROP_SRC_IS_NETWORK, isNetwork); src.putBoolean(ReactVideoViewManager.PROP_SRC_IS_NETWORK, isNetwork);
if(mMainVer>0) { if(mMainVer>0) {
src.putInt(ReactVideoViewManager.PROP_SRC_MAINVER, mMainVer); src.putInt(ReactVideoViewManager.PROP_SRC_MAINVER, mMainVer);
@ -542,10 +556,10 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
super.onAttachedToWindow(); super.onAttachedToWindow();
if(mMainVer>0) { if(mMainVer>0) {
setSrc(mSrcUriString, mSrcType, mSrcIsNetwork,mSrcIsAsset,mMainVer,mPatchVer); setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders, mMainVer, mPatchVer);
} }
else { else {
setSrc(mSrcUriString, mSrcType, mSrcIsNetwork,mSrcIsAsset); setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders);
} }
} }
@ -577,4 +591,28 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
@Override @Override
public void onHostDestroy() { public void onHostDestroy() {
} }
/**
* toStringMap converts a {@link ReadableMap} into a HashMap.
*
* @param readableMap The ReadableMap to be conveted.
* @return A HashMap containing the data that was in the ReadableMap.
* @see 'Adapted from https://github.com/artemyarulin/react-native-eval/blob/master/android/src/main/java/com/evaluator/react/ConversionUtil.java'
*/
public static Map<String, String> toStringMap(@Nullable ReadableMap readableMap) {
if (readableMap == null)
return null;
com.facebook.react.bridge.ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
if (!iterator.hasNextKey())
return null;
Map<String, String> result = new HashMap<>();
while (iterator.hasNextKey()) {
String key = iterator.nextKey();
result.put(key, readableMap.getString(key));
}
return result;
}
} }

View File

@ -21,6 +21,7 @@ public class ReactVideoViewManager extends SimpleViewManager<ReactVideoView> {
public static final String PROP_SRC = "src"; public static final String PROP_SRC = "src";
public static final String PROP_SRC_URI = "uri"; public static final String PROP_SRC_URI = "uri";
public static final String PROP_SRC_TYPE = "type"; public static final String PROP_SRC_TYPE = "type";
public static final String PROP_SRC_HEADERS = "headers";
public static final String PROP_SRC_IS_NETWORK = "isNetwork"; public static final String PROP_SRC_IS_NETWORK = "isNetwork";
public static final String PROP_SRC_MAINVER = "mainVer"; public static final String PROP_SRC_MAINVER = "mainVer";
public static final String PROP_SRC_PATCHVER = "patchVer"; public static final String PROP_SRC_PATCHVER = "patchVer";
@ -85,6 +86,7 @@ public class ReactVideoViewManager extends SimpleViewManager<ReactVideoView> {
src.getString(PROP_SRC_TYPE), src.getString(PROP_SRC_TYPE),
src.getBoolean(PROP_SRC_IS_NETWORK), src.getBoolean(PROP_SRC_IS_NETWORK),
src.getBoolean(PROP_SRC_IS_ASSET), src.getBoolean(PROP_SRC_IS_ASSET),
src.getMap(PROP_SRC_HEADERS),
mainVer, mainVer,
patchVer patchVer
); );
@ -94,7 +96,8 @@ public class ReactVideoViewManager extends SimpleViewManager<ReactVideoView> {
src.getString(PROP_SRC_URI), src.getString(PROP_SRC_URI),
src.getString(PROP_SRC_TYPE), src.getString(PROP_SRC_TYPE),
src.getBoolean(PROP_SRC_IS_NETWORK), src.getBoolean(PROP_SRC_IS_NETWORK),
src.getBoolean(PROP_SRC_IS_ASSET) src.getBoolean(PROP_SRC_IS_ASSET),
src.getMap(PROP_SRC_HEADERS)
); );
} }
} }

View File

@ -312,12 +312,17 @@ static NSString *const timedMetadata = @"timedMetadata";
bool isAsset = [RCTConvert BOOL:[source objectForKey:@"isAsset"]]; bool isAsset = [RCTConvert BOOL:[source objectForKey:@"isAsset"]];
NSString *uri = [source objectForKey:@"uri"]; NSString *uri = [source objectForKey:@"uri"];
NSString *type = [source objectForKey:@"type"]; NSString *type = [source objectForKey:@"type"];
NSDictionary *headers = [source objectForKey:@"requestHeaders"];
NSURL *url = (isNetwork || isAsset) ? NSURL *url = (isNetwork || isAsset) ?
[NSURL URLWithString:uri] : [NSURL URLWithString:uri] :
[[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:uri ofType:type]]; [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:uri ofType:type]];
if (isNetwork) { if (isNetwork) {
if ([headers count] > 0) {
AVURLAsset* asset = [AVURLAsset URLAssetWithURL:url options:@{@"AVURLAssetHTTPHeaderFieldsKey": headers}];
return [AVPlayerItem playerItemWithAsset:asset];
}
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]; NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:@{AVURLAssetHTTPCookiesKey : cookies}]; AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:@{AVURLAssetHTTPCookiesKey : cookies}];
return [AVPlayerItem playerItemWithAsset:asset]; return [AVPlayerItem playerItemWithAsset:asset];