@capgo/capacitor-admob 8.1.20 → 8.2.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 (44) hide show
  1. package/CapgoCapacitorAdmob.podspec +1 -0
  2. package/Package.swift +4 -2
  3. package/README.md +348 -10
  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
@@ -1,10 +1,29 @@
1
1
  # @capgo/capacitor-admob
2
- <a href="https://capgo.app/"><img src="https://capgo.app/readme-banner.svg?repo=Cap-go/capacitor-admob" alt="Capgo - Instant updates for Capacitor" /></a>
2
+
3
+ Show Google AdMob ads in your Capacitor app on iOS and Android: banner, interstitial, rewarded and rewarded interstitial formats from one TypeScript API. Monetize your app with the official Google Mobile Ads SDKs underneath.
4
+
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>
3
6
 
4
7
  <div align="center">
5
- <h2><a href="https://capgo.app/?ref=plugin_admob"> ➡️ Get Instant updates for your App with Capgo</a></h2>
6
- <h2><a href="https://capgo.app/consulting/?ref=plugin_admob"> Missing a feature? We’ll build the plugin for you 💪</a></h2>
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
+ <h2><a href="https://capgo.app/register/?ref=plugin_admob">➡️ Get started for free</a></h2>
10
+ <p>14-day unlimited free trial. No credit card required</p>
11
+ <p><a href="https://capgo.app/consulting/?ref=plugin_admob">Missing a feature? We'll build the plugin for you 💪</a></p>
7
12
  </div>
13
+
14
+ <p align="center">
15
+ <img src="https://raw.githubusercontent.com/Cap-go/capacitor-admob/main/assets/github-social-preview.png" alt="@capgo/capacitor-admob for Capacitor apps" width="300" />
16
+ </p>
17
+
18
+ ## Key features
19
+
20
+ - **Four ad formats**: `BannerAd`, `InterstitialAd`, `RewardedAd` and `RewardedInterstitialAd` classes with load and show, plus `hide()` on `BannerAd`.
21
+ - **Ad lifecycle**: `adCreate()`, `adLoad()`, `adIsLoaded()`, `adShow()` and `adHide()` give you full control over each ad instance.
22
+ - **SDK setup**: `start()` initializes AdMob, `configure()` sets app-wide options and `configRequest()` sets request options.
23
+ - **App Tracking Transparency**: `trackingAuthorizationStatus()` and `requestTrackingAuthorization()` handle the iOS tracking prompt.
24
+ - **Current SDKs**: Google Mobile Ads Next Gen SDK on Android and Google Mobile Ads SDK on iOS.
25
+ - **Platforms**: iOS and Android. The web implementation is a no-op stub.
26
+
8
27
  AdMob SDK bridge for Capacitor apps
9
28
 
10
29
  Android now uses the Google Mobile Ads Next Gen SDK, and iOS is aligned to Google Mobile Ads SDK `13.1.x`, while preserving the existing Capacitor-facing API.
@@ -45,6 +64,29 @@ npm install @capgo/capacitor-admob
45
64
  npx cap sync
46
65
  ```
47
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
+
48
90
  ## API
49
91
 
50
92
  <docgen-index>
@@ -52,14 +94,23 @@ npx cap sync
52
94
  * [`start()`](#start)
53
95
  * [`configure(...)`](#configure)
54
96
  * [`configRequest(...)`](#configrequest)
97
+ * [`requestConsentInfo(...)`](#requestconsentinfo)
98
+ * [`showConsentForm()`](#showconsentform)
99
+ * [`showPrivacyOptionsForm()`](#showprivacyoptionsform)
55
100
  * [`adCreate(...)`](#adcreate)
56
101
  * [`adIsLoaded(...)`](#adisloaded)
57
102
  * [`adLoad(...)`](#adload)
58
103
  * [`adShow(...)`](#adshow)
59
104
  * [`adHide(...)`](#adhide)
105
+ * [`feedAdCreate(...)`](#feedadcreate)
106
+ * [`feedAdDestroy(...)`](#feedaddestroy)
107
+ * [`feedAdLoad(...)`](#feedadload)
108
+ * [`feedAdIsLoaded(...)`](#feedadisloaded)
109
+ * [`feedAdUpdateBounds(...)`](#feedadupdatebounds)
110
+ * [`feedAdSetAutoRefresh(...)`](#feedadsetautorefresh)
60
111
  * [`trackingAuthorizationStatus()`](#trackingauthorizationstatus)
61
112
  * [`requestTrackingAuthorization()`](#requesttrackingauthorization)
62
- * [`addListener(string, ...)`](#addlistenerstring-)
113
+ * [`addListener(E, ...)`](#addlistenere-)
63
114
  * [`getPluginVersion()`](#getpluginversion)
64
115
  * [Interfaces](#interfaces)
65
116
  * [Type Aliases](#type-aliases)
@@ -119,6 +170,57 @@ Configure ad request settings.
119
170
  --------------------
120
171
 
121
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
+
122
224
  ### adCreate(...)
123
225
 
124
226
  ```typescript
@@ -206,6 +308,112 @@ Hide a currently displayed ad.
206
308
  --------------------
207
309
 
208
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
+
209
417
  ### trackingAuthorizationStatus()
210
418
 
211
419
  ```typescript
@@ -236,18 +444,18 @@ Request tracking authorization from the user (iOS only).
236
444
  --------------------
237
445
 
238
446
 
239
- ### addListener(string, ...)
447
+ ### addListener(E, ...)
240
448
 
241
449
  ```typescript
242
- 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
243
451
  ```
244
452
 
245
453
  Add a listener for ad events.
246
454
 
247
- | Param | Type | Description |
248
- | ------------------ | ------------------------------------ | -------------------------------------------- |
249
- | **`eventName`** | <code>string</code> | - The name of the event to listen for |
250
- | **`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 |
251
459
 
252
460
  **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt; & <a href="#pluginlistenerhandle">PluginListenerHandle</a></code>
253
461
 
@@ -298,6 +506,20 @@ Configuration for ad requests.
298
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>
299
507
 
300
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
+
301
523
  #### MobileAdOptions
302
524
 
303
525
  Base options for mobile ads.
@@ -305,6 +527,92 @@ Base options for mobile ads.
305
527
  <code>{ /** The ad unit ID from AdMob */ adUnitId: string; }</code>
306
528
 
307
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>{
308
614
  [P in K]: T;
309
615
  }</code>
616
+
617
+
310
618
  ### Enums
311
619
 
312
620
 
@@ -319,6 +627,36 @@ Base options for mobile ads.
319
627
  | **`UNSPECIFIED`** | <code>''</code> | Unspecified rating |
320
628
 
321
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
+
322
660
  #### TrackingAuthorizationStatus
323
661
 
324
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.20"
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)