diff --git a/README.md b/README.md index 72dde848..004863ba 100644 --- a/README.md +++ b/README.md @@ -379,6 +379,7 @@ AdMob.addListener(RewardAdPluginEvents.Rewarded, async () => { * [`addListener(AppOpenAdPluginEvents.Opened, ...)`](#addlistenerappopenadplugineventsopened-) * [`addListener(AppOpenAdPluginEvents.Closed, ...)`](#addlistenerappopenadplugineventsclosed-) * [`addListener(AppOpenAdPluginEvents.FailedToShow, ...)`](#addlistenerappopenadplugineventsfailedtoshow-) +* [`addListener(AppOpenAdPluginEvents.AdImpression, ...)`](#addlistenerappopenadplugineventsadimpression-) * [`showBanner(...)`](#showbanner) * [`hideBanner()`](#hidebanner) * [`resumeBanner()`](#resumebanner) @@ -400,6 +401,7 @@ AdMob.addListener(RewardAdPluginEvents.Rewarded, async () => { * [`addListener(InterstitialAdPluginEvents.Dismissed, ...)`](#addlistenerinterstitialadplugineventsdismissed-) * [`addListener(InterstitialAdPluginEvents.FailedToShow, ...)`](#addlistenerinterstitialadplugineventsfailedtoshow-) * [`addListener(InterstitialAdPluginEvents.Showed, ...)`](#addlistenerinterstitialadplugineventsshowed-) +* [`addListener(InterstitialAdPluginEvents.AdImpression, ...)`](#addlistenerinterstitialadplugineventsadimpression-) * [`prepareRewardVideoAd(...)`](#preparerewardvideoad) * [`showRewardVideoAd()`](#showrewardvideoad) * [`addListener(RewardAdPluginEvents.FailedToLoad, ...)`](#addlistenerrewardadplugineventsfailedtoload-) @@ -408,6 +410,7 @@ AdMob.addListener(RewardAdPluginEvents.Rewarded, async () => { * [`addListener(RewardAdPluginEvents.Dismissed, ...)`](#addlistenerrewardadplugineventsdismissed-) * [`addListener(RewardAdPluginEvents.FailedToShow, ...)`](#addlistenerrewardadplugineventsfailedtoshow-) * [`addListener(RewardAdPluginEvents.Showed, ...)`](#addlistenerrewardadplugineventsshowed-) +* [`addListener(RewardAdPluginEvents.AdImpression, ...)`](#addlistenerrewardadplugineventsadimpression-) * [`prepareRewardInterstitialAd(...)`](#preparerewardinterstitialad) * [`showRewardInterstitialAd()`](#showrewardinterstitialad) * [`addListener(RewardInterstitialAdPluginEvents.FailedToLoad, ...)`](#addlistenerrewardinterstitialadplugineventsfailedtoload-) @@ -416,6 +419,7 @@ AdMob.addListener(RewardAdPluginEvents.Rewarded, async () => { * [`addListener(RewardInterstitialAdPluginEvents.Dismissed, ...)`](#addlistenerrewardinterstitialadplugineventsdismissed-) * [`addListener(RewardInterstitialAdPluginEvents.FailedToShow, ...)`](#addlistenerrewardinterstitialadplugineventsfailedtoshow-) * [`addListener(RewardInterstitialAdPluginEvents.Showed, ...)`](#addlistenerrewardinterstitialadplugineventsshowed-) +* [`addListener(RewardInterstitialAdPluginEvents.AdImpression, ...)`](#addlistenerrewardinterstitialadplugineventsadimpression-) * [Interfaces](#interfaces) * [Type Aliases](#type-aliases) * [Enums](#enums) @@ -625,6 +629,22 @@ addListener(eventName: AppOpenAdPluginEvents.FailedToShow, listenerFunc: (error: -------------------- +### addListener(AppOpenAdPluginEvents.AdImpression, ...) + +```typescript +addListener(eventName: AppOpenAdPluginEvents.AdImpression, listenerFunc: (data: AdMobRevenueData) => void) => Promise +``` + +| Param | Type | +| ------------------ | ------------------------------------------------------------------------------------ | +| **`eventName`** | AppOpenAdPluginEvents.AdImpression | +| **`listenerFunc`** | (data: AdMobRevenueData) => void | + +**Returns:** Promise<PluginListenerHandle> + +-------------------- + + ### showBanner(...) ```typescript @@ -971,6 +991,22 @@ addListener(eventName: InterstitialAdPluginEvents.Showed, listenerFunc: () => vo -------------------- +### addListener(InterstitialAdPluginEvents.AdImpression, ...) + +```typescript +addListener(eventName: InterstitialAdPluginEvents.AdImpression, listenerFunc: (data: AdMobRevenueData) => void) => Promise +``` + +| Param | Type | +| ------------------ | ---------------------------------------------------------------------------------------------- | +| **`eventName`** | InterstitialAdPluginEvents.AdImpression | +| **`listenerFunc`** | (data: AdMobRevenueData) => void | + +**Returns:** Promise<PluginListenerHandle> + +-------------------- + + ### prepareRewardVideoAd(...) ```typescript @@ -1101,6 +1137,22 @@ addListener(eventName: RewardAdPluginEvents.Showed, listenerFunc: () => void) => -------------------- +### addListener(RewardAdPluginEvents.AdImpression, ...) + +```typescript +addListener(eventName: RewardAdPluginEvents.AdImpression, listenerFunc: (data: AdMobRevenueData) => void) => Promise +``` + +| Param | Type | +| ------------------ | ---------------------------------------------------------------------------------- | +| **`eventName`** | RewardAdPluginEvents.AdImpression | +| **`listenerFunc`** | (data: AdMobRevenueData) => void | + +**Returns:** Promise<PluginListenerHandle> + +-------------------- + + ### prepareRewardInterstitialAd(...) ```typescript @@ -1231,6 +1283,22 @@ addListener(eventName: RewardInterstitialAdPluginEvents.Showed, listenerFunc: () -------------------- +### addListener(RewardInterstitialAdPluginEvents.AdImpression, ...) + +```typescript +addListener(eventName: RewardInterstitialAdPluginEvents.AdImpression, listenerFunc: (data: AdMobRevenueData) => void) => Promise +``` + +| Param | Type | +| ------------------ | ---------------------------------------------------------------------------------------------------------- | +| **`eventName`** | RewardInterstitialAdPluginEvents.AdImpression | +| **`listenerFunc`** | (data: AdMobRevenueData) => void | + +**Returns:** Promise<PluginListenerHandle> + +-------------------- + + ### Interfaces @@ -1291,6 +1359,18 @@ https://developers.google.com/android/reference/com/google/android/gms/ads/AdErr | **`message`** | string | Gets the message describing the error. | +#### AdMobRevenueData + +| Prop | Type | +| ------------------ | ------------------------------------------------------------- | +| **`adUnitId`** | string | +| **`valueMicros`** | number | +| **`currencyCode`** | string | +| **`precision`** | AdValuePrecision | +| **`networkName`** | string | +| **`impressionId`** | string | + + #### BannerAdOptions This interface extends AdOptions @@ -1436,6 +1516,17 @@ From T, pick a set of properties whose keys are in the union K | **`Opened`** | 'appOpenAdOpened' | | **`Closed`** | 'appOpenAdClosed' | | **`FailedToShow`** | 'appOpenAdFailedToShow' | +| **`AdImpression`** | 'appOpenAdImpression' | + + +#### AdValuePrecision + +| Members | Value | +| ----------------------- | -------------- | +| **`Unknown`** | 0 | +| **`Estimated`** | 1 | +| **`PublisherProvided`** | 2 | +| **`Precise`** | 3 | #### BannerAdSize @@ -1511,6 +1602,7 @@ From T, pick a set of properties whose keys are in the union K | **`Showed`** | 'interstitialAdShowed' | Emits when the Interstitial ad is visible to the user | | **`FailedToShow`** | 'interstitialAdFailedToShow' | Emits when the Interstitial ad is failed to show | | **`Dismissed`** | 'interstitialAdDismissed' | Emits when the Interstitial ad is not visible to the user anymore. | +| **`AdImpression`** | 'interstitialAdImpression' | Emits when an impression-level ad revenue event is recorded | #### RewardAdPluginEvents @@ -1523,6 +1615,7 @@ From T, pick a set of properties whose keys are in the union K | **`FailedToShow`** | 'onRewardedVideoAdFailedToShow' | Emits when the AdReward video is failed to show | | **`Dismissed`** | 'onRewardedVideoAdDismissed' | Emits when the AdReward video is not visible to the user anymore. **Important**: This has nothing to do with the reward it self. This event will emits in this two cases: 1. The user starts the video ad but close it before the reward emit. 2. The user start the video and see it until end, then gets the reward and after that the ad is closed. | | **`Rewarded`** | 'onRewardedVideoAdReward' | Emits when user get rewarded from AdReward | +| **`AdImpression`** | 'onRewardedVideoAdImpression' | Emits when an impression-level ad revenue event is recorded | #### RewardInterstitialAdPluginEvents @@ -1535,6 +1628,7 @@ From T, pick a set of properties whose keys are in the union K | **`FailedToShow`** | 'onRewardedInterstitialAdFailedToShow' | Emits when the AdReward video is failed to show | | **`Dismissed`** | 'onRewardedInterstitialAdDismissed' | Emits when the AdReward video is not visible to the user anymore. **Important**: This has nothing to do with the reward it self. This event will emits in this two cases: 1. The user starts the video ad but close it before the reward emit. 2. The user start the video and see it until end, then gets the reward and after that the ad is closed. | | **`Rewarded`** | 'onRewardedInterstitialAdReward' | Emits when user get rewarded from AdReward | +| **`AdImpression`** | 'onRewardedInterstitialAdImpression' | Emits when an impression-level ad revenue event is recorded | diff --git a/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdManager.kt b/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdManager.kt index a5f33fee..1b9cc8b8 100644 --- a/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdManager.kt +++ b/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdManager.kt @@ -5,6 +5,7 @@ import android.content.Context import com.google.android.gms.ads.AdError import com.google.android.gms.ads.AdRequest import com.google.android.gms.ads.FullScreenContentCallback +import com.google.android.gms.ads.AdValue import com.google.android.gms.ads.LoadAdError import com.google.android.gms.ads.appopen.AppOpenAd @@ -17,7 +18,7 @@ class AppOpenAdManager(val adUnitId: String) { val isAdLoaded: Boolean get() = appOpenAd != null - fun loadAd(context: Context, onLoaded: () -> Unit, onFailed: (LoadAdError?) -> Unit) { + fun loadAd(context: Context, onLoaded: () -> Unit, onFailed: (LoadAdError?) -> Unit, onPaidEvent: (AdValue, String, String) -> Unit) { if (appOpenAd != null) { onLoaded() return @@ -40,6 +41,11 @@ class AppOpenAdManager(val adUnitId: String) { override fun onAdLoaded(ad: AppOpenAd) { appOpenAd = ad isLoadingAd = false + ad.setOnPaidEventListener { adValue -> + val networkName = ad.responseInfo?.mediationAdapterClassName ?: "" + val impressionId = ad.responseInfo?.responseId ?: "" + onPaidEvent(adValue, networkName, impressionId) + } onLoaded() } diff --git a/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdPlugin.kt b/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdPlugin.kt index f17a2d5c..66b9ae3b 100644 --- a/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdPlugin.kt +++ b/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdPlugin.kt @@ -7,6 +7,7 @@ import android.os.Looper import com.getcapacitor.JSObject import com.getcapacitor.PluginCall import com.getcapacitor.community.admob.models.AdMobPluginError +import com.getcapacitor.community.admob.models.AdMobRevenueData class AppOpenAdPlugin { @@ -56,6 +57,10 @@ class AppOpenAdPlugin { val errorCode = loadAdError?.code ?: -1 notifier.notify(AppOpenAdPluginEvents.FailedToLoad, AdMobPluginError(errorCode, errorMessage)) call.reject(errorMessage) + }, + onPaidEvent = { adValue, networkName, impressionId -> + val revenueData = AdMobRevenueData(adValue, adUnitId, networkName, impressionId) + notifier.notify(AppOpenAdPluginEvents.AdImpression, revenueData) } ) } diff --git a/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdPluginEvents.kt b/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdPluginEvents.kt index 32adc4e5..e2a7d48f 100644 --- a/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdPluginEvents.kt +++ b/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdPluginEvents.kt @@ -6,4 +6,5 @@ object AppOpenAdPluginEvents { const val Opened = "appOpenAdOpened" const val Closed = "appOpenAdClosed" const val FailedToShow = "appOpenAdFailedToShow" + const val AdImpression = "appOpenAdImpression" } diff --git a/android/src/main/java/com/getcapacitor/community/admob/banner/BannerExecutor.java b/android/src/main/java/com/getcapacitor/community/admob/banner/BannerExecutor.java index c6291395..0e1c2c78 100644 --- a/android/src/main/java/com/getcapacitor/community/admob/banner/BannerExecutor.java +++ b/android/src/main/java/com/getcapacitor/community/admob/banner/BannerExecutor.java @@ -18,6 +18,7 @@ import com.getcapacitor.community.admob.helpers.AdViewIdHelper; import com.getcapacitor.community.admob.helpers.RequestHelper; import com.getcapacitor.community.admob.models.AdMobPluginError; +import com.getcapacitor.community.admob.models.AdMobRevenueData; import com.getcapacitor.community.admob.models.AdOptions; import com.getcapacitor.community.admob.models.Executor; import com.google.android.gms.ads.AdListener; @@ -287,15 +288,22 @@ public void onAdClosed() { notifyListeners(BannerAdPluginEvents.Closed.getWebEventName(), emptyObject); super.onAdClosed(); } - - @Override - public void onAdImpression() { - notifyListeners(BannerAdPluginEvents.AdImpression.getWebEventName(), emptyObject); - super.onAdImpression(); - } } ); + mAdView.setOnPaidEventListener((adValue) -> { + String networkName = ""; + String impressionId = ""; + if (mAdView.getResponseInfo() != null) { + networkName = mAdView.getResponseInfo().getMediationAdapterClassName(); + if (networkName == null) networkName = ""; + impressionId = mAdView.getResponseInfo().getResponseId(); + if (impressionId == null) impressionId = ""; + } + AdMobRevenueData revenueData = new AdMobRevenueData(adValue, mAdView.getAdUnitId(), networkName, impressionId); + notifyListeners(BannerAdPluginEvents.AdImpression.getWebEventName(), revenueData); + }); + // Add AdViewLayout top of the WebView mViewGroup.addView(mAdViewLayout); }); diff --git a/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdCallbackAndListeners.kt b/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdCallbackAndListeners.kt index 1aaf6f77..86e8faa4 100644 --- a/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdCallbackAndListeners.kt +++ b/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdCallbackAndListeners.kt @@ -4,6 +4,7 @@ import com.getcapacitor.JSObject import com.getcapacitor.PluginCall import com.getcapacitor.community.admob.helpers.FullscreenPluginCallback import com.getcapacitor.community.admob.models.AdMobPluginError +import com.getcapacitor.community.admob.models.AdMobRevenueData import com.google.android.gms.ads.LoadAdError import com.google.android.gms.ads.interstitial.InterstitialAd import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback @@ -20,6 +21,14 @@ object InterstitialAdCallbackAndListeners { ad.fullScreenContentCallback = FullscreenPluginCallback(InterstitialAdPluginPluginEvent, notifyListenersFunction) ad.setImmersiveMode(immersiveMode ?: false) + ad.setOnPaidEventListener { adValue -> + val responseInfo = ad.responseInfo + val networkName = responseInfo?.mediationAdapterClassName ?: "" + val impressionId = responseInfo?.responseId ?: "" + val revenueData = AdMobRevenueData(adValue, ad.adUnitId, networkName, impressionId) + notifyListenersFunction.accept(InterstitialAdPluginPluginEvent.AdImpression, revenueData) + } + AdInterstitialExecutor.interstitialAd = ad val adInfo = JSObject() diff --git a/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdPluginPluginEvent.kt b/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdPluginPluginEvent.kt index 2cef74a3..1189a4c4 100644 --- a/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdPluginPluginEvent.kt +++ b/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdPluginPluginEvent.kt @@ -8,4 +8,5 @@ object InterstitialAdPluginPluginEvent: LoadPluginEventNames { override val Showed = "interstitialAdShowed" override val FailedToShow = "interstitialAdFailedToShow" override val Dismissed = "interstitialAdDismissed" + const val AdImpression = "interstitialAdImpression" } \ No newline at end of file diff --git a/android/src/main/java/com/getcapacitor/community/admob/models/AdMobRevenueData.kt b/android/src/main/java/com/getcapacitor/community/admob/models/AdMobRevenueData.kt new file mode 100644 index 00000000..535a3d21 --- /dev/null +++ b/android/src/main/java/com/getcapacitor/community/admob/models/AdMobRevenueData.kt @@ -0,0 +1,15 @@ +package com.getcapacitor.community.admob.models + +import com.getcapacitor.JSObject +import com.google.android.gms.ads.AdValue + +class AdMobRevenueData(adValue: AdValue, adUnitId: String, networkName: String, impressionId: String) : JSObject() { + init { + put("adUnitId", adUnitId) + put("valueMicros", adValue.valueMicros) + put("currencyCode", adValue.currencyCode) + put("precision", adValue.precisionType) + put("networkName", networkName) + put("impressionId", impressionId) + } +} diff --git a/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardAdPluginEvents.kt b/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardAdPluginEvents.kt index c491645c..09339843 100644 --- a/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardAdPluginEvents.kt +++ b/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardAdPluginEvents.kt @@ -9,4 +9,5 @@ object RewardAdPluginEvents: LoadPluginEventNames { override val Showed = "onRewardedVideoAdShowed" override val FailedToShow = "onRewardedVideoAdFailedToShow" override val Dismissed = "onRewardedVideoAdDismissed" + const val AdImpression = "onRewardedVideoAdImpression" } \ No newline at end of file diff --git a/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardedAdCallbackAndListeners.kt b/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardedAdCallbackAndListeners.kt index c4650777..08c398e6 100644 --- a/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardedAdCallbackAndListeners.kt +++ b/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardedAdCallbackAndListeners.kt @@ -4,6 +4,7 @@ import com.getcapacitor.JSObject import com.getcapacitor.PluginCall import com.getcapacitor.community.admob.helpers.FullscreenPluginCallback import com.getcapacitor.community.admob.models.AdMobPluginError +import com.getcapacitor.community.admob.models.AdMobRevenueData import com.getcapacitor.community.admob.models.AdOptions import com.google.android.gms.ads.LoadAdError import com.google.android.gms.ads.OnUserEarnedRewardListener @@ -35,6 +36,14 @@ object RewardedAdCallbackAndListeners { AdRewardExecutor.mRewardedAd.fullScreenContentCallback = FullscreenPluginCallback( RewardAdPluginEvents, notifyListenersFunction) + ad.setOnPaidEventListener { adValue -> + val responseInfo = ad.responseInfo + val networkName = responseInfo?.mediationAdapterClassName ?: "" + val impressionId = responseInfo?.responseId ?: "" + val revenueData = AdMobRevenueData(adValue, ad.adUnitId, networkName, impressionId) + notifyListenersFunction.accept(RewardAdPluginEvents.AdImpression, revenueData) + } + if(adOptions.ssvInfo.hasInfo){ val ssvOptions = ServerSideVerificationOptions.Builder() adOptions.ssvInfo.customData?.let { diff --git a/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardInterstitialAdPluginEvents.kt b/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardInterstitialAdPluginEvents.kt index ce1c2ee8..4d25ff76 100644 --- a/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardInterstitialAdPluginEvents.kt +++ b/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardInterstitialAdPluginEvents.kt @@ -9,4 +9,5 @@ object RewardInterstitialAdPluginEvents: LoadPluginEventNames { override val Showed = "onRewardedInterstitialAdShowed" override val FailedToShow = "onRewardedInterstitialAdFailedToShow" override val Dismissed = "onRewardedInterstitialAdDismissed" + const val AdImpression = "onRewardedInterstitialAdImpression" } \ No newline at end of file diff --git a/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardedInterstitialAdCallbackAndListeners.kt b/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardedInterstitialAdCallbackAndListeners.kt index 06488327..28586254 100644 --- a/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardedInterstitialAdCallbackAndListeners.kt +++ b/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardedInterstitialAdCallbackAndListeners.kt @@ -4,6 +4,7 @@ import com.getcapacitor.JSObject import com.getcapacitor.PluginCall import com.getcapacitor.community.admob.helpers.FullscreenPluginCallback import com.getcapacitor.community.admob.models.AdMobPluginError +import com.getcapacitor.community.admob.models.AdMobRevenueData import com.getcapacitor.community.admob.models.AdOptions import com.google.android.gms.ads.LoadAdError import com.google.android.gms.ads.OnUserEarnedRewardListener @@ -31,6 +32,14 @@ object RewardedInterstitialAdCallbackAndListeners { AdRewardInterstitialExecutor.mRewardedInterstitialAd.fullScreenContentCallback = FullscreenPluginCallback( RewardInterstitialAdPluginEvents, notifyListenersFunction) + ad.setOnPaidEventListener { adValue -> + val responseInfo = ad.responseInfo + val networkName = responseInfo?.mediationAdapterClassName ?: "" + val impressionId = responseInfo?.responseId ?: "" + val revenueData = AdMobRevenueData(adValue, ad.adUnitId, networkName, impressionId) + notifyListenersFunction.accept(RewardInterstitialAdPluginEvents.AdImpression, revenueData) + } + val adInfo = JSObject() adInfo.put("adUnitId", ad.adUnitId) call.resolve(adInfo) diff --git a/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdManager.swift b/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdManager.swift index bf249071..fa5a5b87 100644 --- a/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdManager.swift +++ b/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdManager.swift @@ -13,7 +13,7 @@ import UIKit self.adUnitId = adUnitId } - public func loadAd(onLoaded: @escaping () -> Void, onFailed: @escaping (Error?) -> Void) { + public func loadAd(onLoaded: @escaping () -> Void, onFailed: @escaping (Error?) -> Void, onPaidEvent: @escaping (_ valueMicros: Int64, _ currencyCode: String, _ precision: Int, _ networkName: String, _ impressionId: String) -> Void) { if appOpenAd != nil { onLoaded() return @@ -34,6 +34,17 @@ import UIKit await MainActor.run { self.isLoadingAd = false self.appOpenAd = ad + ad.paidEventHandler = { adValue in + let networkName = ad.responseInfo.loadedAdNetworkResponseInfo?.adNetworkClassName ?? "" + let impressionId = ad.responseInfo.responseIdentifier ?? "" + onPaidEvent( + adValue.value.int64Value, + adValue.currencyCode, + adValue.precision.rawValue, + networkName, + impressionId + ) + } onLoaded() } } catch { diff --git a/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPlugin.swift b/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPlugin.swift index ec241f8d..9c439b4f 100644 --- a/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPlugin.swift +++ b/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPlugin.swift @@ -29,6 +29,15 @@ import UIKit "message": message ]) call.reject(message) + }, onPaidEvent: { valueMicros, currencyCode, precision, networkName, impressionId in + notify(AppOpenAdPluginEvents.AdImpression.rawValue, [ + "adUnitId": adUnitId, + "valueMicros": valueMicros, + "currencyCode": currencyCode, + "precision": precision, + "networkName": networkName, + "impressionId": impressionId + ]) }) } } diff --git a/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPluginEvents.swift b/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPluginEvents.swift index c1a44a33..bf3b2e43 100644 --- a/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPluginEvents.swift +++ b/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPluginEvents.swift @@ -4,4 +4,5 @@ public enum AppOpenAdPluginEvents: String { case Opened = "appOpenAdOpened" case Closed = "appOpenAdClosed" case FailedToShow = "appOpenAdFailedToShow" + case AdImpression = "appOpenAdImpression" } diff --git a/ios/Sources/AdMobPlugin/Banner/BannerExecutor.swift b/ios/Sources/AdMobPlugin/Banner/BannerExecutor.swift index 70081af7..29010d49 100644 --- a/ios/Sources/AdMobPlugin/Banner/BannerExecutor.swift +++ b/ios/Sources/AdMobPlugin/Banner/BannerExecutor.swift @@ -49,6 +49,20 @@ class BannerExecutor: NSObject, BannerViewDelegate { self.bannerView.load(request) self.bannerView.delegate = self + self.bannerView.paidEventHandler = { [weak self] adValue in + guard let self = self else { return } + let networkName = self.bannerView.responseInfo?.loadedAdNetworkResponseInfo?.adNetworkClassName ?? "" + let impressionId = self.bannerView.responseInfo?.responseIdentifier ?? "" + self.plugin?.notifyListeners(BannerAdPluginEvents.AdImpression.rawValue, data: [ + "adUnitId": self.bannerView.adUnitID ?? "", + "valueMicros": adValue.value.int64Value, + "currencyCode": adValue.currencyCode, + "precision": adValue.precision.rawValue, + "networkName": networkName, + "impressionId": impressionId + ]) + } + call.resolve([:]) } } @@ -162,7 +176,6 @@ class BannerExecutor: NSObject, BannerViewDelegate { } func bannerViewDidRecordImpression(_ bannerView: BannerView) { - self.plugin?.notifyListeners(BannerAdPluginEvents.AdImpression.rawValue, data: [:]) } /// Tells the delegate that a full-screen view will be presented in response diff --git a/ios/Sources/AdMobPlugin/Interstitial/AdInterstitialExecutor.swift b/ios/Sources/AdMobPlugin/Interstitial/AdInterstitialExecutor.swift index ce31b155..d3f9c269 100644 --- a/ios/Sources/AdMobPlugin/Interstitial/AdInterstitialExecutor.swift +++ b/ios/Sources/AdMobPlugin/Interstitial/AdInterstitialExecutor.swift @@ -23,6 +23,20 @@ class AdInterstitialExecutor: NSObject, FullScreenContentDelegate { self.interstitial = ad self.interstitial.fullScreenContentDelegate = self + + self.interstitial.paidEventHandler = { adValue in + let networkName = ad?.responseInfo.loadedAdNetworkResponseInfo?.adNetworkClassName ?? "" + let impressionId = ad?.responseInfo.responseIdentifier ?? "" + self.plugin?.notifyListeners(InterstitialAdPluginEvents.AdImpression.rawValue, data: [ + "adUnitId": adUnitID, + "valueMicros": adValue.value.int64Value, + "currencyCode": adValue.currencyCode, + "precision": adValue.precision.rawValue, + "networkName": networkName, + "impressionId": impressionId + ]) + } + self.plugin?.notifyListeners(InterstitialAdPluginEvents.Loaded.rawValue, data: [ "adUnitId": adUnitID ]) diff --git a/ios/Sources/AdMobPlugin/Interstitial/InterstitialAdPluginEvents.swift b/ios/Sources/AdMobPlugin/Interstitial/InterstitialAdPluginEvents.swift index 82d60957..f8c2e049 100644 --- a/ios/Sources/AdMobPlugin/Interstitial/InterstitialAdPluginEvents.swift +++ b/ios/Sources/AdMobPlugin/Interstitial/InterstitialAdPluginEvents.swift @@ -4,4 +4,5 @@ public enum InterstitialAdPluginEvents: String { case Showed = "interstitialAdShowed" case FailedToShow = "interstitialAdFailedToShow" case Dismissed = "interstitialAdDismissed" + case AdImpression = "interstitialAdImpression" } diff --git a/ios/Sources/AdMobPlugin/Rewarded/AdRewardExecutor.swift b/ios/Sources/AdMobPlugin/Rewarded/AdRewardExecutor.swift index 8e4d4346..a99f6a98 100644 --- a/ios/Sources/AdMobPlugin/Rewarded/AdRewardExecutor.swift +++ b/ios/Sources/AdMobPlugin/Rewarded/AdRewardExecutor.swift @@ -40,6 +40,20 @@ class AdRewardExecutor: NSObject, FullScreenContentDelegate { } self.rewardedAd?.fullScreenContentDelegate = self + + self.rewardedAd?.paidEventHandler = { adValue in + let networkName = ad?.responseInfo.loadedAdNetworkResponseInfo?.adNetworkClassName ?? "" + let impressionId = ad?.responseInfo.responseIdentifier ?? "" + self.plugin?.notifyListeners(RewardAdPluginEvents.AdImpression.rawValue, data: [ + "adUnitId": adUnitID, + "valueMicros": adValue.value.int64Value, + "currencyCode": adValue.currencyCode, + "precision": adValue.precision.rawValue, + "networkName": networkName, + "impressionId": impressionId + ]) + } + self.plugin?.notifyListeners(RewardAdPluginEvents.Loaded.rawValue, data: [ "adUnitId": adUnitID ]) diff --git a/ios/Sources/AdMobPlugin/Rewarded/RewardAdPluginEvents.swift b/ios/Sources/AdMobPlugin/Rewarded/RewardAdPluginEvents.swift index b4084784..ab916792 100644 --- a/ios/Sources/AdMobPlugin/Rewarded/RewardAdPluginEvents.swift +++ b/ios/Sources/AdMobPlugin/Rewarded/RewardAdPluginEvents.swift @@ -5,4 +5,5 @@ public enum RewardAdPluginEvents: String { case FailedToShow = "onRewardedVideoAdFailedToShow" case Dismissed = "onRewardedVideoAdDismissed" case Rewarded = "onRewardedVideoAdReward" + case AdImpression = "onRewardedVideoAdImpression" } diff --git a/ios/Sources/AdMobPlugin/RewardedInterstitial/AdRewardInterstitialExecutor.swift b/ios/Sources/AdMobPlugin/RewardedInterstitial/AdRewardInterstitialExecutor.swift index 1d446095..89b0633f 100644 --- a/ios/Sources/AdMobPlugin/RewardedInterstitial/AdRewardInterstitialExecutor.swift +++ b/ios/Sources/AdMobPlugin/RewardedInterstitial/AdRewardInterstitialExecutor.swift @@ -40,6 +40,20 @@ class AdRewardInterstitialExecutor: NSObject, FullScreenContentDelegate { } self.rewardedInterstitialAd?.fullScreenContentDelegate = self + + self.rewardedInterstitialAd?.paidEventHandler = { adValue in + let networkName = ad?.responseInfo.loadedAdNetworkResponseInfo?.adNetworkClassName ?? "" + let impressionId = ad?.responseInfo.responseIdentifier ?? "" + self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.AdImpression.rawValue, data: [ + "adUnitId": adUnitID, + "valueMicros": adValue.value.int64Value, + "currencyCode": adValue.currencyCode, + "precision": adValue.precision.rawValue, + "networkName": networkName, + "impressionId": impressionId + ]) + } + self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.Loaded.rawValue, data: [ "adUnitId": adUnitID ]) diff --git a/ios/Sources/AdMobPlugin/RewardedInterstitial/RewardInterstitialAdPluginEvents.swift b/ios/Sources/AdMobPlugin/RewardedInterstitial/RewardInterstitialAdPluginEvents.swift index 8595de09..73703593 100644 --- a/ios/Sources/AdMobPlugin/RewardedInterstitial/RewardInterstitialAdPluginEvents.swift +++ b/ios/Sources/AdMobPlugin/RewardedInterstitial/RewardInterstitialAdPluginEvents.swift @@ -5,4 +5,5 @@ public enum RewardInterstitialAdPluginEvents: String { case FailedToShow = "onRewardedInterstitialAdFailedToShow" case Dismissed = "onRewardedInterstitialAdDismissed" case Rewarded = "onRewardedInterstitialAdReward" + case AdImpression = "onRewardedInterstitialAdImpression" } diff --git a/src/app-open/app-open-ad-plugin-events.enum.ts b/src/app-open/app-open-ad-plugin-events.enum.ts index 327b1e7c..066907ee 100644 --- a/src/app-open/app-open-ad-plugin-events.enum.ts +++ b/src/app-open/app-open-ad-plugin-events.enum.ts @@ -4,4 +4,5 @@ export enum AppOpenAdPluginEvents { Opened = 'appOpenAdOpened', Closed = 'appOpenAdClosed', FailedToShow = 'appOpenAdFailedToShow', + AdImpression = 'appOpenAdImpression', } diff --git a/src/app-open/app-open-definitions.interface.ts b/src/app-open/app-open-definitions.interface.ts index 08ea3471..f929f634 100644 --- a/src/app-open/app-open-definitions.interface.ts +++ b/src/app-open/app-open-definitions.interface.ts @@ -1,7 +1,7 @@ import type { PluginListenerHandle } from '@capacitor/core'; import type { ValidateAllEventsEnumAreImplemented } from '../private/validate-all-events-implemented.type'; -import type { AdMobError } from '../shared'; +import type { AdMobError, AdMobRevenueData } from '../shared'; import type { AppOpenAdOptions } from './app-open-ad-options.interface'; import type { AppOpenAdPluginEvents } from './app-open-ad-plugin-events.enum'; @@ -42,4 +42,9 @@ export interface AppOpenAdPlugin { eventName: AppOpenAdPluginEvents.FailedToShow, listenerFunc: (error: AdMobError) => void, ): Promise; + + addListener( + eventName: AppOpenAdPluginEvents.AdImpression, + listenerFunc: (data: AdMobRevenueData) => void, + ): Promise; } diff --git a/src/interstitial/interstitial-ad-plugin-events.enum.ts b/src/interstitial/interstitial-ad-plugin-events.enum.ts index 41bcb64e..aaed99cd 100644 --- a/src/interstitial/interstitial-ad-plugin-events.enum.ts +++ b/src/interstitial/interstitial-ad-plugin-events.enum.ts @@ -20,4 +20,8 @@ export enum InterstitialAdPluginEvents { * Emits when the Interstitial ad is not visible to the user anymore. */ Dismissed= 'interstitialAdDismissed', + /** + * Emits when an impression-level ad revenue event is recorded + */ + AdImpression = 'interstitialAdImpression', } diff --git a/src/interstitial/interstitial-definitions.interface.ts b/src/interstitial/interstitial-definitions.interface.ts index 74e3dc07..8cf296fd 100644 --- a/src/interstitial/interstitial-definitions.interface.ts +++ b/src/interstitial/interstitial-definitions.interface.ts @@ -1,7 +1,7 @@ import type { PluginListenerHandle } from '@capacitor/core'; import type { ValidateAllEventsEnumAreImplemented } from '../private/validate-all-events-implemented.type'; -import type { AdLoadInfo, AdMobError, AdOptions } from '../shared'; +import type { AdLoadInfo, AdMobError, AdMobRevenueData, AdOptions } from '../shared'; import type { InterstitialAdPluginEvents } from './interstitial-ad-plugin-events.enum'; @@ -54,4 +54,9 @@ export interface InterstitialDefinitions { eventName: InterstitialAdPluginEvents.Showed, listenerFunc: () => void, ): Promise; + + addListener( + eventName: InterstitialAdPluginEvents.AdImpression, + listenerFunc: (data: AdMobRevenueData) => void, + ): Promise; } diff --git a/src/reward-interstitial/reward-interstitial-ad-plugin-events.enum.ts b/src/reward-interstitial/reward-interstitial-ad-plugin-events.enum.ts index 0d6ffce2..7e5795a7 100644 --- a/src/reward-interstitial/reward-interstitial-ad-plugin-events.enum.ts +++ b/src/reward-interstitial/reward-interstitial-ad-plugin-events.enum.ts @@ -30,4 +30,8 @@ export enum RewardInterstitialAdPluginEvents { * Emits when user get rewarded from AdReward */ Rewarded = 'onRewardedInterstitialAdReward', + /** + * Emits when an impression-level ad revenue event is recorded + */ + AdImpression = 'onRewardedInterstitialAdImpression', } diff --git a/src/reward-interstitial/reward-interstitial-definitions.interface.ts b/src/reward-interstitial/reward-interstitial-definitions.interface.ts index 50ffdd22..66ef5990 100644 --- a/src/reward-interstitial/reward-interstitial-definitions.interface.ts +++ b/src/reward-interstitial/reward-interstitial-definitions.interface.ts @@ -1,7 +1,7 @@ import type { PluginListenerHandle } from '@capacitor/core'; import type { ValidateAllEventsEnumAreImplemented } from '../private/validate-all-events-implemented.type'; -import type { AdLoadInfo, AdMobError } from '../shared'; +import type { AdLoadInfo, AdMobError, AdMobRevenueData } from '../shared'; import type { RewardInterstitialAdOptions } from './reward-interstitial-ad-options.interface'; import type { RewardInterstitialAdPluginEvents } from './reward-interstitial-ad-plugin-events.enum'; @@ -63,4 +63,9 @@ export interface RewardInterstitialDefinitions { eventName: RewardInterstitialAdPluginEvents.Showed, listenerFunc: () => void, ): Promise; + + addListener( + eventName: RewardInterstitialAdPluginEvents.AdImpression, + listenerFunc: (data: AdMobRevenueData) => void, + ): Promise; } diff --git a/src/reward/reward-ad-plugin-events.enum.ts b/src/reward/reward-ad-plugin-events.enum.ts index 212ac23d..0151358d 100644 --- a/src/reward/reward-ad-plugin-events.enum.ts +++ b/src/reward/reward-ad-plugin-events.enum.ts @@ -30,4 +30,8 @@ export enum RewardAdPluginEvents { * Emits when user get rewarded from AdReward */ Rewarded= 'onRewardedVideoAdReward', + /** + * Emits when an impression-level ad revenue event is recorded + */ + AdImpression = 'onRewardedVideoAdImpression', } diff --git a/src/reward/reward-definitions.interface.ts b/src/reward/reward-definitions.interface.ts index 3c9ed3b5..f39a935e 100644 --- a/src/reward/reward-definitions.interface.ts +++ b/src/reward/reward-definitions.interface.ts @@ -1,7 +1,7 @@ import type { PluginListenerHandle } from '@capacitor/core'; import type { ValidateAllEventsEnumAreImplemented } from '../private/validate-all-events-implemented.type'; -import type { AdLoadInfo, AdMobError } from '../shared'; +import type { AdLoadInfo, AdMobError, AdMobRevenueData } from '../shared'; import type { RewardAdOptions } from './reward-ad-options.interface'; import type { RewardAdPluginEvents } from './reward-ad-plugin-events.enum'; @@ -60,4 +60,9 @@ export interface RewardDefinitions { eventName: RewardAdPluginEvents.Showed, listenerFunc: () => void, ): Promise; + + addListener( + eventName: RewardAdPluginEvents.AdImpression, + listenerFunc: (data: AdMobRevenueData) => void, + ): Promise; } diff --git a/src/shared/ad-mob-revenue-data.interface.ts b/src/shared/ad-mob-revenue-data.interface.ts new file mode 100644 index 00000000..2af92f96 --- /dev/null +++ b/src/shared/ad-mob-revenue-data.interface.ts @@ -0,0 +1,15 @@ +export enum AdValuePrecision { + Unknown = 0, + Estimated = 1, + PublisherProvided = 2, + Precise = 3, +} + +export interface AdMobRevenueData { + adUnitId: string; + valueMicros: number; + currencyCode: string; + precision: AdValuePrecision; + networkName: string; + impressionId: string; +} diff --git a/src/shared/index.ts b/src/shared/index.ts index fd4ddce8..9b1240ec 100644 --- a/src/shared/index.ts +++ b/src/shared/index.ts @@ -1,3 +1,4 @@ export * from './ad-load-info.interface'; export * from './ad-options.interface'; export * from './admob-error.interface'; +export * from './ad-mob-revenue-data.interface';