@capacitor-community/admob 8.1.0 → 8.2.0-beta.pr454.sha49386d40323a

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 (97) hide show
  1. package/CapacitorCommunityAdmob.podspec +1 -1
  2. package/Package.swift +1 -1
  3. package/README.md +129 -323
  4. package/android/build.gradle +1 -1
  5. package/android/src/main/java/com/getcapacitor/community/admob/AdMob.java +86 -3
  6. package/android/src/main/java/com/getcapacitor/community/admob/banner/BannerExecutor.java +261 -141
  7. package/android/src/main/java/com/getcapacitor/community/admob/helpers/FullscreenPluginCallback.kt +5 -1
  8. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/AdInterstitialExecutor.java +27 -31
  9. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdCallbackAndListeners.kt +1 -1
  10. package/android/src/main/java/com/getcapacitor/community/admob/models/LoadPluginEventNames.kt +2 -1
  11. package/android/src/main/java/com/getcapacitor/community/admob/nativeads/NativeAdExecutor.kt +378 -0
  12. package/android/src/main/java/com/getcapacitor/community/admob/nativeads/NativeAdFeedSessions.kt +35 -0
  13. package/android/src/main/java/com/getcapacitor/community/admob/nativeads/NativeAdPlacementValue.kt +44 -0
  14. package/android/src/main/java/com/getcapacitor/community/admob/nativeads/NativeAdPluginEvents.kt +11 -0
  15. package/android/src/main/java/com/getcapacitor/community/admob/nativeads/PluginNativeAdView.kt +187 -0
  16. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/AdRewardExecutor.java +29 -33
  17. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardAdPluginEvents.kt +2 -1
  18. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardedAdCallbackAndListeners.kt +1 -1
  19. package/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/AdRewardInterstitialExecutor.java +29 -37
  20. package/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardedInterstitialAdCallbackAndListeners.kt +1 -1
  21. package/dist/docs.json +33 -3
  22. package/dist/esm/index.d.ts +1 -0
  23. package/dist/esm/index.js +5 -1
  24. package/dist/esm/index.js.map +1 -1
  25. package/dist/esm/interstitial/interstitial-definitions.interface.d.ts +3 -0
  26. package/dist/esm/native-ads/index.d.ts +6 -0
  27. package/dist/esm/native-ads/index.js +4 -0
  28. package/dist/esm/native-ads/index.js.map +1 -0
  29. package/dist/esm/native-ads/native-ad-definitions.interface.d.ts +14 -0
  30. package/dist/esm/native-ads/native-ad-definitions.interface.js +2 -0
  31. package/dist/esm/native-ads/native-ad-definitions.interface.js.map +1 -0
  32. package/dist/esm/native-ads/native-ad-element.d.ts +9 -0
  33. package/dist/esm/native-ads/native-ad-element.js +53 -0
  34. package/dist/esm/native-ads/native-ad-element.js.map +1 -0
  35. package/dist/esm/native-ads/native-ad-event.interface.d.ts +5 -0
  36. package/dist/esm/native-ads/native-ad-event.interface.js +2 -0
  37. package/dist/esm/native-ads/native-ad-event.interface.js.map +1 -0
  38. package/dist/esm/native-ads/native-ad-feed.d.ts +72 -0
  39. package/dist/esm/native-ads/native-ad-feed.js +568 -0
  40. package/dist/esm/native-ads/native-ad-feed.js.map +1 -0
  41. package/dist/esm/native-ads/native-ad-geometry.d.ts +8 -0
  42. package/dist/esm/native-ads/native-ad-geometry.js +91 -0
  43. package/dist/esm/native-ads/native-ad-geometry.js.map +1 -0
  44. package/dist/esm/native-ads/native-ad-options.interface.d.ts +36 -0
  45. package/dist/esm/native-ads/native-ad-options.interface.js +2 -0
  46. package/dist/esm/native-ads/native-ad-options.interface.js.map +1 -0
  47. package/dist/esm/native-ads/native-ad-placement.interface.d.ts +26 -0
  48. package/dist/esm/native-ads/native-ad-placement.interface.js +2 -0
  49. package/dist/esm/native-ads/native-ad-placement.interface.js.map +1 -0
  50. package/dist/esm/native-ads/native-ad-plugin-events.enum.d.ts +9 -0
  51. package/dist/esm/native-ads/native-ad-plugin-events.enum.js +11 -0
  52. package/dist/esm/native-ads/native-ad-plugin-events.enum.js.map +1 -0
  53. package/dist/esm/native-ads/native-ad-style.interface.d.ts +30 -0
  54. package/dist/esm/native-ads/native-ad-style.interface.js +2 -0
  55. package/dist/esm/native-ads/native-ad-style.interface.js.map +1 -0
  56. package/dist/esm/native-ads/native-ad-template.enum.d.ts +11 -0
  57. package/dist/esm/native-ads/native-ad-template.enum.js +13 -0
  58. package/dist/esm/native-ads/native-ad-template.enum.js.map +1 -0
  59. package/dist/esm/reward/reward-ad-plugin-events.enum.d.ts +4 -0
  60. package/dist/esm/reward/reward-ad-plugin-events.enum.js +4 -0
  61. package/dist/esm/reward/reward-ad-plugin-events.enum.js.map +1 -1
  62. package/dist/esm/reward/reward-definitions.interface.d.ts +8 -0
  63. package/dist/esm/reward-interstitial/reward-interstitial-definitions.interface.d.ts +3 -0
  64. package/dist/esm/web.d.ts +9 -1
  65. package/dist/esm/web.js +15 -0
  66. package/dist/esm/web.js.map +1 -1
  67. package/dist/plugin.cjs.js +755 -1
  68. package/dist/plugin.cjs.js.map +1 -1
  69. package/dist/plugin.js +755 -1
  70. package/dist/plugin.js.map +1 -1
  71. package/docs/app-open.md +53 -0
  72. package/docs/banner.md +100 -0
  73. package/docs/configuration.md +30 -0
  74. package/docs/consent.md +80 -0
  75. package/docs/events.md +76 -0
  76. package/docs/interstitial.md +47 -0
  77. package/docs/migration.md +146 -0
  78. package/docs/native-ads.md +161 -0
  79. package/docs/rewarded.md +148 -0
  80. package/docs/testing.md +67 -0
  81. package/ios/Sources/AdMobPlugin/AdMobPlugin.swift +106 -41
  82. package/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdManager.swift +1 -1
  83. package/ios/Sources/AdMobPlugin/Banner/BannerExecutor.swift +1 -1
  84. package/ios/Sources/AdMobPlugin/Interstitial/AdInterstitialExecutor.swift +6 -3
  85. package/ios/Sources/AdMobPlugin/NativeAds/NativeAdExecutor.swift +354 -0
  86. package/ios/Sources/AdMobPlugin/NativeAds/NativeAdFeedSessions.swift +34 -0
  87. package/ios/Sources/AdMobPlugin/NativeAds/NativeAdPlacementValue.swift +50 -0
  88. package/ios/Sources/AdMobPlugin/NativeAds/NativeAdPluginEvents.swift +11 -0
  89. package/ios/Sources/AdMobPlugin/NativeAds/NativeAdScrollTracker.swift +66 -0
  90. package/ios/Sources/AdMobPlugin/NativeAds/NativeAdValues.swift +27 -0
  91. package/ios/Sources/AdMobPlugin/NativeAds/PluginNativeAdView.swift +187 -0
  92. package/ios/Sources/AdMobPlugin/Rewarded/AdRewardExecutor.swift +10 -3
  93. package/ios/Sources/AdMobPlugin/Rewarded/RewardAdPluginEvents.swift +1 -0
  94. package/ios/Sources/AdMobPlugin/RewardedInterstitial/AdRewardInterstitialExecutor.swift +6 -3
  95. package/ios/Tests/AdMobPluginTests/AdMobPluginTests.swift +82 -10
  96. package/ios/Tests/AdMobPluginTests/NativeAdScrollTrackerTests.swift +47 -0
  97. package/package.json +4 -1
@@ -0,0 +1,187 @@
1
+ package com.getcapacitor.community.admob.nativeads
2
+
3
+ import android.content.Context
4
+ import android.graphics.Color
5
+ import android.graphics.drawable.GradientDrawable
6
+ import android.view.Gravity
7
+ import android.view.View
8
+ import android.view.ViewGroup
9
+ import android.widget.Button
10
+ import android.widget.FrameLayout
11
+ import android.widget.ImageView
12
+ import android.widget.LinearLayout
13
+ import android.widget.TextView
14
+ import com.getcapacitor.JSObject
15
+ import com.google.android.gms.ads.nativead.AdChoicesView
16
+ import com.google.android.gms.ads.nativead.MediaView
17
+ import com.google.android.gms.ads.nativead.NativeAd
18
+ import com.google.android.gms.ads.nativead.NativeAdView
19
+ import kotlin.math.max
20
+ import kotlin.math.min
21
+ import kotlin.math.roundToInt
22
+
23
+ /** Builds the plugin-owned layout around the final Next-Gen SDK [NativeAdView]. */
24
+ internal class PluginNativeAdView private constructor(
25
+ private val context: Context,
26
+ nativeAd: NativeAd,
27
+ template: String,
28
+ private val style: JSObject,
29
+ ) {
30
+ private val density = context.resources.displayMetrics.density
31
+ private val view = NativeAdView(context)
32
+
33
+ init {
34
+ view.layoutParams = FrameLayout.LayoutParams(
35
+ ViewGroup.LayoutParams.MATCH_PARENT,
36
+ ViewGroup.LayoutParams.MATCH_PARENT,
37
+ )
38
+ applyBackground()
39
+ bindAssets(nativeAd, template == "small")
40
+ view.setNativeAd(nativeAd)
41
+ }
42
+
43
+ private fun bindAssets(nativeAd: NativeAd, isSmall: Boolean) {
44
+ val content = LinearLayout(context).apply {
45
+ orientation = LinearLayout.VERTICAL
46
+ setPadding(pixels(12), pixels(12), pixels(12), pixels(12))
47
+ }
48
+ view.addView(
49
+ content,
50
+ FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT),
51
+ )
52
+
53
+ if (!isSmall) {
54
+ val media = MediaView(context).apply { minimumHeight = pixels(120) }
55
+ content.addView(media, LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f))
56
+ view.mediaView = media
57
+ }
58
+
59
+ val details = LinearLayout(context).apply {
60
+ orientation = LinearLayout.VERTICAL
61
+ setPadding(0, pixels(if (isSmall) 0 else 8), 0, 0)
62
+ }
63
+ content.addView(
64
+ details,
65
+ LinearLayout.LayoutParams(
66
+ ViewGroup.LayoutParams.MATCH_PARENT,
67
+ if (isSmall) ViewGroup.LayoutParams.MATCH_PARENT else ViewGroup.LayoutParams.WRAP_CONTENT,
68
+ ),
69
+ )
70
+
71
+ addAttribution(details)
72
+ bindTextAssets(details, nativeAd, isSmall)
73
+ bindFooter(details, nativeAd, isSmall)
74
+
75
+ val adChoices = AdChoicesView(context)
76
+ view.addView(adChoices, FrameLayout.LayoutParams(pixels(24), pixels(24), Gravity.TOP or Gravity.END))
77
+ view.adChoicesView = adChoices
78
+ }
79
+
80
+ private fun addAttribution(parent: LinearLayout) {
81
+ val attribution = TextView(context).apply {
82
+ text = "Ad"
83
+ textSize = 10f
84
+ setTextColor(Color.WHITE)
85
+ setBackgroundColor(Color.DKGRAY)
86
+ gravity = Gravity.CENTER
87
+ }
88
+ parent.addView(attribution, LinearLayout.LayoutParams(pixels(28), pixels(20)))
89
+ }
90
+
91
+ private fun bindTextAssets(parent: LinearLayout, nativeAd: NativeAd, isSmall: Boolean) {
92
+ val headline = TextView(context).apply {
93
+ text = nativeAd.headline
94
+ textSize = fontStyle("headlineFontSize", 16f, 12f, 24f)
95
+ setTextColor(colorStyle("headlineColor", Color.BLACK))
96
+ maxLines = 2
97
+ }
98
+ parent.addView(headline)
99
+ view.headlineView = headline
100
+
101
+ val body = TextView(context).apply {
102
+ text = nativeAd.body
103
+ textSize = fontStyle("bodyFontSize", 13f, 10f, 18f)
104
+ setTextColor(colorStyle("bodyColor", Color.DKGRAY))
105
+ maxLines = if (isSmall) 1 else 2
106
+ visibility = if (isSmall || nativeAd.body == null) View.GONE else View.VISIBLE
107
+ }
108
+ parent.addView(body)
109
+ view.bodyView = body
110
+ }
111
+
112
+ private fun bindFooter(parent: LinearLayout, nativeAd: NativeAd, isSmall: Boolean) {
113
+ val footer = LinearLayout(context).apply { gravity = Gravity.CENTER_VERTICAL }
114
+ parent.addView(
115
+ footer,
116
+ LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT),
117
+ )
118
+
119
+ val icon = ImageView(context).apply {
120
+ scaleType = ImageView.ScaleType.CENTER_CROP
121
+ nativeAd.icon?.drawable?.let(::setImageDrawable) ?: run { visibility = View.GONE }
122
+ }
123
+ val iconSize = pixels(if (isSmall) 28 else 32)
124
+ footer.addView(icon, LinearLayout.LayoutParams(iconSize, iconSize))
125
+ view.iconView = icon
126
+
127
+ val advertiser = TextView(context).apply {
128
+ text = nativeAd.advertiser
129
+ textSize = 11f
130
+ maxLines = 1
131
+ visibility = if (nativeAd.advertiser == null) View.GONE else View.VISIBLE
132
+ }
133
+ footer.addView(advertiser, LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f))
134
+ view.advertiserView = advertiser
135
+
136
+ val callToAction = Button(context).apply {
137
+ text = nativeAd.callToAction
138
+ textSize = fontStyle("callToActionFontSize", 13f, 12f, 18f)
139
+ setTextColor(colorStyle("callToActionTextColor", Color.WHITE))
140
+ setBackgroundColor(colorStyle("callToActionBackgroundColor", Color.rgb(33, 150, 243)))
141
+ visibility = if (nativeAd.callToAction == null) View.GONE else View.VISIBLE
142
+ }
143
+ footer.addView(
144
+ callToAction,
145
+ LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, pixels(if (isSmall) 32 else 40)),
146
+ )
147
+ view.callToActionView = callToAction
148
+ }
149
+
150
+ private fun applyBackground() {
151
+ val drawable = GradientDrawable().apply {
152
+ setColor(colorStyle("backgroundColor", Color.WHITE))
153
+ cornerRadius = pixels(floatStyle("cornerRadius", 0f)).toFloat()
154
+ val borderWidth = pixels(floatStyle("borderWidth", 0f))
155
+ if (borderWidth > 0) setStroke(borderWidth, colorStyle("borderColor", Color.TRANSPARENT))
156
+ }
157
+ view.background = drawable
158
+ }
159
+
160
+ private fun pixels(logicalPixels: Number): Int = (logicalPixels.toDouble() * density).roundToInt()
161
+
162
+ private fun colorStyle(key: String, fallback: Int): Int {
163
+ val hex = style.getString(key)?.trim()?.removePrefix("#") ?: return fallback
164
+ val rgba = hex.toLongOrNull(16) ?: return fallback
165
+ return when (hex.length) {
166
+ 6 -> Color.rgb((rgba shr 16).toInt() and 0xff, (rgba shr 8).toInt() and 0xff, rgba.toInt() and 0xff)
167
+ 8 -> Color.argb(
168
+ rgba.toInt() and 0xff,
169
+ (rgba shr 24).toInt() and 0xff,
170
+ (rgba shr 16).toInt() and 0xff,
171
+ (rgba shr 8).toInt() and 0xff,
172
+ )
173
+ else -> fallback
174
+ }
175
+ }
176
+
177
+ private fun floatStyle(key: String, fallback: Float): Float =
178
+ if (style.has(key)) max(0f, style.optDouble(key, fallback.toDouble()).toFloat()) else fallback
179
+
180
+ private fun fontStyle(key: String, fallback: Float, minimum: Float, maximum: Float): Float =
181
+ min(maximum, max(minimum, floatStyle(key, fallback)))
182
+
183
+ companion object {
184
+ fun create(context: Context, nativeAd: NativeAd, template: String, style: JSObject): NativeAdView =
185
+ PluginNativeAdView(context, nativeAd, template, style).view
186
+ }
187
+ }
@@ -36,22 +36,20 @@ public class AdRewardExecutor extends Executor {
36
36
  public void prepareRewardVideoAd(final PluginCall call, BiConsumer<String, JSObject> notifyListenersFunction) {
37
37
  final AdOptions adOptions = AdOptions.getFactory().createRewardVideoOptions(call);
38
38
 
39
- activitySupplier
40
- .get()
41
- .runOnUiThread(() -> {
42
- try {
43
- final AdRequest adRequest = RequestHelper.createRequest(adOptions);
44
- final String id = AdViewIdHelper.getFinalAdId(adOptions, adRequest, logTag, contextSupplier.get());
45
- RewardedAd.load(
46
- contextSupplier.get(),
47
- id,
48
- adRequest,
49
- RewardedAdCallbackAndListeners.INSTANCE.getRewardedAdLoadCallback(call, notifyListenersFunction, adOptions)
50
- );
51
- } catch (Exception ex) {
52
- call.reject(ex.getLocalizedMessage(), ex);
53
- }
54
- });
39
+ activitySupplier.get().runOnUiThread(() -> {
40
+ try {
41
+ final AdRequest adRequest = RequestHelper.createRequest(adOptions);
42
+ final String id = AdViewIdHelper.getFinalAdId(adOptions, adRequest, logTag, contextSupplier.get());
43
+ RewardedAd.load(
44
+ contextSupplier.get(),
45
+ id,
46
+ adRequest,
47
+ RewardedAdCallbackAndListeners.INSTANCE.getRewardedAdLoadCallback(call, notifyListenersFunction, adOptions)
48
+ );
49
+ } catch (Exception ex) {
50
+ call.reject(ex.getLocalizedMessage(), ex);
51
+ }
52
+ });
55
53
  }
56
54
 
57
55
  @PluginMethod
@@ -69,23 +67,21 @@ public class AdRewardExecutor extends Executor {
69
67
  }
70
68
 
71
69
  try {
72
- activitySupplier
73
- .get()
74
- .runOnUiThread(() -> {
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(
85
- activitySupplier.get(),
86
- RewardedAdCallbackAndListeners.INSTANCE.getOnUserEarnedRewardListener(call, notifyListenersFunction)
87
- );
88
- });
70
+ activitySupplier.get().runOnUiThread(() -> {
71
+ ad.setFullScreenContentCallback(
72
+ new FullscreenPluginCallback(RewardAdPluginEvents.INSTANCE, notifyListenersFunction, () -> {
73
+ preparedAds.remove(adId);
74
+ if (adId != null && adId.equals(lastPreparedAdId)) {
75
+ lastPreparedAdId = null;
76
+ for (String remainingAdId : preparedAds.keySet()) lastPreparedAdId = remainingAdId;
77
+ }
78
+ })
79
+ );
80
+ ad.show(
81
+ activitySupplier.get(),
82
+ RewardedAdCallbackAndListeners.INSTANCE.getOnUserEarnedRewardListener(call, notifyListenersFunction)
83
+ );
84
+ });
89
85
  } catch (Exception ex) {
90
86
  call.reject(ex.getLocalizedMessage(), ex);
91
87
  }
@@ -3,6 +3,7 @@ package com.getcapacitor.community.admob.rewarded
3
3
  import com.getcapacitor.community.admob.models.LoadPluginEventNames
4
4
 
5
5
  object RewardAdPluginEvents: LoadPluginEventNames {
6
+ override val adClicked = "onRewardedVideoAdClicked"
6
7
  const val Loaded = "onRewardedVideoAdLoaded"
7
8
  const val FailedToLoad = "onRewardedVideoAdFailedToLoad"
8
9
  const val Rewarded = "onRewardedVideoAdReward"
@@ -10,4 +11,4 @@ object RewardAdPluginEvents: LoadPluginEventNames {
10
11
  override val FailedToShow = "onRewardedVideoAdFailedToShow"
11
12
  override val Dismissed = "onRewardedVideoAdDismissed"
12
13
  const val AdImpression = "onRewardedVideoAdImpression"
13
- }
14
+ }
@@ -68,7 +68,7 @@ object RewardedAdCallbackAndListeners {
68
68
  val adMobError = AdMobPluginError(adError)
69
69
 
70
70
  notifyListenersFunction.accept(RewardAdPluginEvents.FailedToLoad, adMobError)
71
- call.reject(adError.message)
71
+ call.reject(adError.message, adError.code.toString())
72
72
  }
73
73
  }
74
74
  }
@@ -36,26 +36,20 @@ public class AdRewardInterstitialExecutor extends Executor {
36
36
  public void prepareRewardInterstitialAd(final PluginCall call, BiConsumer<String, JSObject> notifyListenersFunction) {
37
37
  final AdOptions adOptions = AdOptions.getFactory().createRewardInterstitialOptions(call);
38
38
 
39
- activitySupplier
40
- .get()
41
- .runOnUiThread(() -> {
42
- try {
43
- final AdRequest adRequest = RequestHelper.createRequest(adOptions);
44
- final String id = AdViewIdHelper.getFinalAdId(adOptions, adRequest, logTag, contextSupplier.get());
45
- RewardedInterstitialAd.load(
46
- contextSupplier.get(),
47
- id,
48
- adRequest,
49
- RewardedInterstitialAdCallbackAndListeners.INSTANCE.getRewardedAdLoadCallback(
50
- call,
51
- notifyListenersFunction,
52
- adOptions
53
- )
54
- );
55
- } catch (Exception ex) {
56
- call.reject(ex.getLocalizedMessage(), ex);
57
- }
58
- });
39
+ activitySupplier.get().runOnUiThread(() -> {
40
+ try {
41
+ final AdRequest adRequest = RequestHelper.createRequest(adOptions);
42
+ final String id = AdViewIdHelper.getFinalAdId(adOptions, adRequest, logTag, contextSupplier.get());
43
+ RewardedInterstitialAd.load(
44
+ contextSupplier.get(),
45
+ id,
46
+ adRequest,
47
+ RewardedInterstitialAdCallbackAndListeners.INSTANCE.getRewardedAdLoadCallback(call, notifyListenersFunction, adOptions)
48
+ );
49
+ } catch (Exception ex) {
50
+ call.reject(ex.getLocalizedMessage(), ex);
51
+ }
52
+ });
59
53
  }
60
54
 
61
55
  @PluginMethod
@@ -73,23 +67,21 @@ public class AdRewardInterstitialExecutor extends Executor {
73
67
  }
74
68
 
75
69
  try {
76
- activitySupplier
77
- .get()
78
- .runOnUiThread(() -> {
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(
89
- activitySupplier.get(),
90
- RewardedInterstitialAdCallbackAndListeners.INSTANCE.getOnUserEarnedRewardListener(call, notifyListenersFunction)
91
- );
92
- });
70
+ activitySupplier.get().runOnUiThread(() -> {
71
+ ad.setFullScreenContentCallback(
72
+ new FullscreenPluginCallback(RewardInterstitialAdPluginEvents.INSTANCE, notifyListenersFunction, () -> {
73
+ preparedAds.remove(adId);
74
+ if (adId != null && adId.equals(lastPreparedAdId)) {
75
+ lastPreparedAdId = null;
76
+ for (String remainingAdId : preparedAds.keySet()) lastPreparedAdId = remainingAdId;
77
+ }
78
+ })
79
+ );
80
+ ad.show(
81
+ activitySupplier.get(),
82
+ RewardedInterstitialAdCallbackAndListeners.INSTANCE.getOnUserEarnedRewardListener(call, notifyListenersFunction)
83
+ );
84
+ });
93
85
  } catch (Exception ex) {
94
86
  call.reject(ex.getLocalizedMessage(), ex);
95
87
  }
@@ -53,7 +53,7 @@ object RewardedInterstitialAdCallbackAndListeners {
53
53
  val adMobError = AdMobPluginError(adError)
54
54
 
55
55
  notifyListenersFunction.accept(RewardInterstitialAdPluginEvents.FailedToLoad, adMobError)
56
- call.reject(adError.message)
56
+ call.reject(adError.message, adError.code.toString())
57
57
  }
58
58
  }
59
59
  }
package/dist/docs.json CHANGED
@@ -833,7 +833,7 @@
833
833
  "text": "1.1.2"
834
834
  }
835
835
  ],
836
- "docs": "Loads an interstitial ad and returns the loaded ad unit ID.",
836
+ "docs": "Loads an interstitial ad and returns the loaded ad unit ID.\n\nSDK load failures reject with the native error message and a string `code`.\nCodes are platform-specific; FailedToLoad events expose the same code as a number.",
837
837
  "complexTypes": [
838
838
  "AdLoadInfo",
839
839
  "AdOptions"
@@ -1044,7 +1044,7 @@
1044
1044
  "text": "1.1.2"
1045
1045
  }
1046
1046
  ],
1047
- "docs": "Loads a rewarded ad and returns the loaded ad unit ID.",
1047
+ "docs": "Loads a rewarded ad and returns the loaded ad unit ID.\n\nSDK load failures reject with the native error message and a string `code`.\nCodes are platform-specific; FailedToLoad events expose the same code as a number.",
1048
1048
  "complexTypes": [
1049
1049
  "AdLoadInfo",
1050
1050
  "RewardAdOptions"
@@ -1083,6 +1083,30 @@
1083
1083
  ],
1084
1084
  "slug": "showrewardvideoad"
1085
1085
  },
1086
+ {
1087
+ "name": "addListener",
1088
+ "signature": "(eventName: RewardAdPluginEvents.adClicked, listenerFunc: () => void) => Promise<PluginListenerHandle>",
1089
+ "parameters": [
1090
+ {
1091
+ "name": "eventName",
1092
+ "docs": "",
1093
+ "type": "RewardAdPluginEvents.adClicked"
1094
+ },
1095
+ {
1096
+ "name": "listenerFunc",
1097
+ "docs": "",
1098
+ "type": "() => void"
1099
+ }
1100
+ ],
1101
+ "returns": "Promise<PluginListenerHandle>",
1102
+ "tags": [],
1103
+ "docs": "Listens for clicks recorded by the rewarded ad SDK, including after a reward is earned.\nA click does not indicate that the user earned a reward.",
1104
+ "complexTypes": [
1105
+ "PluginListenerHandle",
1106
+ "RewardAdPluginEvents"
1107
+ ],
1108
+ "slug": "addlistenerrewardadplugineventsadclicked-"
1109
+ },
1086
1110
  {
1087
1111
  "name": "addListener",
1088
1112
  "signature": "(eventName: RewardAdPluginEvents.FailedToLoad, listenerFunc: (error: AdMobError) => void) => Promise<PluginListenerHandle>",
@@ -1281,7 +1305,7 @@
1281
1305
  "text": "1.1.2"
1282
1306
  }
1283
1307
  ],
1284
- "docs": "Loads a rewarded interstitial ad and returns the loaded ad unit ID.",
1308
+ "docs": "Loads a rewarded interstitial ad and returns the loaded ad unit ID.\n\nSDK load failures reject with the native error message and a string `code`.\nCodes are platform-specific; FailedToLoad events expose the same code as a number.",
1285
1309
  "complexTypes": [
1286
1310
  "AdLoadInfo",
1287
1311
  "RewardInterstitialAdOptions"
@@ -2856,6 +2880,12 @@
2856
2880
  "name": "RewardAdPluginEvents",
2857
2881
  "slug": "rewardadpluginevents",
2858
2882
  "members": [
2883
+ {
2884
+ "name": "adClicked",
2885
+ "value": "'onRewardedVideoAdClicked'",
2886
+ "tags": [],
2887
+ "docs": "Emits when the SDK records a click on a rewarded ad."
2888
+ },
2859
2889
  {
2860
2890
  "name": "Loaded",
2861
2891
  "value": "'onRewardedVideoAdLoaded'",
@@ -8,4 +8,5 @@ export * from './reward/index';
8
8
  export * from './consent/index';
9
9
  export * from './shared/index';
10
10
  export * from './app-open/index';
11
+ export * from './native-ads/index';
11
12
  export { AdMob };
package/dist/esm/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  import { registerPlugin } from '@capacitor/core';
2
- const AdMob = registerPlugin('AdMob', {
2
+ import { configureNativeAdBridge } from './native-ads/native-ad-feed';
3
+ const nativeAdBridge = registerPlugin('AdMob', {
3
4
  web: () => import('./web').then((m) => new m.AdMobWeb()),
4
5
  });
6
+ const AdMob = nativeAdBridge;
7
+ configureNativeAdBridge(nativeAdBridge);
5
8
  export * from './definitions';
6
9
  export * from './banner/index';
7
10
  export * from './interstitial/index';
@@ -10,5 +13,6 @@ export * from './reward/index';
10
13
  export * from './consent/index';
11
14
  export * from './shared/index';
12
15
  export * from './app-open/index';
16
+ export * from './native-ads/index';
13
17
  export { AdMob };
14
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,KAAK,GAAG,cAAc,CAAc,OAAO,EAAE;IACjD,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;CACzD,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,MAAM,cAAc,GAAG,cAAc,CAAoC,OAAO,EAAE;IAChF,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAuC,CAAC;CAC9F,CAAC,CAAC;AACH,MAAM,KAAK,GAAgB,cAAc,CAAC;AAE1C,uBAAuB,CAAC,cAAc,CAAC,CAAC;AAExC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,CAAC"}
@@ -7,6 +7,9 @@ export interface InterstitialDefinitions {
7
7
  /**
8
8
  * Loads an interstitial ad and returns the loaded ad unit ID.
9
9
  *
10
+ * SDK load failures reject with the native error message and a string `code`.
11
+ * Codes are platform-specific; FailedToLoad events expose the same code as a number.
12
+ *
10
13
  * @group Interstitial
11
14
  * @param options AdOptions
12
15
  * @since 1.1.2
@@ -0,0 +1,6 @@
1
+ export type { NativeAdErrorEvent, NativeAdEvent, NativeAdRevenueEvent } from './native-ad-event.interface';
2
+ export { NativeAdFeed } from './native-ad-feed';
3
+ export type { NativeAdFeedOptions } from './native-ad-options.interface';
4
+ export * from './native-ad-plugin-events.enum';
5
+ export type { NativeAdStyle } from './native-ad-style.interface';
6
+ export * from './native-ad-template.enum';
@@ -0,0 +1,4 @@
1
+ export { NativeAdFeed } from './native-ad-feed';
2
+ export * from './native-ad-plugin-events.enum';
3
+ export * from './native-ad-template.enum';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/native-ads/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,cAAc,gCAAgC,CAAC;AAE/C,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { PluginListenerHandle } from '@capacitor/core';
2
+ import type { NativeAdEvent, NativeAdErrorEvent, NativeAdRevenueEvent } from './native-ad-event.interface';
3
+ import type { NativeAdCommandIdentity, NativeAdFeedSession, NativeAdLoadOptions } from './native-ad-options.interface';
4
+ import type { NativeAdPlacementBatch } from './native-ad-placement.interface';
5
+ import type { NativeAdPluginEvents } from './native-ad-plugin-events.enum';
6
+ /** Low-level native bridge used by {@link NativeAdFeed}. */
7
+ export interface NativeAdDefinitions {
8
+ startNativeAdFeed(options: NativeAdFeedSession): Promise<void>;
9
+ destroyNativeAdFeed(options: NativeAdFeedSession): Promise<void>;
10
+ loadNativeAd(options: NativeAdLoadOptions): Promise<void>;
11
+ updateNativeAdPlacements(options: NativeAdPlacementBatch): Promise<void>;
12
+ removeNativeAd(options: NativeAdCommandIdentity): Promise<void>;
13
+ addListener(eventName: NativeAdPluginEvents, listenerFunc: (info: (NativeAdEvent | NativeAdErrorEvent | NativeAdRevenueEvent) & NativeAdFeedSession) => void): Promise<PluginListenerHandle>;
14
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=native-ad-definitions.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-ad-definitions.interface.js","sourceRoot":"","sources":["../../../src/native-ads/native-ad-definitions.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ export declare const NATIVE_AD_ELEMENT_NAME = "capacitor-admob-native";
2
+ interface NativeAdElementFeed {
3
+ attach(slotKey: string, element: HTMLElement): void;
4
+ detach(element: HTMLElement): void;
5
+ }
6
+ type NativeAdFeedLookup = (feedId: string) => NativeAdElementFeed | undefined;
7
+ export declare const defineNativeAdElement: (findFeed: NativeAdFeedLookup) => void;
8
+ export declare const connectNativeAdElements: () => void;
9
+ export {};
@@ -0,0 +1,53 @@
1
+ export const NATIVE_AD_ELEMENT_NAME = 'capacitor-admob-native';
2
+ export const defineNativeAdElement = (findFeed) => {
3
+ const runtime = globalThis;
4
+ runtime.__capacitorAdMobNativeFeedLookup = findFeed;
5
+ if (typeof customElements === 'undefined' || customElements.get(NATIVE_AD_ELEMENT_NAME)) {
6
+ return;
7
+ }
8
+ customElements.define(NATIVE_AD_ELEMENT_NAME, class extends HTMLElement {
9
+ static get observedAttributes() {
10
+ return ['feed-id', 'slot-key'];
11
+ }
12
+ connectedCallback() {
13
+ this.connectToFeed();
14
+ }
15
+ disconnectedCallback() {
16
+ this.disconnectFromFeed();
17
+ }
18
+ attributeChangedCallback() {
19
+ if (!this.isConnected) {
20
+ return;
21
+ }
22
+ this.disconnectFromFeed();
23
+ this.connectToFeed();
24
+ }
25
+ connectToFeed() {
26
+ var _a, _b, _c;
27
+ const feedId = (_a = this.getAttribute('feed-id')) === null || _a === void 0 ? void 0 : _a.trim();
28
+ const slotKey = (_b = this.getAttribute('slot-key')) === null || _b === void 0 ? void 0 : _b.trim();
29
+ const feed = feedId ? (_c = runtime.__capacitorAdMobNativeFeedLookup) === null || _c === void 0 ? void 0 : _c.call(runtime, feedId) : undefined;
30
+ if (!feed || !slotKey) {
31
+ return;
32
+ }
33
+ try {
34
+ feed.attach(slotKey, this);
35
+ this.attachedFeed = feed;
36
+ }
37
+ catch (error) {
38
+ this.dispatchEvent(new CustomEvent('nativeAdError', { bubbles: true, detail: error }));
39
+ }
40
+ }
41
+ disconnectFromFeed() {
42
+ var _a;
43
+ (_a = this.attachedFeed) === null || _a === void 0 ? void 0 : _a.detach(this);
44
+ this.attachedFeed = undefined;
45
+ }
46
+ });
47
+ };
48
+ export const connectNativeAdElements = () => {
49
+ document
50
+ .querySelectorAll(NATIVE_AD_ELEMENT_NAME)
51
+ .forEach((element) => { var _a, _b; return (_b = (_a = element).connectToFeed) === null || _b === void 0 ? void 0 : _b.call(_a); });
52
+ };
53
+ //# sourceMappingURL=native-ad-element.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-ad-element.js","sourceRoot":"","sources":["../../../src/native-ads/native-ad-element.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AAW/D,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,QAA4B,EAAQ,EAAE;IAC1E,MAAM,OAAO,GAAG,UAAoC,CAAC;IACrD,OAAO,CAAC,gCAAgC,GAAG,QAAQ,CAAC;IACpD,IAAI,OAAO,cAAc,KAAK,WAAW,IAAI,cAAc,CAAC,GAAG,CAAC,sBAAsB,CAAC,EAAE,CAAC;QACxF,OAAO;IACT,CAAC;IAED,cAAc,CAAC,MAAM,CACnB,sBAAsB,EACtB,KAAM,SAAQ,WAAW;QAGvB,MAAM,KAAK,kBAAkB;YAC3B,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACjC,CAAC;QAED,iBAAiB;YACf,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,CAAC;QAED,oBAAoB;YAClB,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC5B,CAAC;QAED,wBAAwB;YACtB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACtB,OAAO;YACT,CAAC;YACD,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC1B,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,CAAC;QAED,aAAa;;YACX,MAAM,MAAM,GAAG,MAAA,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,0CAAE,IAAI,EAAE,CAAC;YACpD,MAAM,OAAO,GAAG,MAAA,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,0CAAE,IAAI,EAAE,CAAC;YACtD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,MAAA,OAAO,CAAC,gCAAgC,wDAAG,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACrF,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACtB,OAAO;YACT,CAAC;YACD,IAAI,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBAC3B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YAC3B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,eAAe,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YACzF,CAAC;QACH,CAAC;QAEO,kBAAkB;;YACxB,MAAA,IAAI,CAAC,YAAY,0CAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;QAChC,CAAC;KACF,CACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAS,EAAE;IAChD,QAAQ;SACL,gBAAgB,CAAc,sBAAsB,CAAC;SACrD,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,eAAC,OAAA,MAAA,MAAC,OAA2B,EAAC,aAAa,kDAAI,CAAA,EAAA,CAAC,CAAC;AAC1E,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { AdMobError, AdMobRevenueData } from '../shared';
2
+ import type { NativeAdIdentity } from './native-ad-options.interface';
3
+ export type NativeAdErrorEvent = NativeAdIdentity & AdMobError;
4
+ export type NativeAdRevenueEvent = NativeAdIdentity & AdMobRevenueData;
5
+ export type NativeAdEvent = NativeAdIdentity;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=native-ad-event.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-ad-event.interface.js","sourceRoot":"","sources":["../../../src/native-ads/native-ad-event.interface.ts"],"names":[],"mappings":""}