diff --git a/packages/brightcove-video/android/build.gradle b/packages/brightcove-video/android/build.gradle index e7b54a31c1c..e52395bcb1b 100644 --- a/packages/brightcove-video/android/build.gradle +++ b/packages/brightcove-video/android/build.gradle @@ -19,12 +19,13 @@ android { } repositories { - maven { - url "http://repo.brightcove.com/releases" - } + maven { url "http://repo.brightcove.com/releases" } + maven { url "https://maven.google.com" } } dependencies { - implementation "com.facebook.react:react-native:0.50.+" - api "com.brightcove.player:exoplayer:5.2.0" + implementation "com.facebook.react:react-native:+" + api "com.brightcove.player:exoplayer:6.0.1" + api "com.brightcove.player:android-ima-plugin:6.0.1" + api "com.google.ads.interactivemedia.v3:interactivemedia:3.+" } diff --git a/packages/brightcove-video/android/src/main/java/uk/co/news/rntbrightcovevideo/BrightcovePlayerView.java b/packages/brightcove-video/android/src/main/java/uk/co/news/rntbrightcovevideo/BrightcovePlayerView.java index 8a134f615bb..db6e0d2c183 100644 --- a/packages/brightcove-video/android/src/main/java/uk/co/news/rntbrightcovevideo/BrightcovePlayerView.java +++ b/packages/brightcove-video/android/src/main/java/uk/co/news/rntbrightcovevideo/BrightcovePlayerView.java @@ -1,5 +1,7 @@ package uk.co.news.rntbrightcovevideo; +import java.util.ArrayList; + import android.content.Context; import android.graphics.Color; import android.support.annotation.NonNull; @@ -7,6 +9,9 @@ import android.view.SurfaceView; import android.view.View; +import com.brightcove.ima.GoogleIMAComponent; +import com.brightcove.ima.GoogleIMAEventType; + import com.brightcove.player.edge.Catalog; import com.brightcove.player.edge.VideoListener; import com.brightcove.player.event.Event; @@ -17,6 +22,11 @@ import com.brightcove.player.model.Video; import com.brightcove.player.view.BrightcoveExoPlayerVideoView; +import com.google.ads.interactivemedia.v3.api.AdDisplayContainer; +import com.google.ads.interactivemedia.v3.api.AdsManager; +import com.google.ads.interactivemedia.v3.api.AdsRequest; +import com.google.ads.interactivemedia.v3.api.ImaSdkFactory; + public class BrightcovePlayerView extends BrightcoveExoPlayerVideoView { public static final String TAG = BrightcovePlayerView.class.getSimpleName(); @@ -24,6 +34,7 @@ public class BrightcovePlayerView extends BrightcoveExoPlayerVideoView { private Boolean mAutoplay; private Boolean mIsPlaying = false; private Boolean mIsFullscreen = false; + private GoogleIMAComponent googleIMAComponent; private float mProgress = 0; public BrightcovePlayerView(final Context context) { @@ -98,13 +109,15 @@ private void bubbleState(Boolean isPlaying, int headPos) { } } - public void initVideo(String videoId, String accountId, String policyKey, Boolean autoplay, Boolean isFullscreenButtonHidden) { + public void initVideo(String videoId, String accountId, String policyKey, Boolean autoplay, Boolean isFullscreenButtonHidden, String vastTag) { View fullScreenButton = this.findViewById(com.brightcove.player.R.id.full_screen); fullScreenButton.setVisibility(isFullscreenButtonHidden ? View.GONE : View.VISIBLE); mAutoplay = autoplay; + Log.i(TAG, "INIT"); EventEmitter eventEmitter = setupEventEmitter(); + // setupGoogleIMA(vastTag, eventEmitter); Catalog catalog = new Catalog(eventEmitter, accountId, policyKey); catalog.findVideoByID(videoId, createVideoListener()); @@ -175,4 +188,74 @@ public float getPlayheadPosition() { return playheadPosition; } + /** + * Setup the Brightcove IMA Plugin. + */ + private void setupGoogleIMA(final String adRulesURL, final EventEmitter eventEmitter) { + Log.i(TAG, "SETUP"); + + // Establish the Google IMA SDK factory instance. + final ImaSdkFactory sdkFactory = ImaSdkFactory.getInstance(); + + // Enable logging up ad start. + eventEmitter.on(EventType.AD_STARTED, new EventListener() { + @Override + public void processEvent(Event event) { + Log.v(TAG, event.getType()); + Log.i(TAG, "STARTED"); + } + }); + + // Enable logging any failed attempts to play an ad. + eventEmitter.on(GoogleIMAEventType.DID_FAIL_TO_PLAY_AD, new EventListener() { + @Override + public void processEvent(Event event) { + Log.i(TAG, "FAILED"); + Log.v(TAG, event.getType()); + } + }); + + // Enable Logging upon ad completion. + eventEmitter.on(EventType.AD_COMPLETED, new EventListener() { + @Override + public void processEvent(Event event) { + Log.v(TAG, event.getType()); + Log.i(TAG, "COMPLETED"); + } + }); + + final BrightcoveExoPlayerVideoView playerView = this; + + // Set up a listener for initializing AdsRequests. The Google + // IMA plugin emits an ad request event as a result of + // initializeAdsRequests() being called. + eventEmitter.on(GoogleIMAEventType.ADS_REQUEST_FOR_VIDEO, new EventListener() { + @Override + public void processEvent(Event event) { + Log.i(TAG, "VIDEO REQUEST"); + // Create a container object for the ads to be presented. + AdDisplayContainer container = sdkFactory.createAdDisplayContainer(); + container.setPlayer(googleIMAComponent.getVideoAdPlayer()); + container.setAdContainer(playerView); + + // Build an ads request object and point it to the ad + // display container created above. + AdsRequest adsRequest = sdkFactory.createAdsRequest(); + adsRequest.setAdTagUrl(adRulesURL); + adsRequest.setAdDisplayContainer(container); + + ArrayList adsRequests = new ArrayList(1); + adsRequests.add(adsRequest); + + // Respond to the event with the new ad requests. + event.properties.put(GoogleIMAComponent.ADS_REQUESTS, adsRequests); + eventEmitter.respond(event); + } + }); + + // Create the Brightcove IMA Plugin and pass in the event + // emitter so that the plugin can integrate with the SDK. + googleIMAComponent = new GoogleIMAComponent(playerView, eventEmitter, true); + } + } diff --git a/packages/brightcove-video/android/src/main/java/uk/co/news/rntbrightcovevideo/RNTBrightcoveManager.java b/packages/brightcove-video/android/src/main/java/uk/co/news/rntbrightcovevideo/RNTBrightcoveManager.java index db071dce659..88a66e6381d 100644 --- a/packages/brightcove-video/android/src/main/java/uk/co/news/rntbrightcovevideo/RNTBrightcoveManager.java +++ b/packages/brightcove-video/android/src/main/java/uk/co/news/rntbrightcovevideo/RNTBrightcoveManager.java @@ -51,6 +51,11 @@ public void setHideFullScreenButton(RNTBrightcoveView view, Boolean hideFullScre view.setHideFullScreenButton(hideFullScreenButton); } + @ReactProp(name = "vastTag") + public void setVastTag(RNTBrightcoveView view, String vastTag) { + view.setVastTag(vastTag); + } + @Override public void receiveCommand(RNTBrightcoveView view, int commandId, @Nullable ReadableArray args) { switch (commandId) { diff --git a/packages/brightcove-video/android/src/main/java/uk/co/news/rntbrightcovevideo/RNTBrightcoveView.java b/packages/brightcove-video/android/src/main/java/uk/co/news/rntbrightcovevideo/RNTBrightcoveView.java index d30a60aec0e..ab3c687ee02 100644 --- a/packages/brightcove-video/android/src/main/java/uk/co/news/rntbrightcovevideo/RNTBrightcoveView.java +++ b/packages/brightcove-video/android/src/main/java/uk/co/news/rntbrightcovevideo/RNTBrightcoveView.java @@ -22,6 +22,7 @@ public class RNTBrightcoveView extends FrameLayout { private String mVideoId; private String mAccountId; private String mPolicyKey; + private String mVastTag; private Boolean mAutoplay; private Boolean mHideFullScreenButton; private BrightcovePlayerView mPlayerView; @@ -55,6 +56,13 @@ public void setVideoId(final String videoId) { } } + public void setVastTag(final String vastTag) { + if (mVastTag == null) { + mVastTag = vastTag; + initPlayerView(); + } + } + public void setAccountId(final String accountId) { if (mAccountId == null) { mAccountId = accountId; @@ -92,7 +100,8 @@ private void initPlayerView() { addView(mPlayerView); boolean isFullscreenButtonHidden = mHideFullScreenButton != null ? mHideFullScreenButton : false; - mPlayerView.initVideo(mVideoId, mAccountId, mPolicyKey, mAutoplay, isFullscreenButtonHidden); + mPlayerView.initVideo(mVideoId, mAccountId, mPolicyKey, mAutoplay, isFullscreenButtonHidden, mVastTag); + // mPlayerView.initVideo(mVideoId, mAccountId, mPolicyKey, mAutoplay, isFullscreenButtonHidden); } } @@ -137,6 +146,7 @@ public void emitError(Event e) { } private boolean parametersSet() { - return mVideoId != null && mAccountId != null && mPolicyKey != null && mAutoplay != null && mHideFullScreenButton != null; + // return mVideoId != null && mAccountId != null && mPolicyKey != null && mAutoplay != null && mHideFullScreenButton != null; + return mVideoId != null && mAccountId != null && mPolicyKey != null && mAutoplay != null && mHideFullScreenButton != null && mVastTag != null; } } diff --git a/packages/brightcove-video/brightcove-player.defaults.js b/packages/brightcove-video/brightcove-player.defaults.js index ecf7c347d3f..e68e02f838c 100644 --- a/packages/brightcove-video/brightcove-player.defaults.js +++ b/packages/brightcove-video/brightcove-player.defaults.js @@ -2,6 +2,7 @@ export default { width: 320, height: 180, playerId: "default", + vastTag: null, onError: () => {}, onPlay: () => {}, onPause: () => {}, diff --git a/packages/brightcove-video/brightcove-player.native.js b/packages/brightcove-video/brightcove-player.native.js index 8db79e77e42..1c6b166d98b 100644 --- a/packages/brightcove-video/brightcove-player.native.js +++ b/packages/brightcove-video/brightcove-player.native.js @@ -138,6 +138,7 @@ class BrightcoveVideo extends Component { zIndex: this.props.zIndex }} policyKey={this.props.policyKey} + vastTag={this.props.vastTag} accountId={this.props.accountId} videoId={this.props.videoId} autoplay={this.props.autoplay} diff --git a/packages/brightcove-video/brightcove-player.proptypes.js b/packages/brightcove-video/brightcove-player.proptypes.js index 010e987d5ab..1a181789cf1 100644 --- a/packages/brightcove-video/brightcove-player.proptypes.js +++ b/packages/brightcove-video/brightcove-player.proptypes.js @@ -8,6 +8,7 @@ const numberOrString = PropTypes.oneOfType([ export default { videoId: PropTypes.string.isRequired, accountId: PropTypes.string.isRequired, + vastTag: PropTypes.string.isRequired, policyKey: PropTypes.string, playerId: PropTypes.string, width: numberOrString, diff --git a/packages/brightcove-video/ios/RNTBrightcove.xcodeproj/project.pbxproj b/packages/brightcove-video/ios/RNTBrightcove.xcodeproj/project.pbxproj index b6a3acca289..a8fd1cc34dc 100644 --- a/packages/brightcove-video/ios/RNTBrightcove.xcodeproj/project.pbxproj +++ b/packages/brightcove-video/ios/RNTBrightcove.xcodeproj/project.pbxproj @@ -284,6 +284,8 @@ "$(SRCROOT)/../../../../ios/Pods/Headers/Public/Brightcove-Player-Core", "$(SRCROOT)/../../../../React/**", "$(SRCROOT)/../../../react-native/React/**", + "$(SRCROOT)/../../../../ios/Pods/Headers/Public/Brightcove-Player-IMA", + "$(SRCROOT)/../../../../ios/Pods/Headers/Public/GoogleAds-IMA-iOS-SDK", ); LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = "-ObjC"; @@ -309,6 +311,8 @@ "$(SRCROOT)/../../../../ios/Pods/Headers/Public/Brightcove-Player-Core", "$(SRCROOT)/../../../../React/**", "$(SRCROOT)/../../../react-native/React/**", + "$(SRCROOT)/../../../../ios/Pods/Headers/Public/Brightcove-Player-IMA", + "$(SRCROOT)/../../../../ios/Pods/Headers/Public/GoogleAds-IMA-iOS-SDK", ); LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = "-ObjC"; diff --git a/packages/brightcove-video/ios/RNTBrightcove/RNTBrightcoveManager.m b/packages/brightcove-video/ios/RNTBrightcove/RNTBrightcoveManager.m index 7eba4738c12..9d9d1347900 100644 --- a/packages/brightcove-video/ios/RNTBrightcove/RNTBrightcoveManager.m +++ b/packages/brightcove-video/ios/RNTBrightcove/RNTBrightcoveManager.m @@ -6,6 +6,7 @@ @implementation RNTBrightcoveManager RCT_EXPORT_MODULE(); +RCT_EXPORT_VIEW_PROPERTY(vastTag, NSString); RCT_EXPORT_VIEW_PROPERTY(policyKey, NSString); RCT_EXPORT_VIEW_PROPERTY(accountId, NSString); RCT_EXPORT_VIEW_PROPERTY(videoId, NSString); diff --git a/packages/brightcove-video/ios/RNTBrightcove/RNTBrightcoveView.h b/packages/brightcove-video/ios/RNTBrightcove/RNTBrightcoveView.h index 6ff958febae..a782b522609 100644 --- a/packages/brightcove-video/ios/RNTBrightcove/RNTBrightcoveView.h +++ b/packages/brightcove-video/ios/RNTBrightcove/RNTBrightcoveView.h @@ -2,12 +2,15 @@ #import #import #import +#import +#import @class RCTEventDispatcher; @interface RNTBrightcoveView : UIView @property (nonatomic, copy) NSString *policyKey; +@property (nonatomic, copy) NSString *vastTag; @property (nonatomic, copy) NSString *accountId; @property (nonatomic, copy) NSString *videoId; @property (nonatomic, assign) BOOL autoplay; diff --git a/packages/brightcove-video/ios/RNTBrightcove/RNTBrightcoveView.m b/packages/brightcove-video/ios/RNTBrightcove/RNTBrightcoveView.m index 2c8f9cd2224..fa87a3850fc 100644 --- a/packages/brightcove-video/ios/RNTBrightcove/RNTBrightcoveView.m +++ b/packages/brightcove-video/ios/RNTBrightcove/RNTBrightcoveView.m @@ -47,22 +47,6 @@ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher { return self; } -- (void)setup { - _isPlaying = NO; - _progress = 0; - _isFinished = NO; - - BCOVPlayerSDKManager *manager = [BCOVPlayerSDKManager sharedManager]; - - _playbackController = [manager createPlaybackController]; - _playbackController.delegate = self; - _playbackController.autoAdvance = YES; - _playbackController.autoPlay = [_autoplayNumber boolValue]; - - _playbackService = [[BCOVPlaybackService alloc] initWithAccountId:_accountId - policyKey:_policyKey]; -} - - (void)requestContentFromPlaybackService { [self.playbackService findVideoWithVideoID:_videoId parameters:nil completion:^(BCOVVideo *video, NSDictionary *jsonResponse, NSError *error) { #pragma unused (jsonResponse) @@ -83,12 +67,18 @@ - (void)layoutSubviews { - (void)removeFromSuperview { _eventDispatcher = nil; + for (UIView *subView in self.subviews) + { + [subView removeFromSuperview]; + } [super removeFromSuperview]; } - (void)initPlayerView { - if (_policyKey && _accountId && _videoId && _autoplayNumber && _hideFullScreenButtonNumber) { - [self setup]; + if (_policyKey && _accountId && _videoId && _autoplayNumber && _hideFullScreenButtonNumber && _vastTag) { + _isPlaying = NO; + _progress = 0; + _isFinished = NO; BCOVPUIBasicControlView *controlsView = [BCOVPUIBasicControlView basicControlViewWithVODLayout]; controlsView.playbackButton.accessibilityIdentifier = @"play"; @@ -101,15 +91,39 @@ - (void)initPlayerView { BCOVPUIPlayerViewOptions *options = [[BCOVPUIPlayerViewOptions alloc] init]; - options.presentingViewController = [self fullscreenViewController]; - - BCOVPUIPlayerView *playerView = [[BCOVPUIPlayerView alloc] initWithPlaybackController:self.playbackController options:options controlsView:controlsView ]; + BCOVPUIPlayerView *playerView = [[BCOVPUIPlayerView alloc] initWithPlaybackController:nil options:options controlsView:controlsView ]; playerView.delegate = self; playerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; _playerView = playerView; - _playerView.playbackController = _playbackController; + + // IMA setup start + IMASettings *imaSettings = [[IMASettings alloc] init]; + imaSettings.language = @"fr-CA"; + + IMAAdsRenderingSettings *renderSettings = [[IMAAdsRenderingSettings alloc] init]; + renderSettings.webOpenerPresentingController = nil; + + BCOVIMAAdsRequestPolicy *adsRequestPolicy = [BCOVIMAAdsRequestPolicy adsRequestPolicyWithVMAPAdTagUrl:_vastTag]; + + BCOVPlayerSDKManager *manager = [BCOVPlayerSDKManager sharedManager]; + _playbackController = + [manager createIMAPlaybackControllerWithSettings:imaSettings + adsRenderingSettings:renderSettings + adsRequestPolicy:adsRequestPolicy + adContainer:playerView + companionSlots:nil + viewStrategy:nil]; + + _playbackController.delegate = self; + _playbackController.autoAdvance = YES; + _playbackController.autoPlay = [_autoplayNumber boolValue]; + self.playerView.playbackController = self.playbackController; + + _playbackService = [[BCOVPlaybackService alloc] initWithAccountId:_accountId + policyKey:_policyKey]; + // IMA setup end [self requestContentFromPlaybackService]; } @@ -122,6 +136,13 @@ - (void)setPolicyKey:(NSString *)policyKey { } } +- (void)setVASTTag:(NSString *)vastTag { + if (![vastTag isEqual:_vastTag]) { + _vastTag = vastTag; + [self initPlayerView]; + } +} + - (void)setAccountId:(NSString *)accountId { if (![accountId isEqual:_accountId]) { _accountId = accountId; @@ -228,16 +249,16 @@ - (UIViewController *)rootViewController{ } - (RNTFullscreenPresentingAutoRotatingViewController *)fullscreenViewController { - + if (_fullscreenViewController) { return _fullscreenViewController; } - + RNTFullscreenPresentingAutoRotatingViewController* vc = [RNTFullscreenPresentingAutoRotatingViewController new]; vc.viewControllerToPresentFrom = [self rootViewController]; _fullscreenViewController = vc; - + return _fullscreenViewController; }