@capgo/capacitor-admob 8.1.21 → 8.2.1

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 (44) hide show
  1. package/CapgoCapacitorAdmob.podspec +1 -0
  2. package/Package.swift +4 -2
  3. package/README.md +327 -8
  4. package/android/build.gradle +3 -2
  5. package/android/src/main/kotlin/admob/plus/capacitor/AdMobPlusPlugin.kt +121 -0
  6. package/android/src/main/kotlin/admob/plus/capacitor/ConsentHelper.kt +140 -0
  7. package/android/src/main/kotlin/admob/plus/capacitor/Generated.kt +7 -0
  8. package/android/src/main/kotlin/admob/plus/capacitor/feed/FeedAdManager.kt +512 -0
  9. package/android/src/main/kotlin/admob/plus/core/Ad.kt +2 -4
  10. package/android/src/main/kotlin/admob/plus/core/Helper.kt +18 -1
  11. package/dist/docs.json +543 -5
  12. package/dist/esm/definitions.d.ts +284 -1
  13. package/dist/esm/definitions.js +55 -0
  14. package/dist/esm/definitions.js.map +1 -1
  15. package/dist/esm/events.d.ts +127 -0
  16. package/dist/esm/events.js +50 -0
  17. package/dist/esm/events.js.map +1 -0
  18. package/dist/esm/feed-ad.d.ts +32 -0
  19. package/dist/esm/feed-ad.js +133 -0
  20. package/dist/esm/feed-ad.js.map +1 -0
  21. package/dist/esm/index.d.ts +4 -2
  22. package/dist/esm/index.js +4 -32
  23. package/dist/esm/index.js.map +1 -1
  24. package/dist/esm/plugin-instance.d.ts +3 -0
  25. package/dist/esm/plugin-instance.js +35 -0
  26. package/dist/esm/plugin-instance.js.map +1 -0
  27. package/dist/esm/web.d.ts +11 -1
  28. package/dist/esm/web.js +40 -0
  29. package/dist/esm/web.js.map +1 -1
  30. package/dist/plugin.cjs.js +313 -31
  31. package/dist/plugin.cjs.js.map +1 -1
  32. package/dist/plugin.js +313 -31
  33. package/dist/plugin.js.map +1 -1
  34. package/ios/Sources/AdmobPlusPlugin/AdmobPlusPlugin.swift +131 -1
  35. package/ios/Sources/AdmobPlusPlugin/BannerAd.swift +6 -9
  36. package/ios/Sources/AdmobPlusPlugin/ConsentExecutor.swift +100 -0
  37. package/ios/Sources/AdmobPlusPlugin/FeedAdManager.swift +435 -0
  38. package/ios/Sources/AdmobPlusPlugin/Generated.swift +7 -0
  39. package/ios/Sources/AdmobPlusPlugin/Helper.swift +29 -0
  40. package/ios/Sources/AdmobPlusPlugin/InterstitialAd.swift +7 -13
  41. package/ios/Sources/AdmobPlusPlugin/RewardedAd.swift +13 -20
  42. package/ios/Sources/AdmobPlusPlugin/RewardedInterstitialAd.swift +13 -20
  43. package/ios/Tests/AdmobPlusPluginTests/AdmobPlusPluginTests.swift +3 -6
  44. package/package.json +2 -2
@@ -14,5 +14,6 @@ Pod::Spec.new do |s|
14
14
  s.ios.deployment_target = '15.0'
15
15
  s.dependency 'Capacitor'
16
16
  s.dependency 'Google-Mobile-Ads-SDK', '~> 13.1'
17
+ s.dependency 'GoogleUserMessagingPlatform', '~> 3.1'
17
18
  s.swift_version = '5.1'
18
19
  end
package/Package.swift CHANGED
@@ -11,7 +11,8 @@ let package = Package(
11
11
  ],
12
12
  dependencies: [
13
13
  .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0"),
14
- .package(url: "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", from: "13.11.0")
14
+ .package(url: "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", from: "13.11.0"),
15
+ .package(url: "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git", from: "3.1.0")
15
16
  ],
16
17
  targets: [
17
18
  .target(
@@ -19,7 +20,8 @@ let package = Package(
19
20
  dependencies: [
20
21
  .product(name: "Capacitor", package: "capacitor-swift-pm"),
21
22
  .product(name: "Cordova", package: "capacitor-swift-pm"),
22
- .product(name: "GoogleMobileAds", package: "swift-package-manager-google-mobile-ads")
23
+ .product(name: "GoogleMobileAds", package: "swift-package-manager-google-mobile-ads"),
24
+ .product(name: "GoogleUserMessagingPlatform", package: "swift-package-manager-google-user-messaging-platform")
23
25
  ],
24
26
  path: "ios/Sources/AdmobPlusPlugin"),
25
27
  .testTarget(
package/README.md CHANGED
@@ -5,7 +5,7 @@ Show Google AdMob ads in your Capacitor app on iOS and Android: banner, intersti
5
5
  <a href="https://capgo.app/?ref=plugin_admob"><img src="https://capgo.app/readme-banner.svg?repo=Cap-go/capacitor-admob" alt="Capgo - Instant updates for Capacitor" /></a>
6
6
 
7
7
  <div align="center">
8
- <p><b>Capgo</b>: open-source live updates for Ionic and Capacitor apps. Ship OTA fixes and features instantly, without waiting for app store review.</p>
8
+ <p><b>Capgo</b>: push fixes to your Capacitor users in minutes, build signed iOS and Android apps without a Mac, and roll back in one click.</p>
9
9
  <h2><a href="https://capgo.app/register/?ref=plugin_admob">➡️ Get started for free</a></h2>
10
10
  <p>14-day unlimited free trial. No credit card required</p>
11
11
  <p><a href="https://capgo.app/consulting/?ref=plugin_admob">Missing a feature? We'll build the plugin for you 💪</a></p>
@@ -64,6 +64,29 @@ npm install @capgo/capacitor-admob
64
64
  npx cap sync
65
65
  ```
66
66
 
67
+ ## Consent (UMP)
68
+
69
+ For apps serving users in the EEA/UK, request consent with Google's User Messaging Platform (UMP) before loading ads. Configure GDPR messages in your AdMob account first.
70
+
71
+ ```typescript
72
+ import { AdMob, AdmobConsentStatus } from '@capgo/capacitor-admob';
73
+
74
+ await AdMob.start();
75
+
76
+ let consentInfo = await AdMob.requestConsentInfo();
77
+ if (consentInfo.isConsentFormAvailable && consentInfo.status === AdmobConsentStatus.REQUIRED) {
78
+ consentInfo = await AdMob.showConsentForm();
79
+ }
80
+
81
+ if (consentInfo.canRequestAds) {
82
+ // Load ads only after consent allows ad requests.
83
+ }
84
+ ```
85
+
86
+ To let users manage privacy choices later, call `showPrivacyOptionsForm()` from a settings screen when `privacyOptionsRequirementStatus` is `REQUIRED`.
87
+
88
+ For local testing on a real device, pass `debugGeography` and `testDeviceIdentifiers` to `requestConsentInfo()`.
89
+
67
90
  ## API
68
91
 
69
92
  <docgen-index>
@@ -71,14 +94,23 @@ npx cap sync
71
94
  * [`start()`](#start)
72
95
  * [`configure(...)`](#configure)
73
96
  * [`configRequest(...)`](#configrequest)
97
+ * [`requestConsentInfo(...)`](#requestconsentinfo)
98
+ * [`showConsentForm()`](#showconsentform)
99
+ * [`showPrivacyOptionsForm()`](#showprivacyoptionsform)
74
100
  * [`adCreate(...)`](#adcreate)
75
101
  * [`adIsLoaded(...)`](#adisloaded)
76
102
  * [`adLoad(...)`](#adload)
77
103
  * [`adShow(...)`](#adshow)
78
104
  * [`adHide(...)`](#adhide)
105
+ * [`feedAdCreate(...)`](#feedadcreate)
106
+ * [`feedAdDestroy(...)`](#feedaddestroy)
107
+ * [`feedAdLoad(...)`](#feedadload)
108
+ * [`feedAdIsLoaded(...)`](#feedadisloaded)
109
+ * [`feedAdUpdateBounds(...)`](#feedadupdatebounds)
110
+ * [`feedAdSetAutoRefresh(...)`](#feedadsetautorefresh)
79
111
  * [`trackingAuthorizationStatus()`](#trackingauthorizationstatus)
80
112
  * [`requestTrackingAuthorization()`](#requesttrackingauthorization)
81
- * [`addListener(string, ...)`](#addlistenerstring-)
113
+ * [`addListener(E, ...)`](#addlistenere-)
82
114
  * [`getPluginVersion()`](#getpluginversion)
83
115
  * [Interfaces](#interfaces)
84
116
  * [Type Aliases](#type-aliases)
@@ -138,6 +170,57 @@ Configure ad request settings.
138
170
  --------------------
139
171
 
140
172
 
173
+ ### requestConsentInfo(...)
174
+
175
+ ```typescript
176
+ requestConsentInfo(options?: AdmobConsentRequestOptions | undefined) => Promise<AdmobConsentInfo>
177
+ ```
178
+
179
+ Request user consent information from Google's User Messaging Platform (UMP).
180
+
181
+ Call this after `start()` and before loading ads for users in the EEA/UK.
182
+
183
+ | Param | Type | Description |
184
+ | ------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------ |
185
+ | **`options`** | <code><a href="#admobconsentrequestoptions">AdmobConsentRequestOptions</a></code> | - Optional consent request options for debugging and tagging |
186
+
187
+ **Returns:** <code>Promise&lt;<a href="#admobconsentinfo">AdmobConsentInfo</a>&gt;</code>
188
+
189
+ **Since:** 8.2.0
190
+
191
+ --------------------
192
+
193
+
194
+ ### showConsentForm()
195
+
196
+ ```typescript
197
+ showConsentForm() => Promise<AdmobConsentInfo>
198
+ ```
199
+
200
+ Shows the Google user consent form rendered from your GDPR message configuration.
201
+
202
+ **Returns:** <code>Promise&lt;<a href="#admobconsentinfo">AdmobConsentInfo</a>&gt;</code>
203
+
204
+ **Since:** 8.2.0
205
+
206
+ --------------------
207
+
208
+
209
+ ### showPrivacyOptionsForm()
210
+
211
+ ```typescript
212
+ showPrivacyOptionsForm() => Promise<void>
213
+ ```
214
+
215
+ Shows the Google privacy options form rendered from your GDPR message configuration.
216
+
217
+ Use this when your privacy message requires an in-app entry point for users to manage choices.
218
+
219
+ **Since:** 8.2.0
220
+
221
+ --------------------
222
+
223
+
141
224
  ### adCreate(...)
142
225
 
143
226
  ```typescript
@@ -225,6 +308,112 @@ Hide a currently displayed ad.
225
308
  --------------------
226
309
 
227
310
 
311
+ ### feedAdCreate(...)
312
+
313
+ ```typescript
314
+ feedAdCreate(opts: FeedAdCreateOptions) => Promise<{ id: number; }>
315
+ ```
316
+
317
+ Create an in-feed ad slot (native overlay or inline banner overlay).
318
+
319
+ | Param | Type | Description |
320
+ | ---------- | ------------------------------------------------------------------- | ----------------------- |
321
+ | **`opts`** | <code><a href="#feedadcreateoptions">FeedAdCreateOptions</a></code> | - Feed ad configuration |
322
+
323
+ **Returns:** <code>Promise&lt;{ id: number; }&gt;</code>
324
+
325
+ **Since:** 8.3.0
326
+
327
+ --------------------
328
+
329
+
330
+ ### feedAdDestroy(...)
331
+
332
+ ```typescript
333
+ feedAdDestroy(opts: { id: number; }) => Promise<void>
334
+ ```
335
+
336
+ Destroy a feed ad instance and remove its native overlay.
337
+
338
+ | Param | Type | Description |
339
+ | ---------- | ---------------------------- | ---------------------------------- |
340
+ | **`opts`** | <code>{ id: number; }</code> | - Object containing the feed ad id |
341
+
342
+ **Since:** 8.3.0
343
+
344
+ --------------------
345
+
346
+
347
+ ### feedAdLoad(...)
348
+
349
+ ```typescript
350
+ feedAdLoad(opts: { id: number; }) => Promise<void>
351
+ ```
352
+
353
+ Load or reload the feed ad. Listen for `feed.load` / `feed.loadfail` events.
354
+
355
+ | Param | Type | Description |
356
+ | ---------- | ---------------------------- | ---------------------------------- |
357
+ | **`opts`** | <code>{ id: number; }</code> | - Object containing the feed ad id |
358
+
359
+ **Since:** 8.3.0
360
+
361
+ --------------------
362
+
363
+
364
+ ### feedAdIsLoaded(...)
365
+
366
+ ```typescript
367
+ feedAdIsLoaded(opts: { id: number; }) => Promise<boolean>
368
+ ```
369
+
370
+ Whether the feed ad has finished loading.
371
+
372
+ | Param | Type | Description |
373
+ | ---------- | ---------------------------- | ---------------------------------- |
374
+ | **`opts`** | <code>{ id: number; }</code> | - Object containing the feed ad id |
375
+
376
+ **Returns:** <code>Promise&lt;boolean&gt;</code>
377
+
378
+ **Since:** 8.3.0
379
+
380
+ --------------------
381
+
382
+
383
+ ### feedAdUpdateBounds(...)
384
+
385
+ ```typescript
386
+ feedAdUpdateBounds(opts: FeedAdBounds & { id: number; }) => Promise<void>
387
+ ```
388
+
389
+ Position the native overlay over an HTML placeholder. Call on scroll, resize, and orientation changes.
390
+
391
+ | Param | Type | Description |
392
+ | ---------- | ----------------------------------------------------------------------- | -------------------------------------------------------------- |
393
+ | **`opts`** | <code><a href="#feedadbounds">FeedAdBounds</a> & { id: number; }</code> | - Feed ad id and bounds from `element.getBoundingClientRect()` |
394
+
395
+ **Since:** 8.3.0
396
+
397
+ --------------------
398
+
399
+
400
+ ### feedAdSetAutoRefresh(...)
401
+
402
+ ```typescript
403
+ feedAdSetAutoRefresh(opts: { id: number; autoRefreshMs: number | null; }) => Promise<void>
404
+ ```
405
+
406
+ Enable or disable auto-refresh (minimum 30 seconds).
407
+
408
+ | Param | Type | Description |
409
+ | ---------- | ----------------------------------------------------------- | ----------------------------------------------------- |
410
+ | **`opts`** | <code>{ id: number; autoRefreshMs: number \| null; }</code> | - Feed ad id and interval in ms, or `null` to disable |
411
+
412
+ **Since:** 8.3.0
413
+
414
+ --------------------
415
+
416
+
228
417
  ### trackingAuthorizationStatus()
229
418
 
230
419
  ```typescript
@@ -255,18 +444,18 @@ Request tracking authorization from the user (iOS only).
255
444
  --------------------
256
445
 
257
446
 
258
- ### addListener(string, ...)
447
+ ### addListener(E, ...)
259
448
 
260
449
  ```typescript
261
- addListener(eventName: string, listenerFunc: (event: any) => void) => Promise<PluginListenerHandle> & PluginListenerHandle
450
+ addListener<E extends AdMobPlusEventName>(eventName: E, listenerFunc: (event: AdMobPlusEventPayloadMap[E]) => void) => Promise<PluginListenerHandle> & PluginListenerHandle
262
451
  ```
263
452
 
264
453
  Add a listener for ad events.
265
454
 
266
- | Param | Type | Description |
267
- | ------------------ | ------------------------------------ | -------------------------------------------- |
268
- | **`eventName`** | <code>string</code> | - The name of the event to listen for |
269
- | **`listenerFunc`** | <code>(event: any) =&gt; void</code> | - The function to call when the event occurs |
455
+ | Param | Type | Description |
456
+ | ------------------ | ------------------------------------------------------------ | -------------------------------------------- |
457
+ | **`eventName`** | <code>E</code> | - The name of the event to listen for |
458
+ | **`listenerFunc`** | <code>(event: AdMobPlusEventPayloadMap[E]) =&gt; void</code> | - The function to call when the event occurs |
270
459
 
271
460
  **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt; & <a href="#pluginlistenerhandle">PluginListenerHandle</a></code>
272
461
 
@@ -317,6 +506,20 @@ Configuration for ad requests.
317
506
  <code>{ /** Maximum ad content rating */ maxAdContentRating?: <a href="#maxadcontentrating">MaxAdContentRating</a>; /** Whether to use the same app key */ sameAppKey?: boolean; /** Tag for child-directed treatment (true, false, or null for unspecified) */ tagForChildDirectedTreatment?: boolean | null; /** Tag for under age of consent (true, false, or null for unspecified) */ tagForUnderAgeOfConsent?: boolean | null; /** Array of test device IDs */ testDeviceIds?: string[]; }</code>
318
507
 
319
508
 
509
+ #### AdmobConsentInfo
510
+
511
+ Consent information returned by UMP.
512
+
513
+ <code>{ /** The consent status of the user. */ status: <a href="#admobconsentstatus">AdmobConsentStatus</a>; /** If true, a consent form is available. */ isConsentFormAvailable?: boolean; /** If true, an ad request can be made. */ canRequestAds: boolean; /** Privacy options requirement status of the user. */ privacyOptionsRequirementStatus: <a href="#privacyoptionsrequirementstatus">PrivacyOptionsRequirementStatus</a>; }</code>
514
+
515
+
516
+ #### AdmobConsentRequestOptions
517
+
518
+ Options for requesting UMP consent information.
519
+
520
+ <code>{ /** Sets the debug geography to test consent locally. */ debugGeography?: <a href="#admobconsentdebuggeography">AdmobConsentDebugGeography</a>; /** * Test device IDs to allow for consent debugging. * On iOS, the ID may change if you uninstall and reinstall the app. */ testDeviceIdentifiers?: string[]; /** * When true, tags the user as under the age of consent for UMP requests. * * @default false */ tagForUnderAgeOfConsent?: boolean; }</code>
521
+
522
+
320
523
  #### MobileAdOptions
321
524
 
322
525
  Base options for mobile ads.
@@ -324,6 +527,92 @@ Base options for mobile ads.
324
527
  <code>{ /** The ad unit ID from AdMob */ adUnitId: string; }</code>
325
528
 
326
529
 
530
+ #### FeedAdCreateOptions
531
+
532
+ Options for creating an in-feed ad instance.
533
+
534
+ Policy: AdMob counts native impressions and clicks only when assets render inside
535
+ {@link https://developers.google.com/admob/android/native/advanced | NativeAdView} /
536
+ GADNativeAdView with the AdChoices icon and an ad attribution badge. This plugin
537
+ overlays a compliant native view on your placeholder. Optional {@link FeedNativeAdAssets}
538
+ are returned on `feed.load` for layout sizing only, not for manual click forwarding.
539
+
540
+ <code>{ /** Native advanced or inline banner. */ format: <a href="#feedadformat">FeedAdFormat</a>; /** AdMob ad unit ID. */ adUnitId: string; /** Optional key echoed on feed events for your feed slot. */ positionKey?: string; /** * Auto-refresh interval in milliseconds. AdMob requires at least 30 seconds. * Omit or pass `null` to disable auto-refresh. */ autoRefreshMs?: number | null; /** Template colors when `format` is `native`. */ nativeStyle?: <a href="#feednativeadstyle">FeedNativeAdStyle</a>; }</code>
541
+
542
+
543
+ #### FeedAdFormat
544
+
545
+ In-feed ad format. Both use a native overlay aligned to an HTML placeholder.
546
+
547
+ <code>'native' | 'banner'</code>
548
+
549
+
550
+ #### FeedNativeAdStyle
551
+
552
+ Optional colors for the built-in native ad template (hex strings, e.g. `#ffffff`).
553
+
554
+ <code>{ backgroundColor?: string; headlineTextColor?: string; bodyTextColor?: string; ctaBackgroundColor?: string; ctaTextColor?: string; }</code>
555
+
556
+
557
+ #### FeedAdBounds
558
+
559
+ Bounds of the HTML placeholder, in CSS pixels relative to the WebView viewport.
560
+
561
+ <code>{ x: number; y: number; width: number; height: number; /** When false, the native overlay is hidden (e.g. off-screen while scrolling). */ visible: boolean; /** `window.devicePixelRatio` from the WebView. Defaults to 1 on web. */ density?: number; }</code>
562
+
563
+
564
+ #### AdMobPlusEventName
565
+
566
+ <code>(typeof AdMobPlusEvents)[keyof typeof AdMobPlusEvents]</code>
567
+
568
+
569
+ #### AdMobPlusEventPayloadMap
570
+
571
+ Maps each {@link <a href="#admobpluseventname">AdMobPlusEventName</a>} to the payload shape emitted from native code.
572
+
573
+ <code>{ [AdMobPlusEvents.AdClick]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.AdDismiss]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.AdImpression]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.AdLoad]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.AdLoadFail]: <a href="#admobplusadfailurepayload">AdMobPlusAdFailurePayload</a>; [AdMobPlusEvents.AdReward]: <a href="#admobplusadrewardpayload">AdMobPlusAdRewardPayload</a>; [AdMobPlusEvents.AdShow]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.AdShowFail]: <a href="#admobplusadfailurepayload">AdMobPlusAdFailurePayload</a>; [AdMobPlusEvents.BannerClick]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.BannerClose]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.BannerImpression]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.BannerLoad]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.BannerLoadFail]: <a href="#admobplusadfailurepayload">AdMobPlusAdFailurePayload</a>; [AdMobPlusEvents.BannerOpen]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.BannerSizeChange]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.InterstitialDismiss]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.InterstitialImpression]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.InterstitialLoad]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.InterstitialLoadFail]: <a href="#admobplusadfailurepayload">AdMobPlusAdFailurePayload</a>; [AdMobPlusEvents.InterstitialShow]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.InterstitialShowFail]: <a href="#admobplusadfailurepayload">AdMobPlusAdFailurePayload</a>; [AdMobPlusEvents.RewardedDismiss]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.RewardedImpression]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.RewardedInterstitialDismiss]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.RewardedInterstitialImpression]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.RewardedInterstitialLoad]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.RewardedInterstitialLoadFail]: <a href="#admobplusadfailurepayload">AdMobPlusAdFailurePayload</a>; [AdMobPlusEvents.RewardedInterstitialReward]: <a href="#admobplusadrewardpayload">AdMobPlusAdRewardPayload</a>; [AdMobPlusEvents.RewardedInterstitialShow]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.RewardedInterstitialShowFail]: <a href="#admobplusadfailurepayload">AdMobPlusAdFailurePayload</a>; [AdMobPlusEvents.RewardedLoad]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.RewardedLoadFail]: <a href="#admobplusadfailurepayload">AdMobPlusAdFailurePayload</a>; [AdMobPlusEvents.RewardedReward]: <a href="#admobplusadrewardpayload">AdMobPlusAdRewardPayload</a>; [AdMobPlusEvents.RewardedShow]: <a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a>; [AdMobPlusEvents.RewardedShowFail]: <a href="#admobplusadfailurepayload">AdMobPlusAdFailurePayload</a>; [AdMobPlusEvents.FeedClick]: <a href="#admobplusfeedadidpayload">AdMobPlusFeedAdIdPayload</a>; [AdMobPlusEvents.FeedClose]: <a href="#admobplusfeedadidpayload">AdMobPlusFeedAdIdPayload</a>; [AdMobPlusEvents.FeedImpression]: <a href="#admobplusfeedadidpayload">AdMobPlusFeedAdIdPayload</a>; [AdMobPlusEvents.FeedLoad]: <a href="#admobplusfeedloadpayload">AdMobPlusFeedLoadPayload</a>; [AdMobPlusEvents.FeedLoadFail]: <a href="#admobplusadfailurepayload">AdMobPlusAdFailurePayload</a> & <a href="#admobplusfeedadidpayload">AdMobPlusFeedAdIdPayload</a>; [AdMobPlusEvents.FeedOpen]: <a href="#admobplusfeedadidpayload">AdMobPlusFeedAdIdPayload</a>; [AdMobPlusEvents.FeedRefresh]: <a href="#admobplusfeedadidpayload">AdMobPlusFeedAdIdPayload</a>; }</code>
574
+
575
+
576
+ #### AdMobPlusAdIdPayload
577
+
578
+ Event payload always includes the native ad instance id (`adId`). iOS also emits legacy `id`.
579
+
580
+ <code>{ adId: number; id?: number; }</code>
581
+
582
+
583
+ #### AdMobPlusAdFailurePayload
584
+
585
+ Load and fullscreen show failure payloads from native `LoadAdError` / `FullScreenContentError`.
586
+
587
+ <code><a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a> & { code: number; message: string; /** Legacy iOS failure field; same string as `message` when present. */ error?: string; }</code>
588
+
589
+
590
+ #### AdMobPlusAdRewardPayload
591
+
592
+ Reward callbacks include the earned reward plus `adId`.
593
+
594
+ <code><a href="#admobplusadidpayload">AdMobPlusAdIdPayload</a> & { reward: { amount: number; type: string; }; }</code>
595
+
596
+
597
+ #### AdMobPlusFeedAdIdPayload
598
+
599
+ In-feed ad events use `feedAdId` (same numeric id as `feedAdCreate`).
600
+
601
+ <code>{ feedAdId: number; positionKey?: string; format?: 'native' | 'banner'; }</code>
602
+
603
+
604
+ #### AdMobPlusFeedLoadPayload
605
+
606
+ <code><a href="#admobplusfeedadidpayload">AdMobPlusFeedAdIdPayload</a> & { assets?: <a href="#record">Record</a>&lt;string, unknown&gt;; }</code>
607
+
608
+
609
+ #### Record
610
+
611
+ Construct a type with a set of properties K of type T
612
+
613
+ <code>{
327
614
  [P in K]: T;
328
615
  }</code>
616
+
617
+
329
618
  ### Enums
330
619
 
331
620
 
@@ -338,6 +627,36 @@ Base options for mobile ads.
338
627
  | **`UNSPECIFIED`** | <code>''</code> | Unspecified rating |
339
628
 
340
629
 
630
+ #### AdmobConsentStatus
631
+
632
+ | Members | Value | Description |
633
+ | ------------------ | --------------------------- | --------------------------------------------------------------- |
634
+ | **`NOT_REQUIRED`** | <code>'NOT_REQUIRED'</code> | User consent not required. |
635
+ | **`OBTAINED`** | <code>'OBTAINED'</code> | User consent already obtained. |
636
+ | **`REQUIRED`** | <code>'REQUIRED'</code> | User consent required but not yet obtained. |
637
+ | **`UNKNOWN`** | <code>'UNKNOWN'</code> | Unknown consent status. Call requestConsentInfo() to update it. |
638
+
639
+
640
+ #### PrivacyOptionsRequirementStatus
641
+
642
+ | Members | Value | Description |
643
+ | ------------------ | --------------------------- | ---------------------------------------------- |
644
+ | **`NOT_REQUIRED`** | <code>'NOT_REQUIRED'</code> | Privacy options entry point is not required. |
645
+ | **`REQUIRED`** | <code>'REQUIRED'</code> | Privacy options entry point is required. |
646
+ | **`UNKNOWN`** | <code>'UNKNOWN'</code> | Privacy options requirement status is unknown. |
647
+
648
+
649
+ #### AdmobConsentDebugGeography
650
+
651
+ | Members | Value | Description |
652
+ | -------------- | -------------- | --------------------------------------------------------------- |
653
+ | **`DISABLED`** | <code>0</code> | Debug geography disabled. |
654
+ | **`EEA`** | <code>1</code> | Geography appears as in EEA for debug devices. |
655
+ | **`NOT_EEA`** | <code>2</code> | Geography appears as not in EEA for debug devices. |
656
+ | **`US`** | <code>3</code> | Geography appears as in a regulated US state for debug devices. |
657
+ | **`OTHER`** | <code>4</code> | Geography appears as OTHER for debug devices. |
658
+
659
+
341
660
  #### TrackingAuthorizationStatus
342
661
 
343
662
  | Members | Value | Description |
@@ -7,6 +7,7 @@ ext {
7
7
  androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
8
8
  // Next Gen is currently published as a beta artifact; apps can override this property when pinning a newer vetted release.
9
9
  googleMobileAdsNextGenVersion = project.hasProperty('googleMobileAdsNextGenVersion') ? rootProject.ext.googleMobileAdsNextGenVersion : '0.25.0-beta01'
10
+ userMessagingPlatformVersion = project.hasProperty('userMessagingPlatformVersion') ? rootProject.ext.userMessagingPlatformVersion : '4.0.0'
10
11
  }
11
12
 
12
13
  buildscript {
@@ -16,7 +17,7 @@ buildscript {
16
17
  }
17
18
  dependencies {
18
19
  classpath 'com.android.tools.build:gradle:8.13.0'
19
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.3.21"
20
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.4.21"
20
21
  }
21
22
  }
22
23
 
@@ -64,9 +65,9 @@ dependencies {
64
65
  implementation fileTree(dir: 'libs', include: ['*.jar'])
65
66
  implementation project(':capacitor-android')
66
67
  implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
67
- implementation 'androidx.core:core-ktx:1.9.0'
68
68
  testImplementation "junit:junit:$junitVersion"
69
69
  androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
70
70
  androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
71
71
  implementation "com.google.android.libraries.ads.mobile.sdk:ads-mobile-sdk:$googleMobileAdsNextGenVersion"
72
+ implementation "com.google.android.ump:user-messaging-platform:$userMessagingPlatformVersion"
72
73
  }
@@ -1,6 +1,7 @@
1
1
  package admob.plus.capacitor
2
2
 
3
3
  import admob.plus.capacitor.ads.Banner
4
+ import admob.plus.capacitor.feed.FeedAdManager
4
5
  import admob.plus.capacitor.ads.Interstitial
5
6
  import admob.plus.capacitor.ads.Rewarded
6
7
  import admob.plus.capacitor.ads.RewardedInterstitial
@@ -23,6 +24,8 @@ import org.json.JSONObject
23
24
  class AdMobPlusPlugin : Plugin(), Helper.Adapter {
24
25
  private val pluginVersion = "8.0.15"
25
26
  private var helper: Helper? = null
27
+ private var consentHelper: ConsentHelper? = null
28
+ private var feedAdManager: FeedAdManager? = null
26
29
  @Volatile
27
30
  private var mobileAdsInitialized = false
28
31
  private var requestConfigurationOverride: RequestConfiguration? = null
@@ -30,6 +33,8 @@ class AdMobPlusPlugin : Plugin(), Helper.Adapter {
30
33
  override fun load() {
31
34
  super.load()
32
35
  helper = Helper(this)
36
+ consentHelper = ConsentHelper(this)
37
+ feedAdManager = FeedAdManager(this)
33
38
  ExecuteContext.plugin = this
34
39
  }
35
40
 
@@ -83,6 +88,23 @@ class AdMobPlusPlugin : Plugin(), Helper.Adapter {
83
88
  ctx.configure(helper!!)
84
89
  }
85
90
 
91
+ @PluginMethod
92
+ fun requestConsentInfo(call: PluginCall) {
93
+ bridge.executeOnMainThread {
94
+ consentHelper?.requestConsentInfo(call)
95
+ }
96
+ }
97
+
98
+ @PluginMethod
99
+ fun showConsentForm(call: PluginCall) {
100
+ consentHelper?.showConsentForm(call)
101
+ }
102
+
103
+ @PluginMethod
104
+ fun showPrivacyOptionsForm(call: PluginCall) {
105
+ consentHelper?.showPrivacyOptionsForm(call)
106
+ }
107
+
86
108
  @PluginMethod
87
109
  fun configRequest(call: PluginCall) {
88
110
  val ctx = ExecuteContext(call)
@@ -160,6 +182,105 @@ class AdMobPlusPlugin : Plugin(), Helper.Adapter {
160
182
  }
161
183
  }
162
184
 
185
+ @PluginMethod
186
+ fun feedAdCreate(call: PluginCall) {
187
+ val format = call.getString("format")
188
+ val adUnitId = call.getString("adUnitId")
189
+ if (format == null || adUnitId == null) {
190
+ call.reject("format and adUnitId are required")
191
+ return
192
+ }
193
+ val positionKey = call.getString("positionKey")
194
+ val autoRefreshMs = if (call.data.has("autoRefreshMs")) call.getInt("autoRefreshMs") else null
195
+ val nativeStyle = mutableMapOf<String, String>()
196
+ val styleObj = call.getObject("nativeStyle")
197
+ if (styleObj != null) {
198
+ val keys = styleObj.keys()
199
+ while (keys.hasNext()) {
200
+ val key = keys.next()
201
+ nativeStyle[key] = styleObj.optString(key)
202
+ }
203
+ }
204
+ bridge.executeOnMainThread {
205
+ val id = feedAdManager!!.create(format, adUnitId, positionKey, autoRefreshMs, nativeStyle)
206
+ val ret = JSObject()
207
+ ret.put("id", id)
208
+ call.resolve(ret)
209
+ }
210
+ }
211
+
212
+ @PluginMethod
213
+ fun feedAdDestroy(call: PluginCall) {
214
+ val id = call.getInt("id")
215
+ if (id == null) {
216
+ call.reject("id is required")
217
+ return
218
+ }
219
+ bridge.executeOnMainThread {
220
+ feedAdManager!!.destroy(id)
221
+ call.resolve()
222
+ }
223
+ }
224
+
225
+ @PluginMethod
226
+ fun feedAdLoad(call: PluginCall) {
227
+ val id = call.getInt("id")
228
+ if (id == null) {
229
+ call.reject("id is required")
230
+ return
231
+ }
232
+ if (rejectIfNotInitialized { call.reject(it) }) {
233
+ return
234
+ }
235
+ feedAdManager!!.load(id) { error ->
236
+ if (error != null) {
237
+ call.reject(error)
238
+ } else {
239
+ call.resolve()
240
+ }
241
+ }
242
+ }
243
+
244
+ @PluginMethod
245
+ fun feedAdIsLoaded(call: PluginCall) {
246
+ val id = call.getInt("id")
247
+ if (id == null) {
248
+ call.reject("id is required")
249
+ return
250
+ }
251
+ val ret = JSObject()
252
+ ret.put("value", feedAdManager!!.isLoaded(id))
253
+ call.resolve(ret)
254
+ }
255
+
256
+ @PluginMethod
257
+ fun feedAdUpdateBounds(call: PluginCall) {
258
+ val id = call.getInt("id")
259
+ if (id == null) {
260
+ call.reject("id is required")
261
+ return
262
+ }
263
+ val x = call.getDouble("x") ?: 0.0
264
+ val y = call.getDouble("y") ?: 0.0
265
+ val width = call.getDouble("width") ?: 0.0
266
+ val height = call.getDouble("height") ?: 0.0
267
+ val visible = call.getBoolean("visible") ?: false
268
+ feedAdManager!!.updateBounds(id, x, y, width, height, visible)
269
+ call.resolve()
270
+ }
271
+
272
+ @PluginMethod
273
+ fun feedAdSetAutoRefresh(call: PluginCall) {
274
+ val id = call.getInt("id")
275
+ if (id == null) {
276
+ call.reject("id is required")
277
+ return
278
+ }
279
+ val autoRefreshMs = if (call.data.has("autoRefreshMs")) call.getInt("autoRefreshMs") else null
280
+ feedAdManager!!.setAutoRefresh(id, autoRefreshMs)
281
+ call.resolve()
282
+ }
283
+
163
284
  @PluginMethod
164
285
  fun adHide(call: PluginCall) {
165
286
  val ctx = ExecuteContext(call)