@capacitor-community/admob 8.1.0 → 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 (41) hide show
  1. package/README.md +129 -324
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/getcapacitor/community/admob/AdMob.java +13 -3
  4. package/android/src/main/java/com/getcapacitor/community/admob/banner/BannerExecutor.java +261 -141
  5. package/android/src/main/java/com/getcapacitor/community/admob/helpers/FullscreenPluginCallback.kt +5 -1
  6. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/AdInterstitialExecutor.java +27 -31
  7. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdCallbackAndListeners.kt +1 -1
  8. package/android/src/main/java/com/getcapacitor/community/admob/models/LoadPluginEventNames.kt +2 -1
  9. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/AdRewardExecutor.java +29 -33
  10. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardAdPluginEvents.kt +2 -1
  11. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardedAdCallbackAndListeners.kt +1 -1
  12. package/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/AdRewardInterstitialExecutor.java +29 -37
  13. package/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardedInterstitialAdCallbackAndListeners.kt +1 -1
  14. package/dist/docs.json +33 -3
  15. package/dist/esm/interstitial/interstitial-definitions.interface.d.ts +3 -0
  16. package/dist/esm/reward/reward-ad-plugin-events.enum.d.ts +4 -0
  17. package/dist/esm/reward/reward-ad-plugin-events.enum.js +4 -0
  18. package/dist/esm/reward/reward-ad-plugin-events.enum.js.map +1 -1
  19. package/dist/esm/reward/reward-definitions.interface.d.ts +8 -0
  20. package/dist/esm/reward-interstitial/reward-interstitial-definitions.interface.d.ts +3 -0
  21. package/dist/plugin.cjs.js +4 -0
  22. package/dist/plugin.cjs.js.map +1 -1
  23. package/dist/plugin.js +4 -0
  24. package/dist/plugin.js.map +1 -1
  25. package/docs/app-open.md +53 -0
  26. package/docs/banner.md +100 -0
  27. package/docs/configuration.md +30 -0
  28. package/docs/consent.md +80 -0
  29. package/docs/events.md +75 -0
  30. package/docs/interstitial.md +47 -0
  31. package/docs/migration.md +126 -0
  32. package/docs/rewarded.md +135 -0
  33. package/docs/testing.md +67 -0
  34. package/ios/Sources/AdMobPlugin/AdMobPlugin.swift +4 -1
  35. package/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdManager.swift +1 -1
  36. package/ios/Sources/AdMobPlugin/Banner/BannerExecutor.swift +1 -1
  37. package/ios/Sources/AdMobPlugin/Interstitial/AdInterstitialExecutor.swift +3 -3
  38. package/ios/Sources/AdMobPlugin/Rewarded/AdRewardExecutor.swift +7 -3
  39. package/ios/Sources/AdMobPlugin/Rewarded/RewardAdPluginEvents.swift +1 -0
  40. package/ios/Sources/AdMobPlugin/RewardedInterstitial/AdRewardInterstitialExecutor.swift +3 -3
  41. package/package.json +3 -1
package/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ <!-- rdlabo-docs-omit -->
1
2
  <p align="center"><br><img src="https://user-images.githubusercontent.com/236501/85893648-1c92e880-b7a8-11ea-926d-95355b8175c7.png" width="128" height="128" /></p>
2
3
  <h3 align="center">AdMob</h3>
3
4
  <p align="center"><strong><code>@capacitor-community/admob</code></strong></p>
@@ -5,6 +6,10 @@
5
6
  Capacitor community plugin for native AdMob.
6
7
  </p>
7
8
 
9
+ <p align="center">
10
+ <strong><a href="https://docs.rdlabo.dev/projects/capacitor-admob">Read the full documentation</a></strong>
11
+ </p>
12
+
8
13
  <p align="center">
9
14
  <img src="https://img.shields.io/maintenance/yes/2026?style=flat-square" />
10
15
  <a href="https://www.npmjs.com/package/@capacitor-community/admob"><img src="https://img.shields.io/npm/l/@capacitor-community/admob?style=flat-square" /></a>
@@ -15,10 +20,10 @@
15
20
 
16
21
  ## Maintainers
17
22
 
18
- | Maintainer | GitHub | Social | Sponsoring Company |
19
- | ------------------- | ------------------------------------------------ | ----------------------------------------------- | ---------------------------------------------- |
20
- | Masahiko Sakakibara | [rdlabo](https://github.com/rdlabo) | [@rdlabo](https://twitter.com/rdlabo) | RELATION DESIGN LABO, GENERAL INC. ASSOCIATION |
21
- | Saninn Salas Diaz | [Saninn Salas Diaz](https://github.com/distante) | [@SaninnSalas](https://twitter.com/SaninnSalas) | |
23
+ | Maintainer | GitHub | Social | Website |
24
+ | ------------------- | ------------------------------------------------ | ----------------------------------------------- | ----------------------------------------------- |
25
+ | Masahiko Sakakibara | [rdlabo](https://github.com/rdlabo) | [@rdlabo](https://twitter.com/rdlabo) | [rdlabo.dev](https://rdlabo.dev/) |
26
+ | Saninn Salas Diaz | [Saninn Salas Diaz](https://github.com/distante) | [@SaninnSalas](https://twitter.com/SaninnSalas) | — |
22
27
 
23
28
  Maintenance Status: Actively Maintained
24
29
 
@@ -41,51 +46,60 @@ Made with [contributors-img](https://contrib.rocks).
41
46
  | **iOS** | ![](demo/screenshots/ios_banner.png) | ![](demo/screenshots/ios_interstitial.png) | ![](demo/screenshots/ios_reward.png) | ![](demo/screenshots/ios_open.png) |
42
47
  | **Android** | ![](demo/screenshots/md_banner.png) | ![](demo/screenshots/md_interstitial.png) | ![](demo/screenshots/md_reward.png) | ![](demo/screenshots/md_open.png) |
43
48
 
49
+ <!-- /rdlabo-docs-omit -->
50
+
51
+ ## Overview
52
+
53
+ Capacitor community plugin for native AdMob. This plugin wraps the Google Mobile Ads SDK for iOS and Android so you can display banner, interstitial, rewarded, rewarded interstitial, and app open ads in Capacitor apps. It also covers Google User Messaging Platform (UMP) consent and App Tracking Transparency helpers on iOS.
54
+
44
55
  ## Installation
45
56
 
46
- If you use Capacitor 7:
57
+ This plugin already ships Google Mobile Ads SDK. Install the package, then add your AdMob **application** ID in AndroidManifest / Info.plist. Google's Get started guides for [Android](https://developers.google.com/admob/android/quick-start) and [iOS](https://developers.google.com/admob/ios/quick-start) explain app IDs and SKAdNetwork identifiers (Apple's ad conversion IDs); do not add a second Mobile Ads dependency.
47
58
 
48
- ```
49
- % npm install --save @capacitor-community/admob@7
50
- % npx cap update
51
- ```
59
+ This plugin targets `@capacitor-community/admob` **v8** and Capacitor 8.5 or later (within v8). It supports iOS 15 or later and Android API 24 or later.
52
60
 
53
- ### Google Mobile Ads SDK compatibility
61
+ ```bash
62
+ npm install @capacitor-community/admob
63
+ npx cap sync
64
+ ```
54
65
 
55
- To preserve behavior for users of the current major version, this plugin continues to use Google Mobile Ads SDK APIs that are deprecated but still supported. Replacing those APIs can change banner sizing and age-restricted treatment behavior, so that migration is deferred until the next major release.
66
+ If you still use Capacitor 7, install `@capacitor-community/admob@7`.
56
67
 
57
- Migration to the [GMA Next-Gen SDK for Android](https://developers.google.com/admob/android/next-gen) is also deferred until the next major release because it requires breaking changes to SDK initialization, ad requests, and mediation integration.
68
+ ### Google Mobile Ads SDK versions
58
69
 
59
- Android continues to use GMA SDK (Legacy) 25.4.x. On iOS, both Swift Package Manager and CocoaPods are fixed to GMA SDK 13.6.0 until CocoaPods support is removed in the next major release.
70
+ This major version pins Google Mobile Ads SDK **25.4.x** on Android and **13.6.0** on iOS (Swift Package Manager and CocoaPods). Leave those versions unless you have a specific need. Google's [Next-Gen SDK for Android](https://developers.google.com/admob/android/next-gen) waits until the next plugin major. See [Migration](https://docs.rdlabo.dev/projects/capacitor-admob/docs/migration) for the policy behind the pins.
60
71
 
61
72
  ### Android configuration
62
73
 
63
- In file `android/app/src/main/AndroidManifest.xml`, add the following XML elements under `<manifest><application>` :
74
+ In `android/app/src/main/AndroidManifest.xml`, add the following under `<application>`:
64
75
 
65
76
  ```xml
66
77
  <meta-data
67
- android:name="com.google.android.gms.ads.APPLICATION_ID"
68
- android:value="@string/admob_app_id"/>
78
+ android:name="com.google.android.gms.ads.APPLICATION_ID"
79
+ android:value="@string/admob_app_id" />
69
80
  ```
70
81
 
71
- In file `android/app/src/main/res/values/strings.xml` add the following lines :
82
+ In `android/app/src/main/res/values/strings.xml`:
72
83
 
73
84
  ```xml
74
85
  <string name="admob_app_id">[APP_ID]</string>
75
86
  ```
76
87
 
77
- Don't forget to replace `[APP_ID]` by your AdMob application Id.
88
+ Replace `[APP_ID]` with your AdMob **application** ID, not an ad unit ID.
78
89
 
79
90
  #### Variables
80
91
 
81
- This plugin will use the following project variables (defined in your app's `variables.gradle` file):
92
+ You can leave these unset. Override them in your app's `variables.gradle` only when you need a specific artifact version:
82
93
 
83
- - `playServicesAdsVersion` version of `com.google.android.gms:play-services-ads` (default: `25.4.+`)
84
- - `androidxCoreKTXVersion`: version of `androidx.core:core-ktx` (default: `1.15.0`)
94
+ | Variable | Artifact | Default |
95
+ | ------------------------------ | ------------------------------------------------ | -------- |
96
+ | `playServicesAdsVersion` | `com.google.android.gms:play-services-ads` | `25.4.+` |
97
+ | `userMessagingPlatformVersion` | `com.google.android.ump:user-messaging-platform` | `4.0.0` |
98
+ | `androidxCoreKTXVersion` | `androidx.core:core-ktx` | `1.15.0` |
85
99
 
86
100
  ### iOS configuration
87
101
 
88
- Add the following in the `ios/App/App/info.plist` file inside of the outermost `<dict>`:
102
+ Add the following inside the outermost `<dict>` in `ios/App/App/Info.plist`:
89
103
 
90
104
  ```xml
91
105
  <key>GADIsAdManagerApp</key>
@@ -100,337 +114,90 @@ Add the following in the `ios/App/App/info.plist` file inside of the outermost `
100
114
  </dict>
101
115
  </array>
102
116
  <key>NSUserTrackingUsageDescription</key>
103
- <string>[Why you use NSUserTracking. ex: This identifier will be used to deliver personalized ads to you.]</string>
117
+ <string>This identifier will be used to deliver personalized ads to you.</string>
104
118
  ```
105
119
 
106
- Don't forget to replace `[APP_ID]` by your AdMob application Id.
120
+ Replace `[APP_ID]` with your AdMob application ID, and describe your actual tracking use in `NSUserTrackingUsageDescription`.
107
121
 
108
- ## Example
109
-
110
- ### Initialize AdMob
111
-
112
- ```ts
113
- import { AdMob, AdmobConsentStatus } from '@capacitor-community/admob';
122
+ The `SKAdNetworkItems` snippet includes Google's own identifier. Add the other IDs from Google's [iOS setup guide](https://developers.google.com/admob/ios/quick-start#update_your_infoplist).
114
123
 
115
- export async function initialize(): Promise<void> {
116
- await AdMob.initialize();
124
+ ### Troubleshooting
117
125
 
118
- const [trackingInfo, consentInfo] = await Promise.all([
119
- AdMob.trackingAuthorizationStatus(),
120
- AdMob.requestConsentInfo(),
121
- ]);
122
-
123
- if (trackingInfo.status === 'notDetermined') {
124
- /**
125
- * If you want to explain TrackingAuthorization before showing the iOS dialog,
126
- * you can show the modal here.
127
- * ex)
128
- * const modal = await this.modalCtrl.create({
129
- * component: RequestTrackingPage,
130
- * });
131
- * await modal.present();
132
- * await modal.onDidDismiss(); // Wait for close modal
133
- **/
134
-
135
- await AdMob.requestTrackingAuthorization();
136
- }
126
+ If CocoaPods cannot resolve `Google-Mobile-Ads-SDK`:
137
127
 
138
- const authorizationStatus = await AdMob.trackingAuthorizationStatus();
139
- if (
140
- authorizationStatus.status === 'authorized' &&
141
- consentInfo.isConsentFormAvailable &&
142
- consentInfo.status === AdmobConsentStatus.REQUIRED
143
- ) {
144
- await AdMob.showConsentForm();
145
- }
146
- }
128
+ ```text
129
+ [error] Error running update: Analyzing dependencies
130
+ [!] CocoaPods could not find compatible versions for pod "Google-Mobile-Ads-SDK":
147
131
  ```
148
132
 
149
- Send an array of device Ids in `testingDevices` to use production like ads on your specified devices -> https://developers.google.com/admob/android/test-ads#enable_test_devices
150
-
151
- ### User Message Platform (UMP)
133
+ Run `pod repo update` in `ios/`, then `npx cap sync ios` again.
152
134
 
153
- To use UMP, you must [create your GDPR messages](https://support.google.com/admob/answer/10113207?hl=en&ref_topic=10105230&sjid=6731900490614517032-AP).
135
+ ## First test banner
154
136
 
155
- You may need to [setup IDFA messages](https://support.google.com/admob/answer/10115027?hl=en), it will work along with GDPR messages and will show when users are not in EEA and UK.
137
+ After installation and platform setup, initialize the SDK, request consent, and show a Google demo banner. Use the platform banner IDs from [Testing](https://docs.rdlabo.dev/projects/capacitor-admob/docs/testing)—do not create your own ad unit for this first check.
156
138
 
157
- Example of how to use UMP.
139
+ Call `startAdMob` from a user action or after the UI is ready (for example a button or post-navigation hook), not only at module evaluation time.
158
140
 
159
141
  ```ts
160
- import { AdMob } from '@capacitor-community/admob';
142
+ import { Capacitor } from '@capacitor/core';
143
+ import { AdMob, AdmobConsentStatus, BannerAdOptions, BannerAdSize, BannerAdPosition } from '@capacitor-community/admob';
144
+
145
+ const bannerAdId =
146
+ Capacitor.getPlatform() === 'ios'
147
+ ? 'ca-app-pub-3940256099942544/2934735716'
148
+ : 'ca-app-pub-3940256099942544/6300978111';
161
149
 
162
- private canShowAds: boolean | null = null;
150
+ async function startAdMob() {
151
+ await AdMob.initialize();
163
152
 
164
- async showConsent() {
165
153
  let consentInfo = await AdMob.requestConsentInfo();
166
- if (!consentInfo.canRequestAds) {
154
+ if (consentInfo.isConsentFormAvailable && consentInfo.status === AdmobConsentStatus.REQUIRED) {
167
155
  consentInfo = await AdMob.showConsentForm();
168
- this.canShowAds = consentInfo.canRequestAds;
169
156
  }
170
- }
171
- ```
172
-
173
- To let users manage their privacy options at any time, show the privacy options form.
174
- ```ts
175
- import { AdMob } from '@capacitor-community/admob';
176
157
 
177
- showPrivacyOptionsForm() {
178
- AdMob.showPrivacyOptionsForm();
179
- }
180
- ```
181
-
182
- If you testing on real device, you have to set `debugGeography` and add your device ID to `testDeviceIdentifiers`. You can find your device ID with logcat (Android) or XCode (iOS).
183
-
184
- ```ts
185
- import { AdMob, AdmobConsentDebugGeography } from '@capacitor-community/admob';
186
-
187
- const consentInfo = await AdMob.requestConsentInfo({
188
- debugGeography: AdmobConsentDebugGeography.EEA,
189
- testDeviceIdentifiers: ['YOUR_DEVICE_ID'],
190
- });
191
- ```
192
-
193
- **Note**: When testing, if you choose not consent (Manage -> Confirm Choices). The ads may not load/show. Even on testing enviroment. This is normal. It will work on Production so don't worry.
194
-
195
- **Note**: The order in which they are combined with other methods is as follows.
196
-
197
- 1. AdMob.initialize
198
- 2. AdMob.requestConsentInfo
199
- 3. AdMob.showConsentForm (If consent form required )
200
- 3/ AdMob.showBanner
201
-
202
- ### Show App Open Ad
203
-
204
- ```ts
205
- import {
206
- AdMob,
207
- AppOpenAdPluginEvents,
208
- AppOpenAdOptions,
209
- AdLoadInfo,
210
- } from '@capacitor-community/admob';
211
-
212
- export async function showAppOpenAd(): Promise<void> {
213
- // listen to events
214
- AdMob.addListener(AppOpenAdPluginEvents.Loaded, (info: AdLoadInfo) => {
215
- console.log('App Open Ad loaded', info.adUnitId);
216
- });
217
- AdMob.addListener(AppOpenAdPluginEvents.FailedToLoad, (error) => {
218
- console.log('Failed to load App Open Ad', error);
219
- });
220
- AdMob.addListener(AppOpenAdPluginEvents.Opened, () => {
221
- console.log('App Open Ad open');
222
- });
223
- AdMob.addListener(AppOpenAdPluginEvents.Closed, () => {
224
- console.log('App Open Ad close');
225
- });
226
- AdMob.addListener(AppOpenAdPluginEvents.FailedToShow, (error) => {
227
- console.log('Failed to show App Open Ad', error);
228
- });
229
-
230
- const options: AppOpenAdOptions = {
231
- adId: 'YOUR_AD_UNIT_ID',
232
- };
233
- const { adUnitId } = await AdMob.loadAppOpen(options);
234
- const { value } = await AdMob.isAppOpenLoaded({ adId: adUnitId });
235
- if (value) {
236
- await AdMob.showAppOpen({ adId: adUnitId });
158
+ if (!consentInfo.canRequestAds) {
159
+ // Consent not ready — no banner is shown.
160
+ return;
237
161
  }
238
- }
239
- ```
240
- ### Show Banner
241
-
242
- ```ts
243
- import {
244
- AdMob,
245
- BannerAdOptions,
246
- BannerAdSize,
247
- BannerAdPosition,
248
- BannerAdPluginEvents,
249
- AdMobBannerSize,
250
- } from '@capacitor-community/admob';
251
-
252
- export async function banner(): Promise<void> {
253
- AdMob.addListener(BannerAdPluginEvents.Loaded, () => {
254
- // Subscribe Banner Event Listener
255
- });
256
-
257
- AdMob.addListener(
258
- BannerAdPluginEvents.SizeChanged,
259
- (size: AdMobBannerSize) => {
260
- // Subscribe Change Banner Size
261
- },
262
- );
263
162
 
264
163
  const options: BannerAdOptions = {
265
- adId: 'YOUR ADID',
266
- adSize: BannerAdSize.BANNER,
164
+ adId: bannerAdId,
165
+ adSize: BannerAdSize.ADAPTIVE_BANNER,
267
166
  position: BannerAdPosition.BOTTOM_CENTER,
268
167
  margin: 0,
269
- // isTesting: true
270
- // npa: true
271
- };
272
- AdMob.showBanner(options);
273
- }
274
- ```
275
-
276
- ### Impression-level ad revenue
277
-
278
- Full-screen ad formats emit revenue data through their `AdImpression` event. Banners use the separate `AdPaid` event.
279
-
280
- ```ts
281
- import {
282
- AdMob,
283
- AdMobRevenueData,
284
- BannerAdPluginEvents,
285
- InterstitialAdPluginEvents,
286
- } from '@capacitor-community/admob';
287
-
288
- AdMob.addListener(
289
- InterstitialAdPluginEvents.AdImpression,
290
- (data: AdMobRevenueData) => {
291
- console.log(data);
292
- },
293
- );
294
-
295
- AdMob.addListener(BannerAdPluginEvents.AdPaid, (data: AdMobRevenueData) => {
296
- console.log(data);
297
- });
298
- ```
299
-
300
- ### Show Interstitial
301
-
302
- ```ts
303
- import {
304
- AdMob,
305
- AdOptions,
306
- AdLoadInfo,
307
- InterstitialAdPluginEvents,
308
- } from '@capacitor-community/admob';
309
-
310
- export async function interstitial(): Promise<void> {
311
- AdMob.addListener(InterstitialAdPluginEvents.Loaded, (info: AdLoadInfo) => {
312
- // Subscribe prepared interstitial
313
- });
314
-
315
- const options: AdOptions = {
316
- adId: 'YOUR ADID',
317
- // isTesting: true
318
- // npa: true
319
- // immersiveMode: true
320
- };
321
- await AdMob.prepareInterstitial(options);
322
- await AdMob.showInterstitial();
323
-
324
- // You can also prepare multiple interstitials and show a specific one by passing its adId:
325
- await AdMob.prepareInterstitial({ adId: 'ca-app-pub-xxx/interstitial-1' });
326
- await AdMob.prepareInterstitial({ adId: 'ca-app-pub-xxx/interstitial-2' });
327
-
328
- // Show a specific prepared ad
329
- await AdMob.showInterstitial({ adId: 'ca-app-pub-xxx/interstitial-1' });
330
-
331
- // Or omit adId to show the most recently prepared one (default behavior)
332
- await AdMob.showInterstitial();
333
- }
334
- ```
335
-
336
- ### Show RewardVideo
337
-
338
- ```ts
339
- import {
340
- AdMob,
341
- RewardAdOptions,
342
- AdLoadInfo,
343
- RewardAdPluginEvents,
344
- AdMobRewardItem,
345
- } from '@capacitor-community/admob';
346
-
347
- export async function rewardVideo(): Promise<void> {
348
- AdMob.addListener(RewardAdPluginEvents.Loaded, (info: AdLoadInfo) => {
349
- // Subscribe prepared rewardVideo
350
- });
351
-
352
- AdMob.addListener(
353
- RewardAdPluginEvents.Rewarded,
354
- (rewardItem: AdMobRewardItem) => {
355
- // Subscribe user rewarded
356
- console.log(rewardItem);
357
- },
358
- );
359
-
360
- const options: RewardAdOptions = {
361
- adId: 'YOUR ADID',
362
- // isTesting: true
363
- // npa: true
364
- // immersiveMode: true
365
- // ssv: {
366
- // userId: "A user ID to send to your SSV"
367
- // customData: JSON.stringify({ ...MyCustomData })
368
- //}
369
168
  };
370
- await AdMob.prepareRewardVideoAd(options);
371
- const rewardItem = await AdMob.showRewardVideoAd();
372
-
373
- // You can also prepare multiple reward ads and show a specific one by passing its adId:
374
- await AdMob.prepareRewardVideoAd({ adId: 'ca-app-pub-xxx/reward-1' });
375
- await AdMob.prepareRewardVideoAd({ adId: 'ca-app-pub-xxx/reward-2' });
376
-
377
- // Show a specific prepared ad
378
- const reward = await AdMob.showRewardVideoAd({ adId: 'ca-app-pub-xxx/reward-1' });
379
-
380
- // Or omit adId to show the most recently prepared one (default behavior)
381
- const reward2 = await AdMob.showRewardVideoAd();
169
+ await AdMob.showBanner(options);
382
170
  }
383
171
  ```
384
172
 
385
- ### Show Rewarded Interstitial
173
+ Expected result: when `canRequestAds` is true, a Google test banner appears at the bottom of the native screen. When `canRequestAds` is false, the function returns and no banner is shown. The banner sits above the WebView and can cover HTML—see [Banner Ads](https://docs.rdlabo.dev/projects/capacitor-admob/docs/banner) to inset your layout. Details: [Configuration](https://docs.rdlabo.dev/projects/capacitor-admob/docs/configuration), [Consent](https://docs.rdlabo.dev/projects/capacitor-admob/docs/consent), and [Testing](https://docs.rdlabo.dev/projects/capacitor-admob/docs/testing).
386
174
 
387
- ```ts
388
- import { AdMob, RewardInterstitialAdOptions } from '@capacitor-community/admob';
175
+ ## Choose by advertising goal
389
176
 
390
- export async function rewardInterstitial(): Promise<void> {
391
- const options: RewardInterstitialAdOptions = {
392
- adId: 'YOUR ADID',
393
- };
394
- const { adUnitId } = await AdMob.prepareRewardInterstitialAd(options);
395
- await AdMob.showRewardInterstitialAd({ adId: adUnitId });
396
- }
397
- ```
177
+ | Goal | Ad format | Guide |
178
+ | ----------------------------------------------------------------- | ------------------------- | ------------------------------------------ |
179
+ | Keep an ad visible alongside app content | Banner | [Banner Ads](https://docs.rdlabo.dev/projects/capacitor-admob/docs/banner) |
180
+ | Show a full-screen ad at a natural break without granting a reward | Interstitial | [Interstitial Ads](https://docs.rdlabo.dev/projects/capacitor-admob/docs/interstitial) |
181
+ | Offer a dedicated rewarded experience | Rewarded | [Rewarded Ads](https://docs.rdlabo.dev/projects/capacitor-admob/docs/rewarded) |
182
+ | Offer a reward at a natural transition | Rewarded interstitial | [Rewarded Ads](https://docs.rdlabo.dev/projects/capacitor-admob/docs/rewarded) |
183
+ | Monetize an app-open experience | App Open | [App Open Ads](https://docs.rdlabo.dev/projects/capacitor-admob/docs/app-open) |
398
184
 
399
- ## Server-side Verification Notice
185
+ ## Documentation
400
186
 
401
- SSV callbacks are only fired on Production Adverts, therefore test Ads will not fire off your SSV callback.
187
+ Start with [Installation](#installation) above, then [Configuration](https://docs.rdlabo.dev/projects/capacitor-admob/docs/configuration) and [Consent](https://docs.rdlabo.dev/projects/capacitor-admob/docs/consent). Run the first test banner, then use [Testing](https://docs.rdlabo.dev/projects/capacitor-admob/docs/testing) for demo units and devices. Pick an ad format from the table above. The same guides are also on the [documentation site](https://docs.rdlabo.dev/projects/capacitor-admob) (English and Japanese). If you opened this README on npm, use that site for the guides — the `docs/` files live in the GitHub repository. Method signatures are in the API section below.
402
188
 
403
- For E2E tests or just for validating the data in your `RewardAdOptions` work as expected, you can add a custom GET
404
- request to your mock endpoint after the `RewardAdPluginEvents.Rewarded` similar to this:
405
-
406
- ```ts
407
- AdMob.addListener(RewardAdPluginEvents.Rewarded, async () => {
408
- // ...
409
- if (ENVIRONMENT_IS_DEVELOPMENT) {
410
- try {
411
- const url =
412
- `https://your-staging-ssv-endpoint` +
413
- new URLSearchParams({
414
- ad_network: 'TEST',
415
- ad_unit: 'TEST',
416
- custom_data: customData, // <-- passed CustomData
417
- reward_amount: 'TEST',
418
- reward_item: 'TEST',
419
- timestamp: 'TEST',
420
- transaction_id: 'TEST',
421
- user_id: userId, // <-- Passed UserID
422
- signature: 'TEST',
423
- key_id: 'TEST',
424
- });
425
- await fetch(url);
426
- } catch (err) {
427
- console.error(err);
428
- }
429
- }
430
- // ...
431
- });
432
- ```
189
+ - [Configuration](https://docs.rdlabo.dev/projects/capacitor-admob/docs/configuration) — `AdMob.initialize` and SDK options.
190
+ - [Consent](https://docs.rdlabo.dev/projects/capacitor-admob/docs/consent) — privacy consent and iOS tracking authorization.
191
+ - [Testing](https://docs.rdlabo.dev/projects/capacitor-admob/docs/testing) — demo ad units, test devices, and consent testing.
192
+ - [Banner Ads](https://docs.rdlabo.dev/projects/capacitor-admob/docs/banner) — banner options, lifecycle, and events.
193
+ - Full-screen ads:
194
+ - [Interstitial Ads](https://docs.rdlabo.dev/projects/capacitor-admob/docs/interstitial) — load, show, and multiple prepared ads.
195
+ - [Rewarded Ads](https://docs.rdlabo.dev/projects/capacitor-admob/docs/rewarded) — rewarded video, rewarded interstitial, and server-side verification.
196
+ - [App Open Ads](https://docs.rdlabo.dev/projects/capacitor-admob/docs/app-open) — load and present on foreground transitions.
197
+ - [Ad Events](https://docs.rdlabo.dev/projects/capacitor-admob/docs/events) — shared lifecycle events, errors, and revenue data.
198
+ - [Migration Guide](https://docs.rdlabo.dev/projects/capacitor-admob/docs/migration) — historical notes when upgrading from older plugin versions.
433
199
 
200
+ <!-- rdlabo-docs-omit -->
434
201
  ## Index
435
202
 
436
203
  <docgen-index>
@@ -474,6 +241,7 @@ AdMob.addListener(RewardAdPluginEvents.Rewarded, async () => {
474
241
  * [`addListener(InterstitialAdPluginEvents.AdImpression, ...)`](#addlistenerinterstitialadplugineventsadimpression-)
475
242
  * [`prepareRewardVideoAd(...)`](#preparerewardvideoad)
476
243
  * [`showRewardVideoAd(...)`](#showrewardvideoad)
244
+ * [`addListener(RewardAdPluginEvents.adClicked, ...)`](#addlistenerrewardadplugineventsadclicked-)
477
245
  * [`addListener(RewardAdPluginEvents.FailedToLoad, ...)`](#addlistenerrewardadplugineventsfailedtoload-)
478
246
  * [`addListener(RewardAdPluginEvents.Loaded, ...)`](#addlistenerrewardadplugineventsloaded-)
479
247
  * [`addListener(RewardAdPluginEvents.Rewarded, ...)`](#addlistenerrewardadplugineventsrewarded-)
@@ -1001,6 +769,9 @@ prepareInterstitial(options: AdOptions) => Promise<AdLoadInfo>
1001
769
 
1002
770
  Loads an interstitial ad and returns the loaded ad unit ID.
1003
771
 
772
+ SDK load failures reject with the native error message and a string `code`.
773
+ Codes are platform-specific; FailedToLoad events expose the same code as a number.
774
+
1004
775
  | Param | Type | Description |
1005
776
  | ------------- | ----------------------------------------------- | ---------------------------------- |
1006
777
  | **`options`** | <code><a href="#adoptions">AdOptions</a></code> | <a href="#adoptions">AdOptions</a> |
@@ -1145,6 +916,9 @@ prepareRewardVideoAd(options: RewardAdOptions) => Promise<AdLoadInfo>
1145
916
 
1146
917
  Loads a rewarded ad and returns the loaded ad unit ID.
1147
918
 
919
+ SDK load failures reject with the native error message and a string `code`.
920
+ Codes are platform-specific; FailedToLoad events expose the same code as a number.
921
+
1148
922
  | Param | Type | Description |
1149
923
  | ------------- | ----------------------------------------------------------- | ---------------------------------------------- |
1150
924
  | **`options`** | <code><a href="#rewardadoptions">RewardAdOptions</a></code> | <a href="#rewardadoptions">RewardAdOptions</a> |
@@ -1175,6 +949,25 @@ Shows a loaded rewarded ad and resolves when the user earns the reward.
1175
949
  --------------------
1176
950
 
1177
951
 
952
+ ### addListener(RewardAdPluginEvents.adClicked, ...)
953
+
954
+ ```typescript
955
+ addListener(eventName: RewardAdPluginEvents.adClicked, listenerFunc: () => void) => Promise<PluginListenerHandle>
956
+ ```
957
+
958
+ Listens for clicks recorded by the rewarded ad SDK, including after a reward is earned.
959
+ A click does not indicate that the user earned a reward.
960
+
961
+ | Param | Type |
962
+ | ------------------ | ------------------------------------------------------------------------------- |
963
+ | **`eventName`** | <code><a href="#rewardadpluginevents">RewardAdPluginEvents.adClicked</a></code> |
964
+ | **`listenerFunc`** | <code>() =&gt; void</code> |
965
+
966
+ **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>
967
+
968
+ --------------------
969
+
970
+
1178
971
  ### addListener(RewardAdPluginEvents.FailedToLoad, ...)
1179
972
 
1180
973
  ```typescript
@@ -1309,6 +1102,9 @@ prepareRewardInterstitialAd(options: RewardInterstitialAdOptions) => Promise<AdL
1309
1102
 
1310
1103
  Loads a rewarded interstitial ad and returns the loaded ad unit ID.
1311
1104
 
1105
+ SDK load failures reject with the native error message and a string `code`.
1106
+ Codes are platform-specific; FailedToLoad events expose the same code as a number.
1107
+
1312
1108
  | Param | Type | Description |
1313
1109
  | ------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
1314
1110
  | **`options`** | <code><a href="#rewardinterstitialadoptions">RewardInterstitialAdOptions</a></code> | <a href="#rewardinterstitialadoptions">RewardInterstitialAdOptions</a> |
@@ -1799,6 +1595,7 @@ From T, pick a set of properties whose keys are in the union K
1799
1595
 
1800
1596
  | Members | Value | Description |
1801
1597
  | ------------------ | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
1598
+ | **`adClicked`** | <code>'onRewardedVideoAdClicked'</code> | Emits when the SDK records a click on a rewarded ad. |
1802
1599
  | **`Loaded`** | <code>'onRewardedVideoAdLoaded'</code> | Emits when a rewarded ad has loaded and is ready to show. |
1803
1600
  | **`FailedToLoad`** | <code>'onRewardedVideoAdFailedToLoad'</code> | Emits when a rewarded ad fails to load. |
1804
1601
  | **`Showed`** | <code>'onRewardedVideoAdShowed'</code> | Emits when a rewarded ad is shown. |
@@ -1822,15 +1619,23 @@ From T, pick a set of properties whose keys are in the union K
1822
1619
 
1823
1620
  </docgen-api>
1824
1621
 
1825
- ## TROUBLE SHOOTING
1622
+ ## Prerelease channels
1623
+
1624
+ An open, non-draft pull request can be published to the npm `beta` dist-tag after its `Validation` and `Package Candidate` workflows pass. A repository owner or maintainer must add a comment whose entire body is:
1625
+
1626
+ ```text
1627
+ /beta
1628
+ ```
1629
+
1630
+ The request authorizes only the pull request head SHA that existed when the comment was added. The workflow revalidates the owner or maintainer permission and head SHA immediately before publishing. Any new commit requires CI to pass again and a fresh owner or maintainer `/beta` comment. Fork pull requests are supported. Pull requests that change a release-gating workflow cannot be beta-published until those workflow changes land on `main`.
1826
1631
 
1827
- ### If you have error:
1632
+ Beta versions use `<base>-beta.pr<PR number>.sha<12-character SHA>`. The candidate is built in a read-only workflow without npm publishing credentials. The privileged release workflow publishes only the validated immutable package artifact with lifecycle scripts disabled. A notification failure cannot invalidate a successful npm publish.
1828
1633
 
1829
- > [error] Error running update: Analyzing dependencies
1830
- > [!] CocoaPods could not find compatible versions for pod "Google-Mobile-Ads-SDK":
1634
+ When a pull request is merged into `main`, it is automatically published to `beta` only after the required CI and `Package Candidate` succeed for that exact merge commit. Direct pushes to `main` do not publish a candidate.
1831
1635
 
1832
- You should run `pod repo update` ;
1636
+ Only `npm run release` creates a release tag. Stable `vX.Y.Z` tags publish to npm `latest`; revision/prerelease tags publish to `next`. Neither `beta` nor `next` publishing changes the npm `latest` dist-tag.
1833
1637
 
1834
1638
  ## License
1835
1639
 
1836
1640
  Capacitor AdMob is [MIT licensed](./LICENSE).
1641
+ <!-- /rdlabo-docs-omit -->
@@ -37,7 +37,7 @@ android {
37
37
  buildTypes {
38
38
  release {
39
39
  minifyEnabled false
40
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
40
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
41
41
  }
42
42
  }
43
43
  lintOptions {
@@ -103,8 +103,15 @@ public class AdMob extends Plugin {
103
103
  public void onInitializationComplete(InitializationStatus initializationStatus) {}
104
104
  }
105
105
  );
106
- bannerExecutor.initialize();
107
- call.resolve();
106
+ // Resolve only once the banner parent actually exists, so a resolved
107
+ // initialize() means what callers already read it as. See #451.
108
+ bannerExecutor.awaitViewGroup((found) -> {
109
+ if (found) {
110
+ call.resolve();
111
+ } else {
112
+ call.reject("AdMob initialized, but the banner parent view never appeared");
113
+ }
114
+ });
108
115
  } catch (Exception ex) {
109
116
  call.reject(ex.getLocalizedMessage(), ex);
110
117
  }
@@ -185,7 +192,10 @@ public class AdMob extends Plugin {
185
192
 
186
193
  @PluginMethod
187
194
  public void showBanner(final PluginCall call) {
188
- bannerExecutor.showBanner(call);
195
+ boolean systemBarsHandlesInsets = !"disable".equals(
196
+ getBridge().getConfig().getPluginConfiguration("SystemBars").getString("insetsHandling", "css")
197
+ );
198
+ bannerExecutor.showBanner(call, systemBarsHandlesInsets);
189
199
  }
190
200
 
191
201
  @PluginMethod