Skip to content
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
4f9ea4f
rebase main
yarivgdidi Mar 19, 2026
ce515c3
Update src/web.ts
BETOXL Oct 13, 2025
2cb85f3
Update src/web.ts
BETOXL Oct 13, 2025
8a46c8a
Update demo/angular/src/app/app.component.ts
BETOXL Oct 13, 2025
79654eb
Update README.md
BETOXL Oct 13, 2025
540573c
Update README.md
BETOXL Oct 14, 2025
8c8d6f9
Update README.md
BETOXL Oct 14, 2025
544528f
Update AppOpenAdManager.java
BETOXL Oct 14, 2025
538cc30
Update AppOpenAdManager.java
BETOXL Oct 14, 2025
cd21f66
Update AppOpenAdManager.java
BETOXL Oct 14, 2025
88df068
Update AdMob.java
BETOXL Oct 14, 2025
cb76260
Update app.component.ts
BETOXL Oct 14, 2025
4a8071e
Update AppOpenAdManager.swift
BETOXL Oct 14, 2025
ff7f28f
Update app-open-definitions.interface.ts
BETOXL Oct 14, 2025
8be2121
Update web.ts
BETOXL Oct 14, 2025
8cbc810
Update README.md
BETOXL Oct 14, 2025
2377c8f
Refactor AppOpenAd Plugin initialization
BETOXL Oct 25, 2025
31ac6e5
Define AppOpenAdOptions interface and update loadAppOpen
BETOXL Oct 25, 2025
088fe10
Update AppOpenAdManager.java
BETOXL Oct 27, 2025
13b0992
Update android/src/main/java/com/getcapacitor/community/admob/appopen…
BETOXL Dec 4, 2025
0d64991
Update src/web.ts
BETOXL Dec 4, 2025
2a2fc5e
Update README.md
BETOXL Dec 4, 2025
b42a565
Update demo/angular/src/app/app.component.ts
BETOXL Dec 4, 2025
7564a9b
Update README.md
BETOXL Dec 4, 2025
8ec3d1b
Update README.md
BETOXL Dec 4, 2025
f925ea0
Update demo/angular/src/app/app.component.ts
BETOXL Dec 4, 2025
c1c19ce
Fix App Open ad lifecycle, event emission, and docs across Android/iOS
yarivgdidi Mar 19, 2026
9b08fdf
GoogleMobileAds fixes
yarivgdidi Mar 21, 2026
066e0ff
GoogleMobileAds fixes
yarivgdidi Mar 21, 2026
264d75e
GoogleMobileAds fixes
yarivgdidi Mar 21, 2026
e397821
GoogleMobileAds fixes
yarivgdidi Mar 21, 2026
6e84322
fix: address all PR review comments
yarivgdidi Apr 7, 2026
b8600b2
fix: address second round of Copilot review comments
yarivgdidi Apr 8, 2026
e3a0b3e
fix: use events enum and bubble errors per reviewer feedback
yarivgdidi Apr 8, 2026
53bbcd7
fix: address reviewer feedback - demo app and screenshots
yarivgdidi Apr 8, 2026
ff6eea6
fix: typed listener overloads, isAdLoaded check, remove unused factory
yarivgdidi Apr 8, 2026
0e4f79b
fix: error params in README examples, remove unused rootViewController
yarivgdidi Apr 9, 2026
03966b4
fix: consistency improvements from self-review
yarivgdidi Apr 9, 2026
182330b
fix: restore createAppOpenOptions factory method and tests
yarivgdidi Apr 9, 2026
a3fe7e3
refactor: convert AppOpenAdPlugin and AppOpenAdManager from Java to K…
yarivgdidi Apr 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 125 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,44 @@ const consentInfo = await AdMob.requestConsentInfo({
2. AdMob.requestConsentInfo
3. AdMob.showConsentForm (If consent form required )
3/ AdMob.showBanner

### Show App Open Ad

```ts
import {
AdMob,
AppOpenAdPluginEvents,
AppOpenAdOptions,
} from '@capacitor-community/admob';

export async function showAppOpenAd(): Promise<void> {
// listen to events
AdMob.addListener(AppOpenAdPluginEvents.Loaded, () => {
console.log('App Open Ad loaded');
});
AdMob.addListener(AppOpenAdPluginEvents.FailedToLoad, () => {
console.log('Failed to load App Open Ad');
});
AdMob.addListener(AppOpenAdPluginEvents.Opened, () => {
console.log('App Open Ad open');
});
AdMob.addListener(AppOpenAdPluginEvents.Closed, () => {
console.log('App Open Ad close');
});
AdMob.addListener(AppOpenAdPluginEvents.FailedToShow, () => {
console.log('Failed to show App Open Ad');
});

const options: AppOpenAdOptions = {
adId: 'YOUR_AD_UNIT_ID',
};
await AdMob.loadAppOpen(options);
const { value } = await AdMob.isAppOpenLoaded();
if (value) {
await AdMob.showAppOpen();
}
}
```
### Show Banner

```ts
Expand Down Expand Up @@ -334,6 +371,10 @@ AdMob.addListener(RewardAdPluginEvents.Rewarded, async () => {
* [`requestTrackingAuthorization()`](#requesttrackingauthorization)
* [`setApplicationMuted(...)`](#setapplicationmuted)
* [`setApplicationVolume(...)`](#setapplicationvolume)
* [`loadAppOpen(...)`](#loadappopen)
* [`showAppOpen()`](#showappopen)
* [`isAppOpenLoaded()`](#isappopenloaded)
* [`addListener(AppOpenAdPluginEvents, ...)`](#addlistenerappopenadpluginevents-)
* [`showBanner(...)`](#showbanner)
* [`hideBanner()`](#hidebanner)
* [`resumeBanner()`](#resumebanner)
Expand Down Expand Up @@ -461,6 +502,63 @@ Report application volume to AdMob SDK
--------------------


### loadAppOpen(...)

```typescript
loadAppOpen(options: AppOpenAdOptions) => Promise<void>
```

Load an App Open ad

| Param | Type |
| ------------- | ------------------------------------------------------------- |
| **`options`** | <code><a href="#appopenadoptions">AppOpenAdOptions</a></code> |

--------------------


### showAppOpen()

```typescript
showAppOpen() => Promise<void>
```

Shows the App Open ad if loaded

--------------------


### isAppOpenLoaded()

```typescript
isAppOpenLoaded() => Promise<{ value: boolean; }>
```

Check if the App Open ad is loaded

**Returns:** <code>Promise&lt;{ value: boolean; }&gt;</code>

--------------------


### addListener(AppOpenAdPluginEvents, ...)

```typescript
addListener(eventName: AppOpenAdPluginEvents, listenerFunc: (...args: any[]) => void) => Promise<PluginListenerHandle>
```

Add listeners for App Open events

| Param | Type |
| ------------------ | ----------------------------------------------------------------------- |
| **`eventName`** | <code><a href="#appopenadpluginevents">AppOpenAdPluginEvents</a></code> |
| **`listenerFunc`** | <code>(...args: any[]) =&gt; void</code> |

**Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>

--------------------


### showBanner(...)

```typescript
Expand Down Expand Up @@ -1102,6 +1200,20 @@ addListener(eventName: RewardInterstitialAdPluginEvents.Showed, listenerFunc: ()
| **`volume`** | <code>0 \| 1 \| 0.1 \| 0.2 \| 0.3 \| 0.4 \| 0.5 \| 0.6 \| 0.7 \| 0.8 \| 0.9</code> | If your app has its own volume controls (such as custom music or sound effect volumes), disclosing app volume to the Google Mobile Ads SDK allows video ads to respect app volume settings. enable set 0.0 - 1.0, any float allowed. | 4.1.1 |


#### AppOpenAdOptions

| Prop | Type |
| ---------- | ------------------- |
| **`adId`** | <code>string</code> |


#### PluginListenerHandle

| Prop | Type |
| ------------ | ----------------------------------------- |
| **`remove`** | <code>() =&gt; Promise&lt;void&gt;</code> |


#### BannerAdOptions

This interface extends <a href="#adoptions">AdOptions</a>
Expand All @@ -1117,13 +1229,6 @@ This interface extends <a href="#adoptions">AdOptions</a>
| **`immersiveMode`** | <code>boolean</code> | Sets a flag that controls if this interstitial or reward object will be displayed in immersive mode. Call this method before show. During show, if this flag is on and immersive mode is supported, SYSTEM_UI_FLAG_IMMERSIVE_STICKY &SYSTEM_UI_FLAG_HIDE_NAVIGATION will be turned on for interstitial or reward ad. | | 7.0.3 |


#### PluginListenerHandle

| Prop | Type |
| ------------ | ----------------------------------------- |
| **`remove`** | <code>() =&gt; Promise&lt;void&gt;</code> |


#### AdMobBannerSize

When notice listener of OnAdLoaded, you can get banner size.
Expand All @@ -1136,7 +1241,7 @@ When notice listener of OnAdLoaded, you can get banner size.

#### AdMobError

For more information
For more information
https://developers.google.com/android/reference/com/google/android/gms/ads/AdError

| Prop | Type | Description |
Expand Down Expand Up @@ -1196,7 +1301,7 @@ https://developers.google.com/android/reference/com/google/android/gms/ads/AdErr

#### AdMobRewardItem

For more information
For more information
https://developers.google.com/admob/android/rewarded-video-adapters?hl=en

| Prop | Type | Description |
Expand Down Expand Up @@ -1256,6 +1361,17 @@ From T, pick a set of properties whose keys are in the union K
| **`MatureAudience`** | <code>'MatureAudience'</code> | Content suitable only for mature audiences. |


#### AppOpenAdPluginEvents

| Members | Value |
| ------------------ | ------------------------------------ |
| **`Loaded`** | <code>'appOpenAdLoaded'</code> |
| **`FailedToLoad`** | <code>'appOpenAdFailedToLoad'</code> |
| **`Opened`** | <code>'appOpenAdOpened'</code> |
| **`Closed`** | <code>'appOpenAdClosed'</code> |
| **`FailedToShow`** | <code>'appOpenAdFailedToShow'</code> |


#### BannerAdSize

| Members | Value | Description |
Expand Down
96 changes: 73 additions & 23 deletions android/src/main/java/com/getcapacitor/community/admob/AdMob.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.getcapacitor.community.admob;

import android.Manifest;
import android.app.Activity;
import android.os.Handler;
import android.os.Looper;
import com.getcapacitor.JSArray;
import com.getcapacitor.JSObject;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.getcapacitor.annotation.Permission;
import com.getcapacitor.community.admob.appopen.AppOpenAdPlugin;
import com.getcapacitor.community.admob.banner.BannerExecutor;
import com.getcapacitor.community.admob.consent.AdConsentExecutor;
import com.getcapacitor.community.admob.helpers.AuthorizationStatusEnum;
Expand All @@ -34,18 +38,21 @@ public class AdMob extends Plugin {
this::notifyListeners,
getLogTag()
);

private final AdRewardExecutor adRewardExecutor = new AdRewardExecutor(
this::getContext,
this::getActivity,
this::notifyListeners,
getLogTag()
);

private final AdRewardInterstitialExecutor adRewardInterstitialExecutor = new AdRewardInterstitialExecutor(
this::getContext,
this::getActivity,
this::notifyListeners,
getLogTag()
);

private final AdInterstitialExecutor adInterstitialExecutor = new AdInterstitialExecutor(
this::getContext,
this::getActivity,
Expand All @@ -61,23 +68,52 @@ public class AdMob extends Plugin {
getLogTag()
);

// Initialize AdMob with appId
private final AppOpenAdPlugin appOpenAdPlugin = new AppOpenAdPlugin();

@PluginMethod
public void loadAppOpen(final PluginCall call) {
appOpenAdPlugin.loadAppOpen(getContext(), getActivity(), call, this::notifyListeners);
}

@PluginMethod
public void showAppOpen(final PluginCall call) {
appOpenAdPlugin.showAppOpen(getActivity(), call, this::notifyListeners);
}

@PluginMethod
public void isAppOpenLoaded(final PluginCall call) {
appOpenAdPlugin.isAppOpenLoaded(getActivity(), call);
}

// ---------------------------------------------------------
// MAIN METHODS
// ---------------------------------------------------------

@PluginMethod
public void initialize(final PluginCall call) {
this.setRequestConfiguration(call);

try {
MobileAds.initialize(
getContext(),
new OnInitializationCompleteListener() {
@Override
public void onInitializationComplete(InitializationStatus initializationStatus) {}
}
);
bannerExecutor.initialize();
call.resolve();
} catch (Exception ex) {
call.reject(ex.getLocalizedMessage(), ex);
// Same as banner/interstitial: bridge thread is not the UI thread — MobileAds + view setup must run on main.
Runnable initOnMain = () -> {
try {
MobileAds.initialize(
getContext(),
new OnInitializationCompleteListener() {
@Override
public void onInitializationComplete(InitializationStatus initializationStatus) {}
}
);
bannerExecutor.initialize();
call.resolve();
} catch (Exception ex) {
call.reject(ex.getLocalizedMessage(), ex);
}
};
Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(initOnMain);
} else {
new Handler(Looper.getMainLooper()).post(initOnMain);
}
}

Expand All @@ -93,7 +129,10 @@ public void trackingAuthorizationStatus(final PluginCall call) {
call.resolve(response);
}

// User Consent
// ---------------------------------------------------------
// USER CONSENT
// ---------------------------------------------------------

@PluginMethod
public void requestConsentInfo(final PluginCall call) {
adConsentExecutor.requestConsentInfo(call, this::notifyListeners);
Expand All @@ -114,6 +153,10 @@ public void resetConsentInfo(final PluginCall call) {
adConsentExecutor.resetConsentInfo(call, this::notifyListeners);
}

// ---------------------------------------------------------
// APP SETTINGS
// ---------------------------------------------------------

@PluginMethod
public void setApplicationMuted(final PluginCall call) {
Boolean muted = call.getBoolean("muted");
Expand All @@ -136,41 +179,48 @@ public void setApplicationVolume(final PluginCall call) {
call.resolve();
}

// Show a banner Ad
// ---------------------------------------------------------
// BANNER ADS
// ---------------------------------------------------------

@PluginMethod
public void showBanner(final PluginCall call) {
bannerExecutor.showBanner(call);
}

// Hide the banner, remove it from screen, but can show it later
@PluginMethod
public void hideBanner(final PluginCall call) {
bannerExecutor.hideBanner(call);
}

// Resume the banner, show it after hide
@PluginMethod
public void resumeBanner(final PluginCall call) {
bannerExecutor.resumeBanner(call);
}

// Destroy the banner, remove it from screen.
@PluginMethod
public void removeBanner(final PluginCall call) {
bannerExecutor.removeBanner(call);
}

// ---------------------------------------------------------
// INTERSTITIAL ADS
// ---------------------------------------------------------

@PluginMethod
public void prepareInterstitial(final PluginCall call) {
adInterstitialExecutor.prepareInterstitial(call, this::notifyListeners);
}

// Show interstitial Ad
@PluginMethod
public void showInterstitial(final PluginCall call) {
adInterstitialExecutor.showInterstitial(call, this::notifyListeners);
}

// ---------------------------------------------------------
// REWARDED ADS
// ---------------------------------------------------------

@PluginMethod
public void prepareRewardVideoAd(final PluginCall call) {
adRewardExecutor.prepareRewardVideoAd(call, this::notifyListeners);
Expand All @@ -191,10 +241,10 @@ public void showRewardInterstitialAd(final PluginCall call) {
adRewardInterstitialExecutor.showRewardInterstitialAd(call, this::notifyListeners);
}

/**
* @see <a href="https://developers.google.com/admob/android/test-ads#enable_test_devices">Test Devices</a>
* @see <a href="https://developers.google.com/admob/android/targeting">Target Settings</a>
*/
// ---------------------------------------------------------
// REQUEST CONFIGURATION
// ---------------------------------------------------------

private void setRequestConfiguration(final PluginCall call) {
// Testing Devices
final boolean initializeForTesting = call.getBoolean("initializeForTesting", false);
Expand Down
Loading
Loading