diff --git a/README.md b/README.md index fd445187..6f6ec98c 100644 --- a/README.md +++ b/README.md @@ -287,6 +287,7 @@ var styles = StyleSheet.create({ ``` ### Configurable props +* [adTagUrl](#adTagUrl) * [allowsExternalPlayback](#allowsexternalplayback) * [audioOnly](#audioonly) * [automaticallyWaitsToMinimizeStalling](#automaticallyWaitsToMinimizeStalling) @@ -358,6 +359,21 @@ var styles = StyleSheet.create({ ### Configurable props +#### adTagUrl +Sets the ad url + +Example: +``` +const adTagUrl = "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/" ++ "ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp" ++ "&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite" ++ "%26sample_ar%3Dpremidpost&cmsid=496&vid=short_onecue&correlator="; + +adTagUrl={adTagUrl} +``` + +Platforms: Android ExoPlayer, iOS + #### allowsExternalPlayback Indicates whether the player allows switching to external playback mode such as AirPlay or HDMI. * **true (default)** - allow switching to external playback mode diff --git a/android-exoplayer/build.gradle b/android-exoplayer/build.gradle index 8ebe1d25..55356e0a 100644 --- a/android-exoplayer/build.gradle +++ b/android-exoplayer/build.gradle @@ -31,6 +31,7 @@ dependencies { implementation('com.google.android.exoplayer:exoplayer:2.11.4') { exclude group: 'com.android.support' } + implementation 'com.google.android.exoplayer:extension-ima:2.11.4' // All support libs must use the same version implementation "androidx.annotation:annotation:1.1.0" diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java index afa5106c..75512628 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java @@ -18,17 +18,20 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.ads.AdsLoader; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.TextRenderer; import com.google.android.exoplayer2.text.TextOutput; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.ui.SubtitleView; +import com.google.android.exoplayer2.util.Assertions; import java.util.List; +import java.util.ArrayList; @TargetApi(16) -public final class ExoPlayerView extends FrameLayout { +public final class ExoPlayerView extends FrameLayout implements AdsLoader.AdViewProvider { private View surfaceView; private final View shutterView; @@ -38,6 +41,7 @@ public final class ExoPlayerView extends FrameLayout { private SimpleExoPlayer player; private Context context; private ViewGroup.LayoutParams layoutParams; + private final FrameLayout adOverlayFrameLayout; private boolean useTextureView = true; private boolean hideShutterView = false; @@ -82,7 +86,11 @@ public final class ExoPlayerView extends FrameLayout { layout.addView(shutterView, 1, layoutParams); layout.addView(subtitleLayout, 2, layoutParams); + adOverlayFrameLayout = new FrameLayout(context); + addViewInLayout(layout, 0, aspectRatioParams); + addViewInLayout(adOverlayFrameLayout, 1, layoutParams); + } private void setVideoView() { @@ -112,6 +120,28 @@ public final class ExoPlayerView extends FrameLayout { shutterView.setVisibility(this.hideShutterView ? View.INVISIBLE : View.VISIBLE); } + @Override + public void requestLayout() { + super.requestLayout(); + post(measureAndLayout); + } + + // AdsLoader.AdViewProvider implementation. + + @Override + public ViewGroup getAdViewGroup() { + return Assertions.checkNotNull(adOverlayFrameLayout, "exo_ad_overlay must be present for ad playback"); + } + + @Override + public View[] getAdOverlayViews() { + ArrayList overlayViews = new ArrayList<>(); + if (adOverlayFrameLayout != null) { + overlayViews.add(adOverlayFrameLayout); + } + return overlayViews.toArray(new View[0]); + } + /** * Set the {@link SimpleExoPlayer} to use. The {@link SimpleExoPlayer#setTextOutput} and * {@link SimpleExoPlayer#setVideoListener} method of the player will be called and previous diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index b41b2768..8e5d7426 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -72,9 +72,13 @@ import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.ext.ima.ImaAdsLoader; +import com.google.android.exoplayer2.source.ads.AdsMediaSource; + import java.net.CookieHandler; import java.net.CookieManager; import java.net.CookiePolicy; +import java.net.URI; import java.util.ArrayList; import java.util.Locale; import java.util.UUID; @@ -88,7 +92,8 @@ class ReactExoplayerView extends FrameLayout implements BecomingNoisyListener, AudioManager.OnAudioFocusChangeListener, MetadataOutput, - DefaultDrmSessionEventListener { + DefaultDrmSessionEventListener, + AdsMediaSource.MediaSourceFactory { private static final String TAG = "ReactExoplayerView"; @@ -108,6 +113,8 @@ class ReactExoplayerView extends FrameLayout implements private Player.EventListener eventListener; private ExoPlayerView exoPlayerView; + private ImaAdsLoader adsLoader; + private int initialOrientation; private DataSource.Factory mediaDataSourceFactory; private SimpleExoPlayer player; @@ -156,6 +163,7 @@ class ReactExoplayerView extends FrameLayout implements private String drmLicenseUrl = null; private String[] drmLicenseHeader = null; private boolean controls; + private Uri adTagUrl; // \ End props // React @@ -172,6 +180,9 @@ class ReactExoplayerView extends FrameLayout implements && player.getPlaybackState() == Player.STATE_READY && player.getPlayWhenReady() ) { + if (isPlayingAd()) { + playerControlView.hide(); + } long pos = player.getCurrentPosition(); long bufferedDuration = player.getBufferedPercentage() * player.getDuration() / 100; eventEmitter.progressChanged(pos, bufferedDuration, player.getDuration(), getPositionInFirstPeriodMsForCurrentWindow(pos)); @@ -198,6 +209,8 @@ class ReactExoplayerView extends FrameLayout implements this.config = config; this.bandwidthMeter = config.getBandwidthMeter(); + adsLoader = new ImaAdsLoader(this.themedReactContext, Uri.EMPTY); + createViews(); audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); @@ -205,6 +218,10 @@ class ReactExoplayerView extends FrameLayout implements audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext); } + private boolean isPlayingAd() { + return player != null && player.isPlayingAd() && player.getPlayWhenReady(); + } + @Override public void setId(int id) { @@ -321,7 +338,9 @@ class ReactExoplayerView extends FrameLayout implements exoPlayerView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - togglePlayerControlVisibility(); + if (!isPlayingAd()) { + togglePlayerControlVisibility(); + } } }); @@ -428,6 +447,7 @@ class ReactExoplayerView extends FrameLayout implements trackSelector, defaultLoadControl, drmSessionManager, bandwidthMeter); player.addListener(self); player.addMetadataOutput(self); + adsLoader.setPlayer(player); exoPlayerView.setPlayer(player); audioBecomingNoisyReceiver.setListener(self); bandwidthMeter.addEventListener(new Handler(), self); @@ -442,11 +462,12 @@ class ReactExoplayerView extends FrameLayout implements ArrayList mediaSourceList = buildTextSources(); MediaSource videoSource = buildMediaSource(srcUri, extension); + MediaSource mediaSourceWithAds = new AdsMediaSource(videoSource, mediaDataSourceFactory, adsLoader, exoPlayerView); MediaSource mediaSource; if (mediaSourceList.size() == 0) { - mediaSource = videoSource; + mediaSource = mediaSourceWithAds; } else { - mediaSourceList.add(0, videoSource); + mediaSourceList.add(0, mediaSourceWithAds); MediaSource[] textSourceArray = mediaSourceList.toArray( new MediaSource[mediaSourceList.size()] ); @@ -487,6 +508,18 @@ class ReactExoplayerView extends FrameLayout implements } return new DefaultDrmSessionManager<>(uuid, FrameworkMediaDrm.newInstance(uuid), drmCallback, null, false, 3); + // AdsMediaSource.MediaSourceFactory implementation. + } + + @Override + public MediaSource createMediaSource(Uri uri) { + return buildMediaSource(uri, extension); + } + + @Override + public int[] getSupportedTypes() { + // IMA does not support Smooth Streaming ads. + return new int[] {C.TYPE_DASH, C.TYPE_HLS, C.TYPE_OTHER}; } private MediaSource buildMediaSource(Uri uri, String overrideExtension) { @@ -560,6 +593,7 @@ class ReactExoplayerView extends FrameLayout implements trackSelector = null; player = null; } + adsLoader.release(); progressHandler.removeMessages(SHOW_PROGRESS); themedReactContext.removeLifecycleEventListener(this); audioBecomingNoisyReceiver.removeListener(); @@ -1025,6 +1059,11 @@ class ReactExoplayerView extends FrameLayout implements mReportBandwidth = reportBandwidth; } + public void setAdTagUrl(final Uri uri) { + adTagUrl = uri; + adsLoader = new ImaAdsLoader(this.themedReactContext, adTagUrl); + } + public void setRawSrc(final Uri uri, final String extension) { if (uri != null) { boolean isOriginalSourceNull = srcUri == null; diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index 0d81e0b2..e71f5358 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -31,6 +31,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager diff --git a/examples/basic/index.ios.js b/examples/basic/index.ios.js index c4c21c3d..fbe2541c 100644 --- a/examples/basic/index.ios.js +++ b/examples/basic/index.ios.js @@ -4,7 +4,7 @@ import React, { } from 'react'; import { - AlertIOS, + Alert, AppRegistry, Platform, StyleSheet, @@ -15,6 +15,11 @@ import { import Video,{FilterType} from 'react-native-video'; +const adTagUrl = "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/" ++ "ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp" ++ "&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite" ++ "%26sample_ar%3Dpremidpost&cmsid=496&vid=short_onecue&correlator="; + const filterTypes = [ FilterType.NONE, FilterType.INVERT, @@ -188,7 +193,7 @@ class VideoPlayer extends Component { onLoad={this.onLoad} onBuffer={this.onBuffer} onProgress={this.onProgress} - onEnd={() => { AlertIOS.alert('Done!') }} + onEnd={() => { Alert.alert('Done!') }} repeat={true} filter={this.state.filter} filterEnabled={this.state.filterEnabled} @@ -282,11 +287,12 @@ class VideoPlayer extends Component { onLoad={this.onLoad} onBuffer={this.onBuffer} onProgress={this.onProgress} - onEnd={() => { AlertIOS.alert('Done!') }} + onEnd={() => { Alert.alert('Done!') }} repeat={true} controls={this.state.controls} filter={this.state.filter} filterEnabled={this.state.filterEnabled} + adTagUrl={adTagUrl} /> diff --git a/examples/basic/ios/Podfile b/examples/basic/ios/Podfile new file mode 100644 index 00000000..0b90640f --- /dev/null +++ b/examples/basic/ios/Podfile @@ -0,0 +1,48 @@ +# Uncomment the next line to define a global platform for your project +platform :ios, '9.0' + +target 'VideoPlayer' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" + pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec" + pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired" + pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety" + pod 'React', :path => '../node_modules/react-native/' + pod 'React-Core', :path => '../node_modules/react-native/' + pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules' + pod 'React-Core/DevSupport', :path => '../node_modules/react-native/' + pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS' + pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation' + pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob' + pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image' + pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' + pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network' + pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings' + pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text' + pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration' + pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/' + + pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' + pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' + pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' + pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' + pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon" + pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon" + pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga' + + pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' + pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' + pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' + + # Pods for VideoPlayer + pod 'react-native-video', :path => '../node_modules/react-native-video' +end + +target 'VideoPlayer-tvOS' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for VideoPlayer-tvOS + +end diff --git a/examples/basic/ios/Podfile.lock b/examples/basic/ios/Podfile.lock new file mode 100644 index 00000000..281930b9 --- /dev/null +++ b/examples/basic/ios/Podfile.lock @@ -0,0 +1,351 @@ +PODS: + - boost-for-react-native (1.63.0) + - DoubleConversion (1.1.6) + - FBLazyVector (0.61.5) + - FBReactNativeSpec (0.61.5): + - Folly (= 2018.10.22.00) + - RCTRequired (= 0.61.5) + - RCTTypeSafety (= 0.61.5) + - React-Core (= 0.61.5) + - React-jsi (= 0.61.5) + - ReactCommon/turbomodule/core (= 0.61.5) + - Folly (2018.10.22.00): + - boost-for-react-native + - DoubleConversion + - Folly/Default (= 2018.10.22.00) + - glog + - Folly/Default (2018.10.22.00): + - boost-for-react-native + - DoubleConversion + - glog + - glog (0.3.5) + - GoogleAds-IMA-iOS-SDK (3.10.1) + - RCTRequired (0.61.5) + - RCTTypeSafety (0.61.5): + - FBLazyVector (= 0.61.5) + - Folly (= 2018.10.22.00) + - RCTRequired (= 0.61.5) + - React-Core (= 0.61.5) + - React (0.61.5): + - React-Core (= 0.61.5) + - React-Core/DevSupport (= 0.61.5) + - React-Core/RCTWebSocket (= 0.61.5) + - React-RCTActionSheet (= 0.61.5) + - React-RCTAnimation (= 0.61.5) + - React-RCTBlob (= 0.61.5) + - React-RCTImage (= 0.61.5) + - React-RCTLinking (= 0.61.5) + - React-RCTNetwork (= 0.61.5) + - React-RCTSettings (= 0.61.5) + - React-RCTText (= 0.61.5) + - React-RCTVibration (= 0.61.5) + - React-Core (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default (= 0.61.5) + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-Core/CoreModulesHeaders (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-Core/Default (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-Core/DevSupport (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default (= 0.61.5) + - React-Core/RCTWebSocket (= 0.61.5) + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - React-jsinspector (= 0.61.5) + - Yoga + - React-Core/RCTActionSheetHeaders (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-Core/RCTAnimationHeaders (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-Core/RCTBlobHeaders (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-Core/RCTImageHeaders (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-Core/RCTLinkingHeaders (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-Core/RCTNetworkHeaders (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-Core/RCTSettingsHeaders (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-Core/RCTTextHeaders (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-Core/RCTVibrationHeaders (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-Core/RCTWebSocket (0.61.5): + - Folly (= 2018.10.22.00) + - glog + - React-Core/Default (= 0.61.5) + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsiexecutor (= 0.61.5) + - Yoga + - React-CoreModules (0.61.5): + - FBReactNativeSpec (= 0.61.5) + - Folly (= 2018.10.22.00) + - RCTTypeSafety (= 0.61.5) + - React-Core/CoreModulesHeaders (= 0.61.5) + - React-RCTImage (= 0.61.5) + - ReactCommon/turbomodule/core (= 0.61.5) + - React-cxxreact (0.61.5): + - boost-for-react-native (= 1.63.0) + - DoubleConversion + - Folly (= 2018.10.22.00) + - glog + - React-jsinspector (= 0.61.5) + - React-jsi (0.61.5): + - boost-for-react-native (= 1.63.0) + - DoubleConversion + - Folly (= 2018.10.22.00) + - glog + - React-jsi/Default (= 0.61.5) + - React-jsi/Default (0.61.5): + - boost-for-react-native (= 1.63.0) + - DoubleConversion + - Folly (= 2018.10.22.00) + - glog + - React-jsiexecutor (0.61.5): + - DoubleConversion + - Folly (= 2018.10.22.00) + - glog + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - React-jsinspector (0.61.5) + - react-native-video (5.1.0-alpha1): + - React + - react-native-video/Video (= 5.1.0-alpha1) + - react-native-video/Video (5.1.0-alpha1): + - GoogleAds-IMA-iOS-SDK (~> 3.9) + - React + - React-RCTActionSheet (0.61.5): + - React-Core/RCTActionSheetHeaders (= 0.61.5) + - React-RCTAnimation (0.61.5): + - React-Core/RCTAnimationHeaders (= 0.61.5) + - React-RCTBlob (0.61.5): + - React-Core/RCTBlobHeaders (= 0.61.5) + - React-Core/RCTWebSocket (= 0.61.5) + - React-jsi (= 0.61.5) + - React-RCTNetwork (= 0.61.5) + - React-RCTImage (0.61.5): + - React-Core/RCTImageHeaders (= 0.61.5) + - React-RCTNetwork (= 0.61.5) + - React-RCTLinking (0.61.5): + - React-Core/RCTLinkingHeaders (= 0.61.5) + - React-RCTNetwork (0.61.5): + - React-Core/RCTNetworkHeaders (= 0.61.5) + - React-RCTSettings (0.61.5): + - React-Core/RCTSettingsHeaders (= 0.61.5) + - React-RCTText (0.61.5): + - React-Core/RCTTextHeaders (= 0.61.5) + - React-RCTVibration (0.61.5): + - React-Core/RCTVibrationHeaders (= 0.61.5) + - ReactCommon/jscallinvoker (0.61.5): + - DoubleConversion + - Folly (= 2018.10.22.00) + - glog + - React-cxxreact (= 0.61.5) + - ReactCommon/turbomodule/core (0.61.5): + - DoubleConversion + - Folly (= 2018.10.22.00) + - glog + - React-Core (= 0.61.5) + - React-cxxreact (= 0.61.5) + - React-jsi (= 0.61.5) + - ReactCommon/jscallinvoker (= 0.61.5) + - Yoga (1.14.0) + +DEPENDENCIES: + - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) + - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) + - FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`) + - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`) + - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) + - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) + - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) + - React (from `../node_modules/react-native/`) + - React-Core (from `../node_modules/react-native/`) + - React-Core/DevSupport (from `../node_modules/react-native/`) + - React-Core/RCTWebSocket (from `../node_modules/react-native/`) + - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) + - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) + - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) + - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) + - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) + - react-native-video (from `../node_modules/react-native-video`) + - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) + - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) + - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) + - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) + - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) + - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) + - React-RCTText (from `../node_modules/react-native/Libraries/Text`) + - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - ReactCommon/jscallinvoker (from `../node_modules/react-native/ReactCommon`) + - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) + +SPEC REPOS: + trunk: + - boost-for-react-native + - GoogleAds-IMA-iOS-SDK + +EXTERNAL SOURCES: + DoubleConversion: + :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" + FBLazyVector: + :path: "../node_modules/react-native/Libraries/FBLazyVector" + FBReactNativeSpec: + :path: "../node_modules/react-native/Libraries/FBReactNativeSpec" + Folly: + :podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec" + glog: + :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" + RCTRequired: + :path: "../node_modules/react-native/Libraries/RCTRequired" + RCTTypeSafety: + :path: "../node_modules/react-native/Libraries/TypeSafety" + React: + :path: "../node_modules/react-native/" + React-Core: + :path: "../node_modules/react-native/" + React-CoreModules: + :path: "../node_modules/react-native/React/CoreModules" + React-cxxreact: + :path: "../node_modules/react-native/ReactCommon/cxxreact" + React-jsi: + :path: "../node_modules/react-native/ReactCommon/jsi" + React-jsiexecutor: + :path: "../node_modules/react-native/ReactCommon/jsiexecutor" + React-jsinspector: + :path: "../node_modules/react-native/ReactCommon/jsinspector" + react-native-video: + :path: "../node_modules/react-native-video" + React-RCTActionSheet: + :path: "../node_modules/react-native/Libraries/ActionSheetIOS" + React-RCTAnimation: + :path: "../node_modules/react-native/Libraries/NativeAnimation" + React-RCTBlob: + :path: "../node_modules/react-native/Libraries/Blob" + React-RCTImage: + :path: "../node_modules/react-native/Libraries/Image" + React-RCTLinking: + :path: "../node_modules/react-native/Libraries/LinkingIOS" + React-RCTNetwork: + :path: "../node_modules/react-native/Libraries/Network" + React-RCTSettings: + :path: "../node_modules/react-native/Libraries/Settings" + React-RCTText: + :path: "../node_modules/react-native/Libraries/Text" + React-RCTVibration: + :path: "../node_modules/react-native/Libraries/Vibration" + ReactCommon: + :path: "../node_modules/react-native/ReactCommon" + Yoga: + :path: "../node_modules/react-native/ReactCommon/yoga" + +SPEC CHECKSUMS: + boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c + DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2 + FBLazyVector: aaeaf388755e4f29cd74acbc9e3b8da6d807c37f + FBReactNativeSpec: 118d0d177724c2d67f08a59136eb29ef5943ec75 + Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51 + glog: 1f3da668190260b06b429bb211bfbee5cd790c28 + GoogleAds-IMA-iOS-SDK: 0e37ab83b22075ad631a70dcba9528cb246c92bf + RCTRequired: b153add4da6e7dbc44aebf93f3cf4fcae392ddf1 + RCTTypeSafety: 9aa1b91d7f9310fc6eadc3cf95126ffe818af320 + React: b6a59ef847b2b40bb6e0180a97d0ca716969ac78 + React-Core: 688b451f7d616cc1134ac95295b593d1b5158a04 + React-CoreModules: d04f8494c1a328b69ec11db9d1137d667f916dcb + React-cxxreact: d0f7bcafa196ae410e5300736b424455e7fb7ba7 + React-jsi: cb2cd74d7ccf4cffb071a46833613edc79cdf8f7 + React-jsiexecutor: d5525f9ed5f782fdbacb64b9b01a43a9323d2386 + React-jsinspector: fa0ecc501688c3c4c34f28834a76302233e29dc0 + react-native-video: c3bf083971eafe6db2cf301636694f83bb012430 + React-RCTActionSheet: 600b4d10e3aea0913b5a92256d2719c0cdd26d76 + React-RCTAnimation: 791a87558389c80908ed06cc5dfc5e7920dfa360 + React-RCTBlob: d89293cc0236d9cb0933d85e430b0bbe81ad1d72 + React-RCTImage: 6b8e8df449eb7c814c99a92d6b52de6fe39dea4e + React-RCTLinking: 121bb231c7503cf9094f4d8461b96a130fabf4a5 + React-RCTNetwork: fb353640aafcee84ca8b78957297bd395f065c9a + React-RCTSettings: 8db258ea2a5efee381fcf7a6d5044e2f8b68b640 + React-RCTText: 9ccc88273e9a3aacff5094d2175a605efa854dbe + React-RCTVibration: a49a1f42bf8f5acf1c3e297097517c6b3af377ad + ReactCommon: 198c7c8d3591f975e5431bec1b0b3b581aa1c5dd + Yoga: f2a7cd4280bfe2cca5a7aed98ba0eb3d1310f18b + +PODFILE CHECKSUM: ff44b40df452c2410ba8c86ff1d981c586cc6286 + +COCOAPODS: 1.8.4 diff --git a/examples/basic/ios/VideoPlayer.xcodeproj/project.pbxproj b/examples/basic/ios/VideoPlayer.xcodeproj/project.pbxproj index db5f9a39..be579062 100644 --- a/examples/basic/ios/VideoPlayer.xcodeproj/project.pbxproj +++ b/examples/basic/ios/VideoPlayer.xcodeproj/project.pbxproj @@ -7,22 +7,12 @@ objects = { /* Begin PBXBuildFile section */ - 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; - 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; - 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; }; - 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; - 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; - 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; - 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; - 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; }; 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; - 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; - 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; }; - 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; - 8C2A0F841E2560A100E31596 /* libRCTVideo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C2A0F791E25608300E31596 /* libRCTVideo.a */; }; + 35038EB1239F5C8E004C7F58 /* Pods_VideoPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 35038EB0239F5C8E004C7F58 /* Pods_VideoPlayer.framework */; }; + 3E565D7A54028115524E19B3 /* Pods_VideoPlayer_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E283EDD1CBBEDE14319F393C /* Pods_VideoPlayer_tvOS.framework */; }; FA3566AB216D5D7000E01ABD /* libRCTImage-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */; }; FA3566AC216D5D7000E01ABD /* libRCTLinking-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */; }; FA3566AD216D5D7000E01ABD /* libRCTNetwork-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */; }; @@ -315,12 +305,20 @@ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = VideoPlayer/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = VideoPlayer/main.m; sourceTree = ""; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; + 193C56737A4BFE22EC8FD7CE /* Pods-VideoPlayer-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VideoPlayer-tvOS.release.xcconfig"; path = "Target Support Files/Pods-VideoPlayer-tvOS/Pods-VideoPlayer-tvOS.release.xcconfig"; sourceTree = ""; }; + 35038EAE239F5C29004C7F58 /* React.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = React.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 35038EB0239F5C8E004C7F58 /* Pods_VideoPlayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Pods_VideoPlayer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 39CBB10045CEBFA9BBB9645E /* libPods-VideoPlayer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-VideoPlayer.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 49F6E2DFCFB5662A09E3B94F /* Pods-VideoPlayer.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VideoPlayer.release.xcconfig"; path = "Target Support Files/Pods-VideoPlayer/Pods-VideoPlayer.release.xcconfig"; sourceTree = ""; }; + 52421E8587B432062FCB0E39 /* Pods-VideoPlayer-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VideoPlayer-tvOS.debug.xcconfig"; path = "Target Support Files/Pods-VideoPlayer-tvOS/Pods-VideoPlayer-tvOS.debug.xcconfig"; sourceTree = ""; }; 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; }; 627363E07276C06249D7CEBF /* libPods-VideoPlayer-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-VideoPlayer-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; 8C2A0F651E25608300E31596 /* RCTVideo.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVideo.xcodeproj; path = "../node_modules/react-native-video/ios/RCTVideo.xcodeproj"; sourceTree = ""; }; + B4E8B7269229AE0B24D2F9C2 /* Pods_VideoPlayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_VideoPlayer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B6DC2FE9CFD02FF649339B93 /* Pods-VideoPlayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VideoPlayer.debug.xcconfig"; path = "Target Support Files/Pods-VideoPlayer/Pods-VideoPlayer.debug.xcconfig"; sourceTree = ""; }; + E283EDD1CBBEDE14319F393C /* Pods_VideoPlayer_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_VideoPlayer_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FA8681CE216D5C6D0010C92A /* VideoPlayer-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "VideoPlayer-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; FA8681D0216D5C6E0010C92A /* VideoPlayer-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "VideoPlayer-tvOS.plist"; path = "/Users/amishra/Development/react-native-video-nfb/examples/basic/ios/VideoPlayer-tvOS.plist"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -330,18 +328,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 146834051AC3E58100842450 /* libReact.a in Frameworks */, - 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */, - 8C2A0F841E2560A100E31596 /* libRCTVideo.a in Frameworks */, - 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, - 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, - 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */, - 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */, - 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */, - 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */, - 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, - 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, - 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, + 35038EB1239F5C8E004C7F58 /* Pods_VideoPlayer.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -357,6 +344,7 @@ FA3566AF216D5D7000E01ABD /* libRCTText-tvOS.a in Frameworks */, FA3566B0216D5D7000E01ABD /* libRCTWebSocket-tvOS.a in Frameworks */, FA3566C8216D5DA900E01ABD /* libRCTVideo.a in Frameworks */, + 3E565D7A54028115524E19B3 /* Pods_VideoPlayer_tvOS.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -516,6 +504,7 @@ 832341AE1AAA6A7D00B99B32 /* Libraries */, 83CBBA001A601CBA00E9B192 /* Products */, FA35669C216D5D7000E01ABD /* Frameworks */, + BB30D76686EC7F53F239F9B8 /* Pods */, ); indentWidth = 2; sourceTree = ""; @@ -539,11 +528,26 @@ name = Products; sourceTree = ""; }; + BB30D76686EC7F53F239F9B8 /* Pods */ = { + isa = PBXGroup; + children = ( + B6DC2FE9CFD02FF649339B93 /* Pods-VideoPlayer.debug.xcconfig */, + 49F6E2DFCFB5662A09E3B94F /* Pods-VideoPlayer.release.xcconfig */, + 52421E8587B432062FCB0E39 /* Pods-VideoPlayer-tvOS.debug.xcconfig */, + 193C56737A4BFE22EC8FD7CE /* Pods-VideoPlayer-tvOS.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; FA35669C216D5D7000E01ABD /* Frameworks */ = { isa = PBXGroup; children = ( + 35038EB0239F5C8E004C7F58 /* Pods_VideoPlayer.framework */, + 35038EAE239F5C29004C7F58 /* React.framework */, 39CBB10045CEBFA9BBB9645E /* libPods-VideoPlayer.a */, 627363E07276C06249D7CEBF /* libPods-VideoPlayer-tvOS.a */, + B4E8B7269229AE0B24D2F9C2 /* Pods_VideoPlayer.framework */, + E283EDD1CBBEDE14319F393C /* Pods_VideoPlayer_tvOS.framework */, ); name = Frameworks; sourceTree = ""; @@ -563,10 +567,12 @@ isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "VideoPlayer" */; buildPhases = ( + 32CB69FF947AEF78D0E22CF5 /* [CP] Check Pods Manifest.lock */, 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 32F3757568F2420976252267 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -581,6 +587,7 @@ isa = PBXNativeTarget; buildConfigurationList = FA8681CB216D5C6D0010C92A /* Build configuration list for PBXNativeTarget "VideoPlayer-tvOS" */; buildPhases = ( + 629EB3CAFD1669F3677B304B /* [CP] Check Pods Manifest.lock */, FA8681B7216D5C6D0010C92A /* Sources */, FA8681BA216D5C6D0010C92A /* Frameworks */, FA8681C7216D5C6D0010C92A /* Resources */, @@ -609,6 +616,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -970,6 +978,112 @@ shellPath = /bin/sh; shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n"; }; + 32CB69FF947AEF78D0E22CF5 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-VideoPlayer-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 32F3757568F2420976252267 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-VideoPlayer/Pods-VideoPlayer-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/DoubleConversion/DoubleConversion.framework", + "${BUILT_PRODUCTS_DIR}/FBReactNativeSpec/FBReactNativeSpec.framework", + "${BUILT_PRODUCTS_DIR}/Folly/folly.framework", + "${PODS_ROOT}/GoogleAds-IMA-iOS-SDK/GoogleInteractiveMediaAds.framework", + "${BUILT_PRODUCTS_DIR}/RCTTypeSafety/RCTTypeSafety.framework", + "${BUILT_PRODUCTS_DIR}/React-Core/React.framework", + "${BUILT_PRODUCTS_DIR}/React-CoreModules/CoreModules.framework", + "${BUILT_PRODUCTS_DIR}/React-RCTActionSheet/RCTActionSheet.framework", + "${BUILT_PRODUCTS_DIR}/React-RCTAnimation/RCTAnimation.framework", + "${BUILT_PRODUCTS_DIR}/React-RCTBlob/RCTBlob.framework", + "${BUILT_PRODUCTS_DIR}/React-RCTImage/RCTImage.framework", + "${BUILT_PRODUCTS_DIR}/React-RCTLinking/RCTLinking.framework", + "${BUILT_PRODUCTS_DIR}/React-RCTNetwork/RCTNetwork.framework", + "${BUILT_PRODUCTS_DIR}/React-RCTSettings/RCTSettings.framework", + "${BUILT_PRODUCTS_DIR}/React-RCTText/RCTText.framework", + "${BUILT_PRODUCTS_DIR}/React-RCTVibration/RCTVibration.framework", + "${BUILT_PRODUCTS_DIR}/React-cxxreact/cxxreact.framework", + "${BUILT_PRODUCTS_DIR}/React-jsi/jsi.framework", + "${BUILT_PRODUCTS_DIR}/React-jsiexecutor/jsireact.framework", + "${BUILT_PRODUCTS_DIR}/React-jsinspector/jsinspector.framework", + "${BUILT_PRODUCTS_DIR}/ReactCommon/ReactCommon.framework", + "${BUILT_PRODUCTS_DIR}/Yoga/yoga.framework", + "${BUILT_PRODUCTS_DIR}/glog/glog.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DoubleConversion.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBReactNativeSpec.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/folly.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleInteractiveMediaAds.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTTypeSafety.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CoreModules.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTActionSheet.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTAnimation.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTBlob.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTLinking.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTNetwork.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTSettings.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTText.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTVibration.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cxxreact.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/jsi.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/jsireact.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/jsinspector.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactCommon.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/yoga.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-VideoPlayer/Pods-VideoPlayer-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 629EB3CAFD1669F3677B304B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-VideoPlayer-tvOS-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; FA8681CA216D5C6D0010C92A /* Bundle React Native code and images */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1022,6 +1136,7 @@ /* Begin XCBuildConfiguration section */ 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = B6DC2FE9CFD02FF649339B93 /* Pods-VideoPlayer.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = 1; @@ -1041,6 +1156,7 @@ }; 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 49F6E2DFCFB5662A09E3B94F /* Pods-VideoPlayer.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = 1; @@ -1091,7 +1207,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -1126,7 +1242,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; @@ -1135,6 +1251,7 @@ }; FA8681CC216D5C6D0010C92A /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 52421E8587B432062FCB0E39 /* Pods-VideoPlayer-tvOS.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = 1; @@ -1158,6 +1275,7 @@ }; FA8681CD216D5C6D0010C92A /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 193C56737A4BFE22EC8FD7CE /* Pods-VideoPlayer-tvOS.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = 1; diff --git a/examples/basic/yarn.lock b/examples/basic/yarn.lock index d9970938..951143aa 100644 --- a/examples/basic/yarn.lock +++ b/examples/basic/yarn.lock @@ -5046,7 +5046,7 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0: +p-limit@^2.0.0, p-limit@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== diff --git a/ios/RCTVideo.xcodeproj/project.pbxproj b/ios/RCTVideo.xcodeproj/project.pbxproj index 4e675ac7..1761485f 100644 --- a/ios/RCTVideo.xcodeproj/project.pbxproj +++ b/ios/RCTVideo.xcodeproj/project.pbxproj @@ -163,6 +163,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, ); mainGroup = 58B511D21A9E6C8500147676; @@ -236,7 +237,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -270,7 +271,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; diff --git a/ios/Video/RCTVideo.h b/ios/Video/RCTVideo.h index 6fee2996..403fb195 100644 --- a/ios/Video/RCTVideo.h +++ b/ios/Video/RCTVideo.h @@ -5,6 +5,7 @@ #import "RCTVideoPlayerViewControllerDelegate.h" #import #import +@import GoogleInteractiveMediaAds; #if __has_include() #import @@ -14,11 +15,11 @@ @class RCTEventDispatcher; #if __has_include() -@interface RCTVideo : UIView +@interface RCTVideo : UIView #elif TARGET_OS_TV @interface RCTVideo : UIView #else -@interface RCTVideo : UIView +@interface RCTVideo : UIView #endif @property (nonatomic, copy) RCTDirectEventBlock onVideoLoadStart; @@ -55,6 +56,12 @@ typedef NS_ENUM(NSInteger, RCTVideoError) { RCTVideoErrorNoFairplayDRM, RCTVideoErrorNoDRMData }; +/// Playhead used by the SDK to track content video progress and insert mid-rolls. +@property(nonatomic, strong) IMAAVPlayerContentPlayhead *contentPlayhead; +/// Entry point for the SDK. Used to make ad requests. +@property(nonatomic, strong) IMAAdsLoader *adsLoader; +/// Main point of interaction with the SDK. Created by the SDK as the result of an ad request. +@property(nonatomic, strong) IMAAdsManager *adsManager; - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER; diff --git a/ios/Video/RCTVideo.m b/ios/Video/RCTVideo.m index 989167a6..278b7cd9 100644 --- a/ios/Video/RCTVideo.m +++ b/ios/Video/RCTVideo.m @@ -45,6 +45,7 @@ static int const RCTVideoUnset = -1; BOOL _playbackRateObserverRegistered; BOOL _isExternalPlaybackActiveObserverRegistered; BOOL _videoLoadStarted; + BOOL _isRequestAds; bool _pendingSeek; float _pendingSeekTime; @@ -82,6 +83,7 @@ static int const RCTVideoUnset = -1; NSString * _fullscreenOrientation; BOOL _fullscreenPlayerPresented; NSString *_filterName; + NSString * _adTagUrl; BOOL _filterEnabled; UIViewController * _presentingViewController; #if __has_include() @@ -118,6 +120,7 @@ static int const RCTVideoUnset = -1; _allowsExternalPlayback = YES; _playWhenInactive = false; _pictureInPicture = false; + _isRequestAds = false; _ignoreSilentSwitch = @"inherit"; // inherit, ignore, obey _mixWithOthers = @"inherit"; // inherit, mix, duck #if TARGET_OS_IOS @@ -152,14 +155,16 @@ static int const RCTVideoUnset = -1; - (RCTVideoPlayerViewController*)createPlayerViewController:(AVPlayer*)player withPlayerItem:(AVPlayerItem*)playerItem { - RCTVideoPlayerViewController* viewController = [[RCTVideoPlayerViewController alloc] init]; - viewController.showsPlaybackControls = YES; - viewController.rctDelegate = self; - viewController.preferredOrientation = _fullscreenOrientation; - - viewController.view.frame = self.bounds; - viewController.player = player; - return viewController; + RCTVideoPlayerViewController* viewController = [[RCTVideoPlayerViewController alloc] init]; + viewController.showsPlaybackControls = YES; + viewController.rctDelegate = self; + viewController.preferredOrientation = _fullscreenOrientation; + self.contentPlayhead = [[IMAAVPlayerContentPlayhead alloc] initWithAVPlayer:player]; + [self setupAdsLoader]; + + viewController.view.frame = self.bounds; + viewController.player = player; + return viewController; } /* --------------------------------------------------------- @@ -280,8 +285,12 @@ static int const RCTVideoUnset = -1; const Float64 currentTimeSecs = CMTimeGetSeconds(currentTime); [[NSNotificationCenter defaultCenter] postNotificationName:@"RCTVideo_progress" object:nil userInfo:@{@"progress": [NSNumber numberWithDouble: currentTimeSecs / duration]}]; - + if( currentTimeSecs >= 0 && self.onVideoProgress) { + if(!_isRequestAds && currentTimeSecs >= 0.0001) { + [self requestAds]; + _isRequestAds = true; + } self.onVideoProgress(@{ @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(currentTime)], @"playableDuration": [self calculatePlayableDuration], @@ -694,7 +703,6 @@ static int const RCTVideoUnset = -1; @"target": self.reactTag}); } _videoLoadStarted = NO; - [self attachListeners]; [self applyModifiers]; } else if (_playerItem.status == AVPlayerItemStatusFailed && self.onVideoError) { @@ -757,6 +765,74 @@ static int const RCTVideoUnset = -1; } } +- (void)setupAdsLoader { + // Re-use this IMAAdsLoader instance for the entire lifecycle of your app. + self.adsLoader = [[IMAAdsLoader alloc] initWithSettings:nil]; + // NOTE: This line will cause a warning until the next step, "Get the Ads Manager". + self.adsLoader.delegate = self; +} + +- (void)requestAds { + // Create an ad display container for ad rendering. + IMAAdDisplayContainer *adDisplayContainer = + [[IMAAdDisplayContainer alloc] initWithAdContainer:self companionSlots:nil]; + // Create an ad request with our ad tag, display container, and optional user context. + IMAAdsRequest *request = [[IMAAdsRequest alloc] initWithAdTagUrl:_adTagUrl + adDisplayContainer:adDisplayContainer + contentPlayhead:self.contentPlayhead + userContext:nil]; + [self.adsLoader requestAdsWithRequest:request]; +} + +#pragma mark AdsLoader Delegates + +- (void)adsLoader:(IMAAdsLoader *)loader adsLoadedWithData:(IMAAdsLoadedData *)adsLoadedData { + // Grab the instance of the IMAAdsManager and set ourselves as the delegate. + self.adsManager = adsLoadedData.adsManager; + + // NOTE: This line will cause a warning until the next step, "Display Ads". + self.adsManager.delegate = self; + + // Create ads rendering settings and tell the SDK to use the in-app browser. + IMAAdsRenderingSettings *adsRenderingSettings = [[IMAAdsRenderingSettings alloc] init]; + adsRenderingSettings.webOpenerPresentingController = _playerViewController; + + // Initialize the ads manager. + [self.adsManager initializeWithAdsRenderingSettings:adsRenderingSettings]; +} + +- (void)adsLoader:(IMAAdsLoader *)loader failedWithErrorData:(IMAAdLoadingErrorData *)adErrorData { + // Something went wrong loading ads. Log the error and play the content. + NSLog(@"Error loading ads: %@", adErrorData.adError.message); + [_player play]; +} + +#pragma mark AdsManager Delegates + +- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdEvent:(IMAAdEvent *)event { + if (event.type == kIMAAdEvent_LOADED) { + // When the SDK notifies us that ads have been loaded, play them. + [adsManager start]; + } +} + +- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdError:(IMAAdError *)error { + // Something went wrong with the ads manager after ads were loaded. Log the error and play the + // content. + NSLog(@"AdsManager error: %@", error.message); + [_player play]; +} + +- (void)adsManagerDidRequestContentPause:(IMAAdsManager *)adsManager { + // The SDK is going to play ads, so pause the content. + [_player pause]; +} + +- (void)adsManagerDidRequestContentResume:(IMAAdsManager *)adsManager { + // The SDK is done playing ads (at least for now), so resume the content. + [_player play]; +} + - (void)attachListeners { // listen for end of file @@ -824,6 +900,9 @@ static int const RCTVideoUnset = -1; - (void)playerItemDidReachEnd:(NSNotification *)notification { + if (notification.object == _player.currentItem) { + [self.adsLoader contentComplete]; + } if(self.onVideoEnd) { self.onVideoEnd(@{@"target": self.reactTag}); } @@ -1535,6 +1614,10 @@ static int const RCTVideoUnset = -1; _filterEnabled = filterEnabled; } +- (void)setAdTagUrl:(NSString *)adTagUrl { + _adTagUrl = adTagUrl; +} + #pragma mark - React View Management - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex diff --git a/ios/Video/RCTVideoManager.m b/ios/Video/RCTVideoManager.m index 000a9e83..728142ba 100644 --- a/ios/Video/RCTVideoManager.m +++ b/ios/Video/RCTVideoManager.m @@ -20,6 +20,7 @@ RCT_EXPORT_MODULE(); RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary); RCT_EXPORT_VIEW_PROPERTY(drm, NSDictionary); +RCT_EXPORT_VIEW_PROPERTY(adTagUrl, NSString); RCT_EXPORT_VIEW_PROPERTY(maxBitRate, float); RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString); RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL); diff --git a/package.json b/package.json index 136e59eb..8f113f3a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "react-native-video", + "name": "react-native-video-inc-ads", "version": "5.1.1", - "description": "A