From d05231d76b87e2f65bc7648bfb81d01e4054b2de Mon Sep 17 00:00:00 2001 From: Axel Vencatareddy Date: Mon, 27 Nov 2023 21:43:30 +0100 Subject: [PATCH] feat(ad): add data to onReceiveAdEvent (#3378) * feat(ad): add adData to onReceiveAdEvent * fix: remove adData from response if empty * fix: add getAdData to stub file * chore: fix build without IMA * fix: rename `adData` to `data` --------- Co-authored-by: olivier --- .../common/react/VideoEventEmitter.java | 14 +++++++++++++ .../exoplayer/ReactExoplayerView.java | 6 +++++- .../ads/interactivemedia/v3/api/AdEvent.java | 3 +++ docs/pages/component/events.md | 20 +++++++++++-------- ios/Video/Features/RCTIMAAdsManager.swift | 16 +++++++++++---- src/VideoNativeComponent.ts | 1 + src/types/Ads.ts | 2 +- src/types/events.ts | 1 + src/types/video.ts | 2 +- 9 files changed, 50 insertions(+), 15 deletions(-) diff --git a/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.java b/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.java index b8718287..8e818f6a 100644 --- a/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.java +++ b/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.java @@ -18,6 +18,7 @@ import java.io.StringWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Map; public class VideoEventEmitter { @@ -413,6 +414,19 @@ public class VideoEventEmitter { receiveEvent(EVENT_AUDIO_BECOMING_NOISY, null); } + public void receiveAdEvent(String event, Map data) { + WritableMap map = Arguments.createMap(); + map.putString("event", event); + + WritableMap dataMap = Arguments.createMap(); + for (Map.Entry entry : data.entrySet()) { + dataMap.putString(entry.getKey(), entry.getValue()); + } + map.putMap("data", dataMap); + + receiveEvent(EVENT_ON_RECEIVE_AD_EVENT, map); + } + public void receiveAdEvent(String event) { WritableMap map = Arguments.createMap(); map.putString("event", event); diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 21ef75a0..698856dc 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -2100,6 +2100,10 @@ public class ReactExoplayerView extends FrameLayout implements @Override public void onAdEvent(AdEvent adEvent) { - eventEmitter.receiveAdEvent(adEvent.getType().name()); + if (adEvent.getAdData() != null) { + eventEmitter.receiveAdEvent(adEvent.getType().name(), adEvent.getAdData()); + } else { + eventEmitter.receiveAdEvent(adEvent.getType().name()); + } } } diff --git a/android/src/main/java/com/google/ads/interactivemedia/v3/api/AdEvent.java b/android/src/main/java/com/google/ads/interactivemedia/v3/api/AdEvent.java index 1913df29..00f640d6 100644 --- a/android/src/main/java/com/google/ads/interactivemedia/v3/api/AdEvent.java +++ b/android/src/main/java/com/google/ads/interactivemedia/v3/api/AdEvent.java @@ -2,8 +2,11 @@ package com.google.ads.interactivemedia.v3.api; import androidx.annotation.InspectableProperty; +import java.util.Map; + public abstract class AdEvent { public abstract InspectableProperty getType(); + public abstract Map getAdData(); public interface AdEventListener { public void onAdEvent(AdEvent adEvent); diff --git a/docs/pages/component/events.md b/docs/pages/component/events.md index aa598c4d..b093377e 100644 --- a/docs/pages/component/events.md +++ b/docs/pages/component/events.md @@ -362,10 +362,10 @@ Enum `AdEvent` possible values for [Android](https://developers.google.com/inter | `AD_METADATA` | Android | Fires when an ads list is loaded. | | `AD_PERIOD_ENDED` | iOS | Fired every time the stream switches from advertising or slate to content. This will be fired even when an ad is played a second time or when seeking into an ad (only used for dynamic ad insertion). | | `AD_PERIOD_STARTED` | iOS | Fired every time the stream switches from content to advertising or slate. This will be fired even when an ad is played a second time or when seeking into an ad (only used for dynamic ad insertion). | -| `AD_PROGRESS` | Android | Fires when the ad's current time value changes. Calling getAdData() on this event will return an AdProgressData object. | +| `AD_PROGRESS` | Android | Fires when the ad's current time value changes. The event `data` will be populated with an AdProgressData object. | | `ALL_ADS_COMPLETED` | Android, iOS | Fires when the ads manager is done playing all the valid ads in the ads response, or when the response doesn't return any valid ads. | | `CLICK` | Android, iOS | Fires when the ad is clicked. | -| `COMPLETE` | Android, iOS | Fires when the ad completes playing. | +| `COMPLETED` | Android, iOS | Fires when the ad completes playing. | | `CONTENT_PAUSE_REQUESTED` | Android | Fires when content should be paused. This usually happens right before an ad is about to cover the content. | | `CONTENT_RESUME_REQUESTED` | Android | Fires when content should be resumed. This usually happens when an ad finishes or collapses. | | `CUEPOINTS_CHANGED` | iOS | Cuepoints changed for VOD stream (only used for dynamic ad insertion). | @@ -395,14 +395,18 @@ Enum `AdEvent` possible values for [Android](https://developers.google.com/inter Payload: -| Property | Type | Description | -|----------|---------|-----------------------| -| event | AdEvent | The ad event received | +| Property | Type | Description | +|----------|-------------------------------------|-----------------------| +| event | AdEvent | The ad event received | +| data | Record \| undefined | The ad event data | Example: -```javascript +```json { - "event": "LOADED" + "data": { + "key": "value" + }, + "event": "LOG" } ``` @@ -540,4 +544,4 @@ Example: } ``` -Platforms: Android, iOS \ No newline at end of file +Platforms: Android, iOS diff --git a/ios/Video/Features/RCTIMAAdsManager.swift b/ios/Video/Features/RCTIMAAdsManager.swift index 8a5e0643..4cb55fc4 100644 --- a/ios/Video/Features/RCTIMAAdsManager.swift +++ b/ios/Video/Features/RCTIMAAdsManager.swift @@ -98,10 +98,18 @@ class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate, I if _video.onReceiveAdEvent != nil { let type = convertEventToString(event: event.type) - _video.onReceiveAdEvent?([ - "event": type, - "target": _video.reactTag! - ]); + if (event.adData != nil) { + _video.onReceiveAdEvent?([ + "event": type, + "data": event.adData ?? [String](), + "target": _video.reactTag! + ]); + } else { + _video.onReceiveAdEvent?([ + "event": type, + "target": _video.reactTag! + ]); + } } } diff --git a/src/VideoNativeComponent.ts b/src/VideoNativeComponent.ts index 54634e35..5b954931 100644 --- a/src/VideoNativeComponent.ts +++ b/src/VideoNativeComponent.ts @@ -238,6 +238,7 @@ export type OnPictureInPictureStatusChangedData = Readonly<{ }>; export type OnReceiveAdEventData = Readonly<{ + data?: Record; event: AdEvent; }>; diff --git a/src/types/Ads.ts b/src/types/Ads.ts index 6534a80e..2d100e22 100644 --- a/src/types/Ads.ts +++ b/src/types/Ads.ts @@ -32,7 +32,7 @@ export enum AdEvent { */ AD_PERIOD_STARTED = 'AD_PERIOD_STARTED', /** - * Android only: Fires when the ad's current time value changes. Calling getAdData() on this event will return an AdProgressData object. + * Android only: Fires when the ad's current time value changes. The event `data` will be populated with an AdProgressData object. */ AD_PROGRESS = 'AD_PROGRESS', /** diff --git a/src/types/events.ts b/src/types/events.ts index b1bc1e4b..bfde7a4b 100644 --- a/src/types/events.ts +++ b/src/types/events.ts @@ -115,6 +115,7 @@ export type OnPictureInPictureStatusChangedData = Readonly<{ }>; export type OnReceiveAdEventData = Readonly<{ + data?: Record; event: AdEvent; }>; diff --git a/src/types/video.ts b/src/types/video.ts index 34b0b3d5..ef91e312 100644 --- a/src/types/video.ts +++ b/src/types/video.ts @@ -174,7 +174,7 @@ export interface ReactVideoProps extends ReactVideoEvents { source?: ReactVideoSource; drm?: Drm; style?: StyleProp; - adTagUrl?: string; // iOS + adTagUrl?: string; audioOnly?: boolean; automaticallyWaitsToMinimizeStalling?: boolean; // iOS backBufferDurationMs?: number; // Android