@capacitor-community/admob 8.0.1 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/CapacitorCommunityAdmob.podspec +1 -1
  2. package/Package.swift +1 -1
  3. package/README.md +470 -186
  4. package/android/build.gradle +1 -1
  5. package/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdManager.kt +7 -1
  6. package/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdPlugin.kt +26 -8
  7. package/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdPluginEvents.kt +1 -0
  8. package/android/src/main/java/com/getcapacitor/community/admob/banner/BannerAdPluginEvents.kt +2 -1
  9. package/android/src/main/java/com/getcapacitor/community/admob/banner/BannerExecutor.java +79 -29
  10. package/android/src/main/java/com/getcapacitor/community/admob/helpers/FullscreenPluginCallback.kt +7 -2
  11. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/AdInterstitialExecutor.java +21 -3
  12. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdCallbackAndListeners.kt +12 -2
  13. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdPluginPluginEvent.kt +1 -0
  14. package/android/src/main/java/com/getcapacitor/community/admob/models/AdMobRevenueData.kt +15 -0
  15. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/AdRewardExecutor.java +20 -3
  16. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardAdPluginEvents.kt +1 -0
  17. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardedAdCallbackAndListeners.kt +14 -4
  18. package/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/AdRewardInterstitialExecutor.java +20 -3
  19. package/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardInterstitialAdPluginEvents.kt +1 -0
  20. package/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardedInterstitialAdCallbackAndListeners.kt +14 -3
  21. package/dist/docs.json +511 -178
  22. package/dist/esm/app-open/app-open-ad-options.interface.d.ts +6 -0
  23. package/dist/esm/app-open/app-open-ad-plugin-events.enum.d.ts +20 -1
  24. package/dist/esm/app-open/app-open-ad-plugin-events.enum.js +19 -0
  25. package/dist/esm/app-open/app-open-ad-plugin-events.enum.js.map +1 -1
  26. package/dist/esm/app-open/app-open-definitions.interface.d.ts +31 -8
  27. package/dist/esm/banner/banner-ad-options.interface.d.ts +5 -6
  28. package/dist/esm/banner/banner-ad-plugin-events.enum.d.ts +17 -4
  29. package/dist/esm/banner/banner-ad-plugin-events.enum.js +16 -3
  30. package/dist/esm/banner/banner-ad-plugin-events.enum.js.map +1 -1
  31. package/dist/esm/banner/banner-ad-position.enum.d.ts +3 -3
  32. package/dist/esm/banner/banner-ad-position.enum.js +3 -3
  33. package/dist/esm/banner/banner-ad-size.enum.d.ts +4 -3
  34. package/dist/esm/banner/banner-ad-size.enum.js +4 -3
  35. package/dist/esm/banner/banner-ad-size.enum.js.map +1 -1
  36. package/dist/esm/banner/banner-definitions.interface.d.ts +17 -10
  37. package/dist/esm/banner/banner-size.interface.d.ts +8 -1
  38. package/dist/esm/definitions.d.ts +17 -16
  39. package/dist/esm/definitions.js.map +1 -1
  40. package/dist/esm/interstitial/interstitial-ad-plugin-events.enum.d.ts +10 -6
  41. package/dist/esm/interstitial/interstitial-ad-plugin-events.enum.js +9 -5
  42. package/dist/esm/interstitial/interstitial-ad-plugin-events.enum.js.map +1 -1
  43. package/dist/esm/interstitial/interstitial-definitions.interface.d.ts +24 -4
  44. package/dist/esm/reward/reward-ad-options.interface.d.ts +7 -6
  45. package/dist/esm/reward/reward-ad-plugin-events.enum.d.ts +13 -12
  46. package/dist/esm/reward/reward-ad-plugin-events.enum.js +12 -11
  47. package/dist/esm/reward/reward-ad-plugin-events.enum.js.map +1 -1
  48. package/dist/esm/reward/reward-definitions.interface.d.ts +27 -4
  49. package/dist/esm/reward/reward-item.interface.d.ts +3 -4
  50. package/dist/esm/reward-interstitial/reward-interstitial-ad-options.interface.d.ts +7 -6
  51. package/dist/esm/reward-interstitial/reward-interstitial-ad-plugin-events.enum.d.ts +13 -12
  52. package/dist/esm/reward-interstitial/reward-interstitial-ad-plugin-events.enum.js +12 -11
  53. package/dist/esm/reward-interstitial/reward-interstitial-ad-plugin-events.enum.js.map +1 -1
  54. package/dist/esm/reward-interstitial/reward-interstitial-definitions.interface.d.ts +30 -7
  55. package/dist/esm/reward-interstitial/reward-interstitial-item.interface.d.ts +3 -4
  56. package/dist/esm/shared/ad-load-info.interface.d.ts +6 -0
  57. package/dist/esm/shared/ad-mob-revenue-data.interface.d.ts +50 -0
  58. package/dist/esm/shared/ad-mob-revenue-data.interface.js +23 -0
  59. package/dist/esm/shared/ad-mob-revenue-data.interface.js.map +1 -0
  60. package/dist/esm/shared/ad-options.interface.d.ts +9 -11
  61. package/dist/esm/shared/ad-show-options.interface.d.ts +12 -0
  62. package/dist/esm/shared/ad-show-options.interface.js +2 -0
  63. package/dist/esm/shared/ad-show-options.interface.js.map +1 -0
  64. package/dist/esm/shared/admob-error.interface.d.ts +3 -2
  65. package/dist/esm/shared/index.d.ts +2 -0
  66. package/dist/esm/shared/index.js +2 -0
  67. package/dist/esm/shared/index.js.map +1 -1
  68. package/dist/esm/shared/tracking-authorization-status.interface.d.ts +6 -1
  69. package/dist/esm/web.d.ts +6 -6
  70. package/dist/esm/web.js +11 -6
  71. package/dist/esm/web.js.map +1 -1
  72. package/dist/plugin.cjs.js +109 -42
  73. package/dist/plugin.cjs.js.map +1 -1
  74. package/dist/plugin.js +109 -42
  75. package/dist/plugin.js.map +1 -1
  76. package/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdManager.swift +12 -1
  77. package/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPlugin.swift +40 -10
  78. package/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPluginEvents.swift +1 -0
  79. package/ios/Sources/AdMobPlugin/Banner/BannerAdPluginEvents.swift +1 -0
  80. package/ios/Sources/AdMobPlugin/Banner/BannerExecutor.swift +14 -0
  81. package/ios/Sources/AdMobPlugin/Interstitial/AdInterstitialExecutor.swift +41 -5
  82. package/ios/Sources/AdMobPlugin/Interstitial/InterstitialAdPluginEvents.swift +1 -0
  83. package/ios/Sources/AdMobPlugin/Rewarded/AdRewardExecutor.swift +44 -5
  84. package/ios/Sources/AdMobPlugin/Rewarded/RewardAdPluginEvents.swift +1 -0
  85. package/ios/Sources/AdMobPlugin/RewardedInterstitial/AdRewardInterstitialExecutor.swift +45 -6
  86. package/ios/Sources/AdMobPlugin/RewardedInterstitial/RewardInterstitialAdPluginEvents.swift +1 -0
  87. package/package.json +1 -1
@@ -4,7 +4,7 @@ ext {
4
4
  androidxCoordinatorLayoutVersion = project.hasProperty('androidxCoordinatorLayoutVersion') ? rootProject.ext.androidxCoordinatorLayoutVersion : '1.3.0'
5
5
  androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
6
6
  androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
7
- playServicesAdsVersion = project.hasProperty('playServicesAdsVersion') ? rootProject.ext.playServicesAdsVersion : '24.9.+'
7
+ playServicesAdsVersion = project.hasProperty('playServicesAdsVersion') ? rootProject.ext.playServicesAdsVersion : '25.4.+'
8
8
  userMessagingPlatformVersion = project.hasProperty('userMessagingPlatformVersion') ? rootProject.ext.userMessagingPlatformVersion : '4.0.0'
9
9
  androidxCoreKTXVersion = project.hasProperty('androidxCoreKTXVersion') ? rootProject.ext.androidxCoreKTXVersion : '1.15.0'
10
10
  }
@@ -5,6 +5,7 @@ import android.content.Context
5
5
  import com.google.android.gms.ads.AdError
6
6
  import com.google.android.gms.ads.AdRequest
7
7
  import com.google.android.gms.ads.FullScreenContentCallback
8
+ import com.google.android.gms.ads.AdValue
8
9
  import com.google.android.gms.ads.LoadAdError
9
10
  import com.google.android.gms.ads.appopen.AppOpenAd
10
11
 
@@ -17,7 +18,7 @@ class AppOpenAdManager(val adUnitId: String) {
17
18
  val isAdLoaded: Boolean
18
19
  get() = appOpenAd != null
19
20
 
20
- fun loadAd(context: Context, onLoaded: () -> Unit, onFailed: (LoadAdError?) -> Unit) {
21
+ fun loadAd(context: Context, onLoaded: () -> Unit, onFailed: (LoadAdError?) -> Unit, onPaidEvent: (AdValue, String, String) -> Unit) {
21
22
  if (appOpenAd != null) {
22
23
  onLoaded()
23
24
  return
@@ -40,6 +41,11 @@ class AppOpenAdManager(val adUnitId: String) {
40
41
  override fun onAdLoaded(ad: AppOpenAd) {
41
42
  appOpenAd = ad
42
43
  isLoadingAd = false
44
+ ad.setOnPaidEventListener { adValue ->
45
+ val networkName = ad.responseInfo?.mediationAdapterClassName ?: ""
46
+ val impressionId = ad.responseInfo?.responseId ?: ""
47
+ onPaidEvent(adValue, networkName, impressionId)
48
+ }
43
49
  onLoaded()
44
50
  }
45
51
 
@@ -7,6 +7,7 @@ import android.os.Looper
7
7
  import com.getcapacitor.JSObject
8
8
  import com.getcapacitor.PluginCall
9
9
  import com.getcapacitor.community.admob.models.AdMobPluginError
10
+ import com.getcapacitor.community.admob.models.AdMobRevenueData
10
11
 
11
12
  class AppOpenAdPlugin {
12
13
 
@@ -14,7 +15,8 @@ class AppOpenAdPlugin {
14
15
  fun notify(eventName: String, data: JSObject)
15
16
  }
16
17
 
17
- private var appOpenAdManager: AppOpenAdManager? = null
18
+ private val preparedManagers = LinkedHashMap<String, AppOpenAdManager>()
19
+ private var lastPreparedAdId: String? = null
18
20
 
19
21
  private fun runOnMain(activity: Activity?, runnable: Runnable) {
20
22
  if (activity != null) {
@@ -38,13 +40,12 @@ class AppOpenAdPlugin {
38
40
 
39
41
  val appContext = context.applicationContext
40
42
  runOnMain(activity) {
41
- if (appOpenAdManager == null || adUnitId != appOpenAdManager?.adUnitId) {
42
- appOpenAdManager = AppOpenAdManager(adUnitId)
43
- }
43
+ val manager = preparedManagers.getOrPut(adUnitId) { AppOpenAdManager(adUnitId) }
44
44
 
45
- appOpenAdManager?.loadAd(
45
+ manager.loadAd(
46
46
  appContext,
47
47
  onLoaded = {
48
+ lastPreparedAdId = adUnitId
48
49
  val adInfo = JSObject().apply {
49
50
  put("adUnitId", adUnitId)
50
51
  }
@@ -56,6 +57,10 @@ class AppOpenAdPlugin {
56
57
  val errorCode = loadAdError?.code ?: -1
57
58
  notifier.notify(AppOpenAdPluginEvents.FailedToLoad, AdMobPluginError(errorCode, errorMessage))
58
59
  call.reject(errorMessage)
60
+ },
61
+ onPaidEvent = { adValue, networkName, impressionId ->
62
+ val revenueData = AdMobRevenueData(adValue, adUnitId, networkName, impressionId)
63
+ notifier.notify(AppOpenAdPluginEvents.AdImpression, revenueData)
59
64
  }
60
65
  )
61
66
  }
@@ -67,22 +72,34 @@ class AppOpenAdPlugin {
67
72
  return
68
73
  }
69
74
 
75
+ val adId = call.getString("adId") ?: lastPreparedAdId
76
+
70
77
  runOnMain(activity) {
71
- if (appOpenAdManager == null || appOpenAdManager?.isAdLoaded != true) {
78
+ val manager = if (adId != null) preparedManagers[adId] else null
79
+
80
+ if (manager == null || !manager.isAdLoaded) {
72
81
  call.reject("App Open Ad is not loaded")
73
82
  return@runOnMain
74
83
  }
75
84
 
76
- appOpenAdManager?.showAdIfAvailable(
85
+ manager.showAdIfAvailable(
77
86
  activity,
78
87
  onOpened = {
79
88
  notifier.notify(AppOpenAdPluginEvents.Opened, JSObject())
80
89
  },
81
90
  onClosed = {
91
+ preparedManagers.remove(adId)
92
+ if (lastPreparedAdId == adId) {
93
+ lastPreparedAdId = preparedManagers.entries.lastOrNull { it.value.isAdLoaded }?.key
94
+ }
82
95
  notifier.notify(AppOpenAdPluginEvents.Closed, JSObject())
83
96
  call.resolve()
84
97
  },
85
98
  onFailedToShow = { adError ->
99
+ preparedManagers.remove(adId)
100
+ if (lastPreparedAdId == adId) {
101
+ lastPreparedAdId = preparedManagers.entries.lastOrNull { it.value.isAdLoaded }?.key
102
+ }
86
103
  val errorMessage = adError?.message ?: "Failed to show App Open Ad"
87
104
  val errorCode = adError?.code ?: -1
88
105
  notifier.notify(AppOpenAdPluginEvents.FailedToShow, AdMobPluginError(errorCode, errorMessage))
@@ -93,8 +110,9 @@ class AppOpenAdPlugin {
93
110
  }
94
111
 
95
112
  fun isAppOpenLoaded(activity: Activity?, call: PluginCall) {
113
+ val adId = call.getString("adId") ?: lastPreparedAdId
96
114
  runOnMain(activity) {
97
- val loaded = appOpenAdManager?.isAdLoaded ?: false
115
+ val loaded = adId?.let { preparedManagers[it]?.isAdLoaded } ?: false
98
116
  val result = JSObject().apply {
99
117
  put("value", loaded)
100
118
  }
@@ -6,4 +6,5 @@ object AppOpenAdPluginEvents {
6
6
  const val Opened = "appOpenAdOpened"
7
7
  const val Closed = "appOpenAdClosed"
8
8
  const val FailedToShow = "appOpenAdFailedToShow"
9
+ const val AdImpression = "appOpenAdImpression"
9
10
  }
@@ -8,4 +8,5 @@ enum class BannerAdPluginEvents(val webEventName: String) {
8
8
  Loaded("bannerAdLoaded"),
9
9
  Clicked("bannerAdClicked"),
10
10
  AdImpression("bannerAdImpression"),
11
- }
11
+ AdPaid("bannerAdPaid"),
12
+ }
@@ -18,6 +18,7 @@ import com.getcapacitor.PluginCall;
18
18
  import com.getcapacitor.community.admob.helpers.AdViewIdHelper;
19
19
  import com.getcapacitor.community.admob.helpers.RequestHelper;
20
20
  import com.getcapacitor.community.admob.models.AdMobPluginError;
21
+ import com.getcapacitor.community.admob.models.AdMobRevenueData;
21
22
  import com.getcapacitor.community.admob.models.AdOptions;
22
23
  import com.getcapacitor.community.admob.models.Executor;
23
24
  import com.google.android.gms.ads.AdListener;
@@ -103,27 +104,10 @@ public class BannerExecutor extends Executor {
103
104
  break;
104
105
  }
105
106
 
106
- // set Safe Area only for Android 15+
107
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
108
- View rootView = activitySupplier.get().getWindow().getDecorView();
109
- rootView.setOnApplyWindowInsetsListener((v, insets) -> {
110
- int bottomInset = insets.getSystemWindowInsetBottom();
111
- int topInset = insets.getSystemWindowInsetTop();
112
-
113
- if ("TOP_CENTER".equals(adOptions.position)) {
114
- mAdViewLayoutParams.setMargins(0, topInset, 0, 0);
115
- } else {
116
- mAdViewLayoutParams.setMargins(0, 0, 0, bottomInset);
117
- }
118
-
119
- mAdViewLayout.setLayoutParams(mAdViewLayoutParams);
120
- return insets;
121
- });
122
- }
123
-
124
107
  mAdViewLayout.setLayoutParams(mAdViewLayoutParams);
125
108
 
126
109
  int densityMargin = (int) (adOptions.margin * density);
110
+ int[] margins = new int[] { 0, densityMargin, 0, densityMargin };
127
111
 
128
112
  // Center Banner Ads
129
113
  int adWidth = (int) (adOptions.adSize.getSize().getWidth() * density);
@@ -133,15 +117,37 @@ public class BannerExecutor extends Executor {
133
117
  if (fullscreen) {
134
118
  margin = (realWidthPixels - defaultWidthPixels) / 2;
135
119
  }
120
+ margins[0] = margin;
121
+ margins[2] = margin;
136
122
  mAdViewLayoutParams.setMargins(margin, densityMargin, margin, densityMargin);
137
123
  } else {
138
124
  int sideMargin = ((int) defaultWidthPixels - adWidth) / 2;
139
125
  if (fullscreen) {
140
126
  sideMargin = (realWidthPixels - adWidth) / 2;
141
127
  }
128
+ margins[0] = sideMargin;
129
+ margins[2] = sideMargin;
142
130
  mAdViewLayoutParams.setMargins(sideMargin, densityMargin, sideMargin, densityMargin);
143
131
  }
144
132
 
133
+ // set Safe Area only for Android 15+
134
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
135
+ View rootView = activitySupplier.get().getWindow().getDecorView();
136
+ rootView.setOnApplyWindowInsetsListener((v, insets) -> {
137
+ int bottomInset = insets.getSystemWindowInsetBottom();
138
+ int topInset = insets.getSystemWindowInsetTop();
139
+
140
+ if ("TOP_CENTER".equals(adOptions.position)) {
141
+ mAdViewLayoutParams.setMargins(margins[0], margins[1] + topInset, margins[2], margins[3]);
142
+ } else {
143
+ mAdViewLayoutParams.setMargins(margins[0], margins[1], margins[2], margins[3] + bottomInset);
144
+ }
145
+
146
+ mAdViewLayout.setLayoutParams(mAdViewLayoutParams);
147
+ return insets;
148
+ });
149
+ }
150
+
145
151
  createNewAdView(adOptions);
146
152
 
147
153
  call.resolve();
@@ -223,11 +229,19 @@ public class BannerExecutor extends Executor {
223
229
  }
224
230
 
225
231
  private void updateExistingAdView(AdOptions adOptions) {
232
+ // Bind to the AdView present when this call was made. `mAdView` is a
233
+ // shared field that another UI-thread task can null before this one
234
+ // runs; using the captured reference avoids a NullPointerException.
235
+ final AdView adView = mAdView;
226
236
  activitySupplier
227
237
  .get()
228
238
  .runOnUiThread(() -> {
239
+ if (adView != mAdView) {
240
+ // Banner was removed or replaced before this task ran.
241
+ return;
242
+ }
229
243
  final AdRequest adRequest = RequestHelper.createRequest(adOptions);
230
- mAdView.loadAd(adRequest);
244
+ adView.loadAd(adRequest);
231
245
  });
232
246
  }
233
247
 
@@ -236,22 +250,36 @@ public class BannerExecutor extends Executor {
236
250
  * https://developers.google.com/admob/ios/banner?hl=ja
237
251
  */
238
252
  private void createNewAdView(AdOptions adOptions) {
253
+ // Bind to the AdView instance created for this call. `mAdView` is a
254
+ // shared field that removeBanner/hideBanner or a stale ad-listener
255
+ // callback can null from the UI thread before this posted task runs;
256
+ // reading the field inside the task would then throw a
257
+ // NullPointerException (e.g. in AdViewIdHelper.assignIdToAdView).
258
+ final AdView adView = mAdView;
259
+
239
260
  // Run AdMob In Main UI Thread
240
261
  activitySupplier
241
262
  .get()
242
263
  .runOnUiThread(() -> {
264
+ if (adView != mAdView) {
265
+ // Banner was removed or replaced before this task ran.
266
+ return;
267
+ }
243
268
  final AdRequest adRequest = RequestHelper.createRequest(adOptions);
244
269
  // Assign the correct id needed
245
- AdViewIdHelper.assignIdToAdView(mAdView, adOptions, adRequest, logTag, contextSupplier.get());
270
+ AdViewIdHelper.assignIdToAdView(adView, adOptions, adRequest, logTag, contextSupplier.get());
246
271
  // Add the AdView to the view hierarchy.
247
- mAdViewLayout.addView(mAdView);
272
+ mAdViewLayout.addView(adView);
248
273
  // Start loading the ad.
249
- mAdView.loadAd(adRequest);
250
- mAdView.setAdListener(
274
+ adView.loadAd(adRequest);
275
+ adView.setAdListener(
251
276
  new AdListener() {
252
277
  @Override
253
278
  public void onAdLoaded() {
254
- final BannerAdSizeInfo sizeInfo = new BannerAdSizeInfo(mAdView);
279
+ if (adView != mAdView) {
280
+ return;
281
+ }
282
+ final BannerAdSizeInfo sizeInfo = new BannerAdSizeInfo(adView);
255
283
 
256
284
  notifyListeners(BannerAdPluginEvents.SizeChanged.getWebEventName(), sizeInfo);
257
285
  notifyListeners(BannerAdPluginEvents.Loaded.getWebEventName(), emptyObject);
@@ -260,13 +288,19 @@ public class BannerExecutor extends Executor {
260
288
 
261
289
  @Override
262
290
  public void onAdFailedToLoad(@NonNull LoadAdError adError) {
263
- if (mAdView != null) {
264
- mViewGroup.removeView(mAdViewLayout);
265
- mAdViewLayout.removeView(mAdView);
266
- mAdView.destroy();
267
- mAdView = null;
291
+ if (adView != mAdView) {
292
+ // Stale callback from a banner that was already removed or
293
+ // replaced. Do not touch the current banner or emit teardown
294
+ // events for a view the JS layer has already discarded.
295
+ super.onAdFailedToLoad(adError);
296
+ return;
268
297
  }
269
298
 
299
+ mViewGroup.removeView(mAdViewLayout);
300
+ mAdViewLayout.removeView(adView);
301
+ adView.destroy();
302
+ mAdView = null;
303
+
270
304
  final BannerAdSizeInfo sizeInfo = new BannerAdSizeInfo(0, 0);
271
305
  notifyListeners(BannerAdPluginEvents.SizeChanged.getWebEventName(), sizeInfo);
272
306
 
@@ -296,6 +330,22 @@ public class BannerExecutor extends Executor {
296
330
  }
297
331
  );
298
332
 
333
+ adView.setOnPaidEventListener((adValue) -> {
334
+ if (adView != mAdView) {
335
+ return;
336
+ }
337
+ String networkName = "";
338
+ String impressionId = "";
339
+ if (adView.getResponseInfo() != null) {
340
+ networkName = adView.getResponseInfo().getMediationAdapterClassName();
341
+ if (networkName == null) networkName = "";
342
+ impressionId = adView.getResponseInfo().getResponseId();
343
+ if (impressionId == null) impressionId = "";
344
+ }
345
+ AdMobRevenueData revenueData = new AdMobRevenueData(adValue, adView.getAdUnitId(), networkName, impressionId);
346
+ notifyListeners(BannerAdPluginEvents.AdPaid.getWebEventName(), revenueData);
347
+ });
348
+
299
349
  // Add AdViewLayout top of the WebView
300
350
  mViewGroup.addView(mAdViewLayout);
301
351
  });
@@ -7,14 +7,18 @@ import com.google.android.gms.ads.AdError
7
7
  import com.google.android.gms.ads.FullScreenContentCallback
8
8
  import com.google.android.gms.common.util.BiConsumer
9
9
 
10
- class FullscreenPluginCallback(private val loadPluginObject: LoadPluginEventNames,
11
- private val notifyListenersFunction: BiConsumer<String, JSObject>): FullScreenContentCallback() {
10
+ class FullscreenPluginCallback(
11
+ private val loadPluginObject: LoadPluginEventNames,
12
+ private val notifyListenersFunction: BiConsumer<String, JSObject>,
13
+ private val onCompleted: Runnable? = null
14
+ ): FullScreenContentCallback() {
12
15
 
13
16
  override fun onAdShowedFullScreenContent() {
14
17
  notifyListenersFunction.accept(loadPluginObject.Showed, JSObject())
15
18
  }
16
19
 
17
20
  override fun onAdFailedToShowFullScreenContent(adError: AdError) {
21
+ onCompleted?.run()
18
22
  val adMobError = AdMobPluginError(adError)
19
23
  notifyListenersFunction.accept(
20
24
  loadPluginObject.FailedToShow, adMobError
@@ -22,6 +26,7 @@ class FullscreenPluginCallback(private val loadPluginObject: LoadPluginEventName
22
26
  }
23
27
 
24
28
  override fun onAdDismissedFullScreenContent() {
29
+ onCompleted?.run()
25
30
  notifyListenersFunction.accept(loadPluginObject.Dismissed, JSObject())
26
31
  }
27
32
  }
@@ -6,6 +6,7 @@ import androidx.core.util.Supplier;
6
6
  import com.getcapacitor.JSObject;
7
7
  import com.getcapacitor.PluginCall;
8
8
  import com.getcapacitor.community.admob.helpers.AdViewIdHelper;
9
+ import com.getcapacitor.community.admob.helpers.FullscreenPluginCallback;
9
10
  import com.getcapacitor.community.admob.helpers.RequestHelper;
10
11
  import com.getcapacitor.community.admob.models.AdMobPluginError;
11
12
  import com.getcapacitor.community.admob.models.AdOptions;
@@ -13,10 +14,13 @@ import com.getcapacitor.community.admob.models.Executor;
13
14
  import com.google.android.gms.ads.AdRequest;
14
15
  import com.google.android.gms.ads.interstitial.InterstitialAd;
15
16
  import com.google.android.gms.common.util.BiConsumer;
17
+ import java.util.LinkedHashMap;
18
+ import java.util.Map;
16
19
 
17
20
  public class AdInterstitialExecutor extends Executor {
18
21
 
19
- public static InterstitialAd interstitialAd;
22
+ public static final Map<String, InterstitialAd> preparedAds = new LinkedHashMap<>();
23
+ public static String lastPreparedAdId;
20
24
 
21
25
  InterstitialAdCallbackAndListeners adCallbackAndListeners;
22
26
 
@@ -54,7 +58,11 @@ public class AdInterstitialExecutor extends Executor {
54
58
  }
55
59
 
56
60
  public void showInterstitial(final PluginCall call, BiConsumer<String, JSObject> notifyListenersFunction) {
57
- if (interstitialAd == null) {
61
+ String requestedAdId = call.getString("adId");
62
+ String adId = requestedAdId != null ? requestedAdId : lastPreparedAdId;
63
+ InterstitialAd ad = adId != null ? preparedAds.get(adId) : null;
64
+
65
+ if (ad == null) {
58
66
  String errorMessage = "No Interstitial can be shown. It was not prepared or maybe it failed to be prepared.";
59
67
  call.reject(errorMessage);
60
68
  AdMobPluginError errorObject = new AdMobPluginError(-1, errorMessage);
@@ -62,11 +70,21 @@ public class AdInterstitialExecutor extends Executor {
62
70
  return;
63
71
  }
64
72
 
73
+ final InterstitialAd adToShow = ad;
65
74
  activitySupplier
66
75
  .get()
67
76
  .runOnUiThread(() -> {
68
77
  try {
69
- interstitialAd.show(activitySupplier.get());
78
+ adToShow.setFullScreenContentCallback(
79
+ new FullscreenPluginCallback(InterstitialAdPluginPluginEvent.INSTANCE, notifyListenersFunction, () -> {
80
+ preparedAds.remove(adId);
81
+ if (adId != null && adId.equals(lastPreparedAdId)) {
82
+ lastPreparedAdId = null;
83
+ for (String remainingAdId : preparedAds.keySet()) lastPreparedAdId = remainingAdId;
84
+ }
85
+ })
86
+ );
87
+ adToShow.show(activitySupplier.get());
70
88
  call.resolve();
71
89
  } catch (Exception ex) {
72
90
  call.reject(ex.getLocalizedMessage(), ex);
@@ -4,6 +4,7 @@ import com.getcapacitor.JSObject
4
4
  import com.getcapacitor.PluginCall
5
5
  import com.getcapacitor.community.admob.helpers.FullscreenPluginCallback
6
6
  import com.getcapacitor.community.admob.models.AdMobPluginError
7
+ import com.getcapacitor.community.admob.models.AdMobRevenueData
7
8
  import com.google.android.gms.ads.LoadAdError
8
9
  import com.google.android.gms.ads.interstitial.InterstitialAd
9
10
  import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback
@@ -20,7 +21,16 @@ object InterstitialAdCallbackAndListeners {
20
21
  ad.fullScreenContentCallback = FullscreenPluginCallback(InterstitialAdPluginPluginEvent, notifyListenersFunction)
21
22
  ad.setImmersiveMode(immersiveMode ?: false)
22
23
 
23
- AdInterstitialExecutor.interstitialAd = ad
24
+ ad.setOnPaidEventListener { adValue ->
25
+ val responseInfo = ad.responseInfo
26
+ val networkName = responseInfo?.mediationAdapterClassName ?: ""
27
+ val impressionId = responseInfo?.responseId ?: ""
28
+ val revenueData = AdMobRevenueData(adValue, ad.adUnitId, networkName, impressionId)
29
+ notifyListenersFunction.accept(InterstitialAdPluginPluginEvent.AdImpression, revenueData)
30
+ }
31
+
32
+ AdInterstitialExecutor.preparedAds[ad.adUnitId] = ad
33
+ AdInterstitialExecutor.lastPreparedAdId = ad.adUnitId
24
34
 
25
35
  val adInfo = JSObject()
26
36
  adInfo.put("adUnitId", ad.adUnitId)
@@ -37,4 +47,4 @@ object InterstitialAdCallbackAndListeners {
37
47
  }
38
48
  }
39
49
  }
40
- }
50
+ }
@@ -8,4 +8,5 @@ object InterstitialAdPluginPluginEvent: LoadPluginEventNames {
8
8
  override val Showed = "interstitialAdShowed"
9
9
  override val FailedToShow = "interstitialAdFailedToShow"
10
10
  override val Dismissed = "interstitialAdDismissed"
11
+ const val AdImpression = "interstitialAdImpression"
11
12
  }
@@ -0,0 +1,15 @@
1
+ package com.getcapacitor.community.admob.models
2
+
3
+ import com.getcapacitor.JSObject
4
+ import com.google.android.gms.ads.AdValue
5
+
6
+ class AdMobRevenueData(adValue: AdValue, adUnitId: String, networkName: String, impressionId: String) : JSObject() {
7
+ init {
8
+ put("adUnitId", adUnitId)
9
+ put("valueMicros", adValue.valueMicros)
10
+ put("currencyCode", adValue.currencyCode)
11
+ put("precision", adValue.precisionType)
12
+ put("networkName", networkName)
13
+ put("impressionId", impressionId)
14
+ }
15
+ }
@@ -7,6 +7,7 @@ import com.getcapacitor.JSObject;
7
7
  import com.getcapacitor.PluginCall;
8
8
  import com.getcapacitor.PluginMethod;
9
9
  import com.getcapacitor.community.admob.helpers.AdViewIdHelper;
10
+ import com.getcapacitor.community.admob.helpers.FullscreenPluginCallback;
10
11
  import com.getcapacitor.community.admob.helpers.RequestHelper;
11
12
  import com.getcapacitor.community.admob.models.AdMobPluginError;
12
13
  import com.getcapacitor.community.admob.models.AdOptions;
@@ -14,10 +15,13 @@ import com.getcapacitor.community.admob.models.Executor;
14
15
  import com.google.android.gms.ads.AdRequest;
15
16
  import com.google.android.gms.ads.rewarded.RewardedAd;
16
17
  import com.google.android.gms.common.util.BiConsumer;
18
+ import java.util.LinkedHashMap;
19
+ import java.util.Map;
17
20
 
18
21
  public class AdRewardExecutor extends Executor {
19
22
 
20
- public static RewardedAd mRewardedAd;
23
+ public static final Map<String, RewardedAd> preparedAds = new LinkedHashMap<>();
24
+ public static String lastPreparedAdId;
21
25
 
22
26
  public AdRewardExecutor(
23
27
  Supplier<Context> contextSupplier,
@@ -52,7 +56,11 @@ public class AdRewardExecutor extends Executor {
52
56
 
53
57
  @PluginMethod
54
58
  public void showRewardVideoAd(final PluginCall call, BiConsumer<String, JSObject> notifyListenersFunction) {
55
- if (mRewardedAd == null) {
59
+ String requestedAdId = call.getString("adId");
60
+ String adId = requestedAdId != null ? requestedAdId : lastPreparedAdId;
61
+ RewardedAd ad = adId != null ? preparedAds.get(adId) : null;
62
+
63
+ if (ad == null) {
56
64
  String errorMessage = "No Reward Video Ad can be shown. It was not prepared or maybe it failed to be prepared.";
57
65
  call.reject(errorMessage);
58
66
  AdMobPluginError errorObject = new AdMobPluginError(-1, errorMessage);
@@ -64,7 +72,16 @@ public class AdRewardExecutor extends Executor {
64
72
  activitySupplier
65
73
  .get()
66
74
  .runOnUiThread(() -> {
67
- mRewardedAd.show(
75
+ ad.setFullScreenContentCallback(
76
+ new FullscreenPluginCallback(RewardAdPluginEvents.INSTANCE, notifyListenersFunction, () -> {
77
+ preparedAds.remove(adId);
78
+ if (adId != null && adId.equals(lastPreparedAdId)) {
79
+ lastPreparedAdId = null;
80
+ for (String remainingAdId : preparedAds.keySet()) lastPreparedAdId = remainingAdId;
81
+ }
82
+ })
83
+ );
84
+ ad.show(
68
85
  activitySupplier.get(),
69
86
  RewardedAdCallbackAndListeners.INSTANCE.getOnUserEarnedRewardListener(call, notifyListenersFunction)
70
87
  );
@@ -9,4 +9,5 @@ object RewardAdPluginEvents: LoadPluginEventNames {
9
9
  override val Showed = "onRewardedVideoAdShowed"
10
10
  override val FailedToShow = "onRewardedVideoAdFailedToShow"
11
11
  override val Dismissed = "onRewardedVideoAdDismissed"
12
+ const val AdImpression = "onRewardedVideoAdImpression"
12
13
  }
@@ -4,6 +4,7 @@ import com.getcapacitor.JSObject
4
4
  import com.getcapacitor.PluginCall
5
5
  import com.getcapacitor.community.admob.helpers.FullscreenPluginCallback
6
6
  import com.getcapacitor.community.admob.models.AdMobPluginError
7
+ import com.getcapacitor.community.admob.models.AdMobRevenueData
7
8
  import com.getcapacitor.community.admob.models.AdOptions
8
9
  import com.google.android.gms.ads.LoadAdError
9
10
  import com.google.android.gms.ads.OnUserEarnedRewardListener
@@ -30,11 +31,17 @@ object RewardedAdCallbackAndListeners {
30
31
  override fun onAdLoaded(ad: RewardedAd) {
31
32
  val immersiveMode = call.getBoolean("immersiveMode")
32
33
  ad.setImmersiveMode(immersiveMode ?: false)
33
-
34
- AdRewardExecutor.mRewardedAd = ad
35
- AdRewardExecutor.mRewardedAd.fullScreenContentCallback = FullscreenPluginCallback(
34
+ ad.fullScreenContentCallback = FullscreenPluginCallback(
36
35
  RewardAdPluginEvents, notifyListenersFunction)
37
36
 
37
+ ad.setOnPaidEventListener { adValue ->
38
+ val responseInfo = ad.responseInfo
39
+ val networkName = responseInfo?.mediationAdapterClassName ?: ""
40
+ val impressionId = responseInfo?.responseId ?: ""
41
+ val revenueData = AdMobRevenueData(adValue, ad.adUnitId, networkName, impressionId)
42
+ notifyListenersFunction.accept(RewardAdPluginEvents.AdImpression, revenueData)
43
+ }
44
+
38
45
  if(adOptions.ssvInfo.hasInfo){
39
46
  val ssvOptions = ServerSideVerificationOptions.Builder()
40
47
  adOptions.ssvInfo.customData?.let {
@@ -44,9 +51,12 @@ object RewardedAdCallbackAndListeners {
44
51
  adOptions.ssvInfo.userId?.let {
45
52
  ssvOptions.setUserId(it)
46
53
  }
47
- AdRewardExecutor.mRewardedAd.setServerSideVerificationOptions(ssvOptions.build())
54
+ ad.setServerSideVerificationOptions(ssvOptions.build())
48
55
  }
49
56
 
57
+ AdRewardExecutor.preparedAds[ad.adUnitId] = ad
58
+ AdRewardExecutor.lastPreparedAdId = ad.adUnitId
59
+
50
60
  val adInfo = JSObject()
51
61
  adInfo.put("adUnitId", ad.adUnitId)
52
62
  call.resolve(adInfo)
@@ -7,6 +7,7 @@ import com.getcapacitor.JSObject;
7
7
  import com.getcapacitor.PluginCall;
8
8
  import com.getcapacitor.PluginMethod;
9
9
  import com.getcapacitor.community.admob.helpers.AdViewIdHelper;
10
+ import com.getcapacitor.community.admob.helpers.FullscreenPluginCallback;
10
11
  import com.getcapacitor.community.admob.helpers.RequestHelper;
11
12
  import com.getcapacitor.community.admob.models.AdMobPluginError;
12
13
  import com.getcapacitor.community.admob.models.AdOptions;
@@ -14,10 +15,13 @@ import com.getcapacitor.community.admob.models.Executor;
14
15
  import com.google.android.gms.ads.AdRequest;
15
16
  import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd;
16
17
  import com.google.android.gms.common.util.BiConsumer;
18
+ import java.util.LinkedHashMap;
19
+ import java.util.Map;
17
20
 
18
21
  public class AdRewardInterstitialExecutor extends Executor {
19
22
 
20
- public static RewardedInterstitialAd mRewardedInterstitialAd;
23
+ public static final Map<String, RewardedInterstitialAd> preparedAds = new LinkedHashMap<>();
24
+ public static String lastPreparedAdId;
21
25
 
22
26
  public AdRewardInterstitialExecutor(
23
27
  Supplier<Context> contextSupplier,
@@ -56,7 +60,11 @@ public class AdRewardInterstitialExecutor extends Executor {
56
60
 
57
61
  @PluginMethod
58
62
  public void showRewardInterstitialAd(final PluginCall call, BiConsumer<String, JSObject> notifyListenersFunction) {
59
- if (mRewardedInterstitialAd == null) {
63
+ String requestedAdId = call.getString("adId");
64
+ String adId = requestedAdId != null ? requestedAdId : lastPreparedAdId;
65
+ RewardedInterstitialAd ad = adId != null ? preparedAds.get(adId) : null;
66
+
67
+ if (ad == null) {
60
68
  String errorMessage = "No Reward Interstitial Video Ad can be shown. It was not prepared or maybe it failed to be prepared.";
61
69
  call.reject(errorMessage);
62
70
  AdMobPluginError errorObject = new AdMobPluginError(-1, errorMessage);
@@ -68,7 +76,16 @@ public class AdRewardInterstitialExecutor extends Executor {
68
76
  activitySupplier
69
77
  .get()
70
78
  .runOnUiThread(() -> {
71
- mRewardedInterstitialAd.show(
79
+ ad.setFullScreenContentCallback(
80
+ new FullscreenPluginCallback(RewardInterstitialAdPluginEvents.INSTANCE, notifyListenersFunction, () -> {
81
+ preparedAds.remove(adId);
82
+ if (adId != null && adId.equals(lastPreparedAdId)) {
83
+ lastPreparedAdId = null;
84
+ for (String remainingAdId : preparedAds.keySet()) lastPreparedAdId = remainingAdId;
85
+ }
86
+ })
87
+ );
88
+ ad.show(
72
89
  activitySupplier.get(),
73
90
  RewardedInterstitialAdCallbackAndListeners.INSTANCE.getOnUserEarnedRewardListener(call, notifyListenersFunction)
74
91
  );
@@ -9,4 +9,5 @@ object RewardInterstitialAdPluginEvents: LoadPluginEventNames {
9
9
  override val Showed = "onRewardedInterstitialAdShowed"
10
10
  override val FailedToShow = "onRewardedInterstitialAdFailedToShow"
11
11
  override val Dismissed = "onRewardedInterstitialAdDismissed"
12
+ const val AdImpression = "onRewardedInterstitialAdImpression"
12
13
  }