Merge remote-tracking branch 'official/master'
This commit is contained in:
commit
3266eb2d67
18
API.md
18
API.md
@ -164,6 +164,21 @@ protected List<ReactPackage> getPackages() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Enable custom feature in gradle file
|
||||||
|
|
||||||
|
##### Enable client side ads insertion
|
||||||
|
To enable client side ads insertion CSAI with google IMA SDK, you need to enable it in your gradle file.
|
||||||
|
|
||||||
|
```gradle
|
||||||
|
buildscript {
|
||||||
|
ext {
|
||||||
|
...
|
||||||
|
RNVUseExoplayerIMA = true
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Windows installation
|
### Windows installation
|
||||||
@ -370,6 +385,9 @@ Example:
|
|||||||
adTagUrl="https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostoptimizedpodbumper&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator="
|
adTagUrl="https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostoptimizedpodbumper&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator="
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: On android, you need enable IMA SDK in gradle file, see: [enableclient side ads insertion](#enable-client-side-ads-insertion)
|
||||||
|
|
||||||
|
|
||||||
Platforms: Android, iOS
|
Platforms: Android, iOS
|
||||||
|
|
||||||
#### allowsExternalPlayback
|
#### allowsExternalPlayback
|
||||||
|
@ -4,6 +4,18 @@ def safeExtGet(prop, fallback) {
|
|||||||
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def useExoplayerIMA = safeExtGet("RNVUseExoplayerIMA", false)
|
||||||
|
|
||||||
|
println "useExoplayerIMA:" + useExoplayerIMA
|
||||||
|
|
||||||
|
// This string is used to define build path.
|
||||||
|
// As react native build output directory is react-native path of the module.
|
||||||
|
// We need to force a new path on each configuration change.
|
||||||
|
// If you add a new build parameter, please add the new value in this string
|
||||||
|
def configStringPath = (
|
||||||
|
'useExoplayerIMA' + useExoplayerIMA \
|
||||||
|
).md5()
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion safeExtGet('compileSdkVersion', 31)
|
compileSdkVersion safeExtGet('compileSdkVersion', 31)
|
||||||
buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2')
|
buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2')
|
||||||
@ -24,6 +36,19 @@ android {
|
|||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildDir 'buildOutput_' + configStringPath
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
java {
|
||||||
|
if (useExoplayerIMA) {
|
||||||
|
exclude 'com/google/ads/interactivemedia/v3/api'
|
||||||
|
exclude 'com/google/android/exoplayer2/ext/ima'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
@ -45,7 +70,9 @@ dependencies {
|
|||||||
implementation('com.google.android.exoplayer:extension-okhttp:2.18.1') {
|
implementation('com.google.android.exoplayer:extension-okhttp:2.18.1') {
|
||||||
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
|
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
|
||||||
}
|
}
|
||||||
implementation 'com.google.android.exoplayer:extension-ima:2.18.1'
|
|
||||||
|
|
||||||
|
if (useExoplayerIMA) {
|
||||||
|
implementation 'com.google.android.exoplayer:extension-ima:2.18.1'
|
||||||
|
}
|
||||||
implementation "com.squareup.okhttp3:okhttp:" + '$OKHTTP_VERSION'
|
implementation "com.squareup.okhttp3:okhttp:" + '$OKHTTP_VERSION'
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.google.ads.interactivemedia.v3.api;
|
||||||
|
|
||||||
|
import androidx.annotation.InspectableProperty;
|
||||||
|
|
||||||
|
public abstract class AdEvent {
|
||||||
|
public abstract InspectableProperty getType();
|
||||||
|
|
||||||
|
public interface AdEventListener {
|
||||||
|
public void onAdEvent(AdEvent adEvent);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package com.google.android.exoplayer2.ext.ima;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.facebook.react.uimanager.ThemedReactContext;
|
||||||
|
import com.google.android.exoplayer2.ExoPlayer;
|
||||||
|
import com.google.android.exoplayer2.Player;
|
||||||
|
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
||||||
|
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||||
|
import com.google.android.exoplayer2.ui.AdViewProvider;
|
||||||
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class ImaAdsLoader implements AdsLoader {
|
||||||
|
public void setPlayer(ExoPlayer player) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayer(@Nullable Player player) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSupportedContentTypes(int... ints) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(AdsMediaSource adsMediaSource, DataSpec dataSpec, Object o, AdViewProvider adViewProvider, EventListener eventListener) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(AdsMediaSource adsMediaSource, EventListener eventListener) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handlePrepareComplete(AdsMediaSource adsMediaSource, int i, int i1) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handlePrepareError(AdsMediaSource adsMediaSource, int i, int i1, IOException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
public Builder(ThemedReactContext themedReactContext) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setAdEventListener(Object reactExoplayerView) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImaAdsLoader build() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,8 @@ buildscript {
|
|||||||
// Otherwise we default to the side-by-side NDK version from AGP.
|
// Otherwise we default to the side-by-side NDK version from AGP.
|
||||||
ndkVersion = "21.4.7075529"
|
ndkVersion = "21.4.7075529"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RNVUseExoplayerIMA = true
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const blacklist = require('metro-config/src/defaults/blacklist');
|
const blacklist = require('metro-config/src/defaults/exclusionList');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
resolver: {
|
resolver: {
|
||||||
|
@ -44,7 +44,7 @@ class RCTResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URLSes
|
|||||||
}
|
}
|
||||||
|
|
||||||
func resourceLoader(_ resourceLoader:AVAssetResourceLoader, didCancel loadingRequest:AVAssetResourceLoadingRequest) {
|
func resourceLoader(_ resourceLoader:AVAssetResourceLoader, didCancel loadingRequest:AVAssetResourceLoadingRequest) {
|
||||||
NSLog("didCancelLoadingRequest")
|
RCTLog("didCancelLoadingRequest")
|
||||||
}
|
}
|
||||||
|
|
||||||
func setLicenseResult(_ license:String!) {
|
func setLicenseResult(_ license:String!) {
|
||||||
|
@ -111,10 +111,14 @@ enum RCTVideoUtils {
|
|||||||
title = value as! String
|
title = value as! String
|
||||||
}
|
}
|
||||||
let language:String! = currentOption?.extendedLanguageTag ?? ""
|
let language:String! = currentOption?.extendedLanguageTag ?? ""
|
||||||
|
|
||||||
|
let selectedOption: AVMediaSelectionOption? = player.currentItem?.currentMediaSelection.selectedMediaOption(in: group!)
|
||||||
|
|
||||||
let audioTrack = [
|
let audioTrack = [
|
||||||
"index": NSNumber(value: i),
|
"index": NSNumber(value: i),
|
||||||
"title": title,
|
"title": title,
|
||||||
"language": language
|
"language": language ?? "",
|
||||||
|
"selected": currentOption?.displayName == selectedOption?.displayName
|
||||||
] as [String : Any]
|
] as [String : Any]
|
||||||
audioTracks.add(audioTrack)
|
audioTracks.add(audioTrack)
|
||||||
}
|
}
|
||||||
@ -137,10 +141,13 @@ enum RCTVideoUtils {
|
|||||||
title = value as! String
|
title = value as! String
|
||||||
}
|
}
|
||||||
let language:String! = currentOption?.extendedLanguageTag ?? ""
|
let language:String! = currentOption?.extendedLanguageTag ?? ""
|
||||||
|
let selectedOpt = player.currentItem?.currentMediaSelection
|
||||||
|
let selectedOption: AVMediaSelectionOption? = player.currentItem?.currentMediaSelection.selectedMediaOption(in: group!)
|
||||||
let textTrack = TextTrack([
|
let textTrack = TextTrack([
|
||||||
"index": NSNumber(value: i),
|
"index": NSNumber(value: i),
|
||||||
"title": title,
|
"title": title,
|
||||||
"language": language
|
"language": language,
|
||||||
|
"selected": currentOption?.displayName == selectedOption?.displayName
|
||||||
])
|
])
|
||||||
textTracks.append(textTrack)
|
textTracks.append(textTrack)
|
||||||
}
|
}
|
||||||
|
@ -1017,6 +1017,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _videoLoadStarted {
|
if _videoLoadStarted {
|
||||||
|
let audioTracks = RCTVideoUtils.getAudioTrackInfo(_player)
|
||||||
|
let textTracks = RCTVideoUtils.getTextTrackInfo(_player).map(\.json)
|
||||||
onVideoLoad?(["duration": NSNumber(value: duration),
|
onVideoLoad?(["duration": NSNumber(value: duration),
|
||||||
"currentTime": NSNumber(value: Float(CMTimeGetSeconds(_playerItem.currentTime()))),
|
"currentTime": NSNumber(value: Float(CMTimeGetSeconds(_playerItem.currentTime()))),
|
||||||
"canPlayReverse": NSNumber(value: _playerItem.canPlayReverse),
|
"canPlayReverse": NSNumber(value: _playerItem.canPlayReverse),
|
||||||
@ -1030,8 +1032,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
"height": width != nil ? NSNumber(value: height!) : "undefinded",
|
"height": width != nil ? NSNumber(value: height!) : "undefinded",
|
||||||
"orientation": orientation
|
"orientation": orientation
|
||||||
],
|
],
|
||||||
"audioTracks": RCTVideoUtils.getAudioTrackInfo(_player),
|
"audioTracks": audioTracks,
|
||||||
"textTracks": _textTracks ?? RCTVideoUtils.getTextTrackInfo(_player),
|
"textTracks": textTracks,
|
||||||
"target": reactTag as Any])
|
"target": reactTag as Any])
|
||||||
}
|
}
|
||||||
_videoLoadStarted = false
|
_videoLoadStarted = false
|
||||||
@ -1090,7 +1092,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
let newRect = change.newValue
|
let newRect = change.newValue
|
||||||
if !oldRect!.equalTo(newRect!) {
|
if !oldRect!.equalTo(newRect!) {
|
||||||
if newRect!.equalTo(UIScreen.main.bounds) {
|
if newRect!.equalTo(UIScreen.main.bounds) {
|
||||||
NSLog("in fullscreen")
|
RCTLog("in fullscreen")
|
||||||
|
|
||||||
self.reactViewController().view.frame = UIScreen.main.bounds
|
self.reactViewController().view.frame = UIScreen.main.bounds
|
||||||
self.reactViewController().view.setNeedsLayout()
|
self.reactViewController().view.setNeedsLayout()
|
||||||
|
@ -25,29 +25,31 @@
|
|||||||
* way into one or the other eventually. Feel free to reuse it as desired.
|
* way into one or the other eventually. Feel free to reuse it as desired.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
let logHeader: String = "RNV:"
|
||||||
|
|
||||||
func RCTLogError(_ message: String, _ file: String=#file, _ line: UInt=#line) {
|
func RCTLogError(_ message: String, _ file: String=#file, _ line: UInt=#line) {
|
||||||
RCTVideoSwiftLog.error(message, file: file, line: line)
|
RCTVideoSwiftLog.error(logHeader + message, file: file, line: line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RCTLogWarn(_ message: String, _ file: String=#file, _ line: UInt=#line) {
|
func RCTLogWarn(_ message: String, _ file: String=#file, _ line: UInt=#line) {
|
||||||
RCTVideoSwiftLog.warn(message, file: file, line: line)
|
RCTVideoSwiftLog.warn(logHeader + message, file: file, line: line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RCTLogInfo(_ message: String, _ file: String=#file, _ line: UInt=#line) {
|
func RCTLogInfo(_ message: String, _ file: String=#file, _ line: UInt=#line) {
|
||||||
RCTVideoSwiftLog.info(message, file: file, line: line)
|
RCTVideoSwiftLog.info(logHeader + message, file: file, line: line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RCTLog(_ message: String, _ file: String=#file, _ line: UInt=#line) {
|
func RCTLog(_ message: String, _ file: String=#file, _ line: UInt=#line) {
|
||||||
RCTVideoSwiftLog.log(message, file: file, line: line)
|
RCTVideoSwiftLog.log(logHeader + message, file: file, line: line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RCTLogTrace(_ message: String, _ file: String=#file, _ line: UInt=#line) {
|
func RCTLogTrace(_ message: String, _ file: String=#file, _ line: UInt=#line) {
|
||||||
RCTVideoSwiftLog.trace(message, file: file, line: line)
|
RCTVideoSwiftLog.trace(logHeader + message, file: file, line: line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DebugLog(_ message: String) {
|
func DebugLog(_ message: String) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
print(message)
|
print(logHeader + message)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
options.useDirectorySeparation = NO;
|
options.useDirectorySeparation = NO;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
options.debugOutput = ^(NSString *string) {
|
options.debugOutput = ^(NSString *string) {
|
||||||
NSLog(@"Video Cache: %@", string);
|
RCTLog(@"Video Cache: %@", string);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
[self createTemporaryPath];
|
[self createTemporaryPath];
|
||||||
@ -48,7 +48,7 @@
|
|||||||
error:&error];
|
error:&error];
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (!success || error) {
|
if (!success || error) {
|
||||||
NSLog(@"Error while! %@", error);
|
RCTLog(@"Error while! %@", error);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@
|
|||||||
[self.videoCache storeData:data forKey:key locked:NO withCallback:^(SPTPersistentCacheResponse * _Nonnull response) {
|
[self.videoCache storeData:data forKey:key locked:NO withCallback:^(SPTPersistentCacheResponse * _Nonnull response) {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
NSLog(@"An error occured while saving the video into the cache: %@", [response.error localizedDescription]);
|
RCTLog(@"An error occured while saving the video into the cache: %@", [response.error localizedDescription]);
|
||||||
#endif
|
#endif
|
||||||
handler(NO);
|
handler(NO);
|
||||||
return;
|
return;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-native-video",
|
"name": "react-native-video",
|
||||||
"version": "6.0.0-alpha.4",
|
"version": "6.0.0-alpha.5",
|
||||||
"description": "A <Video /> element for react-native",
|
"description": "A <Video /> element for react-native",
|
||||||
"main": "Video.js",
|
"main": "Video.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
Loading…
Reference in New Issue
Block a user