├── .husky └── pre-commit ├── demo ├── angular │ ├── src │ │ ├── app │ │ │ ├── app.component.scss │ │ │ ├── validation │ │ │ │ ├── tab1 │ │ │ │ │ ├── tab1.page.scss │ │ │ │ │ ├── tab1.module.ts │ │ │ │ │ ├── tab1-routing.module.ts │ │ │ │ │ └── tab1.page.html │ │ │ │ ├── tab2 │ │ │ │ │ ├── tab2.page.scss │ │ │ │ │ ├── tab2.module.ts │ │ │ │ │ ├── tab2-routing.module.ts │ │ │ │ │ ├── tab2.page.html │ │ │ │ │ └── tab2.page.ts │ │ │ │ ├── tab3 │ │ │ │ │ ├── tab3.page.scss │ │ │ │ │ ├── tab3-routing.module.ts │ │ │ │ │ ├── tab3.module.ts │ │ │ │ │ ├── tab3.page.html │ │ │ │ │ └── tab3.page.ts │ │ │ │ └── tabs │ │ │ │ │ ├── tabs.page.scss │ │ │ │ │ ├── tabs.module.ts │ │ │ │ │ ├── tabs.page.ts │ │ │ │ │ ├── tabs.page.html │ │ │ │ │ └── tabs-routing.module.ts │ │ │ ├── app.component.html │ │ │ ├── shared │ │ │ │ ├── interfaces.ts │ │ │ │ ├── ad.options.ts │ │ │ │ └── helper.service.ts │ │ │ ├── home │ │ │ │ ├── home.module.ts │ │ │ │ ├── home-routing.module.ts │ │ │ │ ├── home.page.scss │ │ │ │ └── home.page.html │ │ │ ├── app-routing.module.ts │ │ │ └── app.component.ts │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── assets │ │ │ ├── icon │ │ │ │ └── favicon.png │ │ │ └── shapes.svg │ │ ├── test.ts │ │ ├── zone-flags.ts │ │ ├── index.html │ │ ├── main.ts │ │ ├── global.scss │ │ └── polyfills.ts │ ├── ios │ │ ├── debug.xcconfig │ │ ├── App │ │ │ ├── CapApp-SPM │ │ │ │ ├── Sources │ │ │ │ │ └── CapApp-SPM │ │ │ │ │ │ └── CapApp-SPM.swift │ │ │ │ ├── README.md │ │ │ │ ├── .gitignore │ │ │ │ └── Package.swift │ │ │ ├── App │ │ │ │ ├── Assets.xcassets │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── AppIcon.appiconset │ │ │ │ │ │ ├── AppIcon-512@2x.png │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Splash.imageset │ │ │ │ │ │ ├── splash-2732x2732.png │ │ │ │ │ │ ├── splash-2732x2732-1.png │ │ │ │ │ │ ├── splash-2732x2732-2.png │ │ │ │ │ │ └── Contents.json │ │ │ │ ├── config.xml │ │ │ │ ├── capacitor.config.json │ │ │ │ ├── Base.lproj │ │ │ │ │ ├── Main.storyboard │ │ │ │ │ └── LaunchScreen.storyboard │ │ │ │ ├── Info.plist │ │ │ │ └── AppDelegate.swift │ │ │ └── App.xcodeproj │ │ │ │ └── project.xcworkspace │ │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── swiftpm │ │ │ │ └── Package.resolved │ │ └── .gitignore │ ├── android │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── src │ │ │ │ ├── main │ │ │ │ │ ├── res │ │ │ │ │ │ ├── drawable │ │ │ │ │ │ │ └── splash.png │ │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ │ ├── drawable-land-hdpi │ │ │ │ │ │ │ └── splash.png │ │ │ │ │ │ ├── drawable-land-mdpi │ │ │ │ │ │ │ └── splash.png │ │ │ │ │ │ ├── drawable-land-xhdpi │ │ │ │ │ │ │ └── splash.png │ │ │ │ │ │ ├── drawable-port-hdpi │ │ │ │ │ │ │ └── splash.png │ │ │ │ │ │ ├── drawable-port-mdpi │ │ │ │ │ │ │ └── splash.png │ │ │ │ │ │ ├── drawable-port-xhdpi │ │ │ │ │ │ │ └── splash.png │ │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ │ ├── drawable-land-xxhdpi │ │ │ │ │ │ │ └── splash.png │ │ │ │ │ │ ├── drawable-land-xxxhdpi │ │ │ │ │ │ │ └── splash.png │ │ │ │ │ │ ├── drawable-port-xxhdpi │ │ │ │ │ │ │ └── splash.png │ │ │ │ │ │ ├── drawable-port-xxxhdpi │ │ │ │ │ │ │ └── splash.png │ │ │ │ │ │ ├── values │ │ │ │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ │ │ │ ├── strings.xml │ │ │ │ │ │ │ └── styles.xml │ │ │ │ │ │ ├── xml │ │ │ │ │ │ │ ├── config.xml │ │ │ │ │ │ │ └── file_paths.xml │ │ │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ │ │ │ ├── ic_launcher.xml │ │ │ │ │ │ │ └── ic_launcher_round.xml │ │ │ │ │ │ ├── layout │ │ │ │ │ │ │ └── activity_main.xml │ │ │ │ │ │ └── drawable-v24 │ │ │ │ │ │ │ └── ic_launcher_foreground.xml │ │ │ │ │ ├── assets │ │ │ │ │ │ ├── capacitor.plugins.json │ │ │ │ │ │ └── capacitor.config.json │ │ │ │ │ ├── java │ │ │ │ │ │ └── io │ │ │ │ │ │ │ └── ionic │ │ │ │ │ │ │ └── starter │ │ │ │ │ │ │ └── MainActivity.java │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ ├── test │ │ │ │ │ └── java │ │ │ │ │ │ └── com │ │ │ │ │ │ └── getcapacitor │ │ │ │ │ │ └── myapp │ │ │ │ │ │ └── ExampleUnitTest.java │ │ │ │ └── androidTest │ │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── getcapacitor │ │ │ │ │ └── myapp │ │ │ │ │ └── ExampleInstrumentedTest.java │ │ │ ├── capacitor.build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── build.gradle │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── settings.gradle │ │ ├── capacitor.settings.gradle │ │ ├── variables.gradle │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── .gitignore │ │ └── gradlew.bat │ ├── ionic.config.json │ ├── capacitor.config.json │ ├── e2e │ │ ├── src │ │ │ ├── app.po.ts │ │ │ └── app.e2e-spec.ts │ │ ├── tsconfig.json │ │ └── protractor.conf.js │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ ├── browserslist │ ├── .gitignore │ ├── tsconfig.json │ ├── karma.conf.js │ ├── eslint.config.js │ └── package.json └── screenshots │ ├── ios_banner.png │ ├── ios_reward.png │ ├── md_banner.png │ ├── md_reward.png │ ├── md_interstitial.png │ └── ios_interstitial.png ├── src ├── shared │ ├── ad-load-info.interface.ts │ ├── index.ts │ ├── tracking-authorization-status.interface.ts │ ├── admob-error.interface.ts │ └── ad-options.interface.ts ├── interstitial │ ├── index.ts │ ├── interstitial-ad-plugin-events.enum.ts │ └── interstitial-definitions.interface.ts ├── banner │ ├── banner-size.interface.ts │ ├── index.ts │ ├── banner-ad-position.enum.ts │ ├── banner-ad-plugin-events.enum.ts │ ├── banner-ad-options.interface.ts │ ├── banner-ad-size.enum.ts │ └── banner-definitions.interface.ts ├── reward │ ├── index.ts │ ├── reward-item.interface.ts │ ├── reward-ad-options.interface.ts │ ├── reward-ad-plugin-events.enum.ts │ └── reward-definitions.interface.ts ├── consent │ ├── index.ts │ ├── privacy-options-requirement-status.enum.ts │ ├── consent-status.enum.ts │ ├── consent-request-options.interface.ts │ ├── consent-debug-geography.enum.ts │ ├── consent-info.interface.ts │ └── consent-definition.interface.ts ├── reward-interstitial │ ├── index.ts │ ├── reward-interstitial-item.interface.ts │ ├── reward-interstitial-ad-options.interface.ts │ ├── reward-interstitial-ad-plugin-events.enum.ts │ └── reward-interstitial-definitions.interface.ts ├── index.ts └── private │ └── validate-all-events-implemented.type.ts ├── .github ├── CODEOWNERS ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── CODE_OF_CONDUCT.md └── workflows │ ├── release.yml │ └── validation.yml ├── android ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── settings.gradle ├── .npmignore ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── getcapacitor │ │ │ │ └── community │ │ │ │ └── admob │ │ │ │ ├── helpers │ │ │ │ ├── AuthorizationStatusEnum.kt │ │ │ │ ├── AdViewIdHelper.java │ │ │ │ ├── FullscreenPluginCallback.kt │ │ │ │ └── RequestHelper.java │ │ │ │ ├── models │ │ │ │ ├── LoadPluginEventNames.kt │ │ │ │ ├── AdMobPluginError.kt │ │ │ │ └── Executor.java │ │ │ │ ├── banner │ │ │ │ ├── BannerAdPluginEvents.kt │ │ │ │ ├── BannerAdSizeEnum.kt │ │ │ │ └── BannerAdSizeInfo.kt │ │ │ │ ├── interstitial │ │ │ │ ├── InterstitialAdPluginPluginEvent.kt │ │ │ │ ├── InterstitialAdCallbackAndListeners.kt │ │ │ │ └── AdInterstitialExecutor.java │ │ │ │ ├── rewarded │ │ │ │ ├── RewardAdPluginEvents.kt │ │ │ │ ├── models │ │ │ │ │ └── SsvInfo.kt │ │ │ │ ├── RewardedAdCallbackAndListeners.kt │ │ │ │ └── AdRewardExecutor.java │ │ │ │ └── rewardedinterstitial │ │ │ │ ├── models │ │ │ │ └── SsvInfo.kt │ │ │ │ ├── RewardInterstitialAdPluginEvents.kt │ │ │ │ ├── RewardedInterstitialAdCallbackAndListeners.kt │ │ │ │ └── AdRewardInterstitialExecutor.java │ │ └── AndroidManifest.xml │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── getcapacitor │ │ │ └── android │ │ │ └── ExampleInstrumentedTest.java │ └── test │ │ └── java │ │ └── com │ │ └── getcapacitor │ │ └── community │ │ └── admob │ │ ├── helpers │ │ ├── RequestHelperTest.java │ │ ├── FullscreenPluginCallbackTest.kt │ │ └── AdViewIdHelperTest.java │ │ └── interstitial │ │ └── InterstitialAdStub.kt ├── proguard-rules.pro ├── gradle.properties └── gradlew.bat ├── ios ├── .gitignore ├── Sources │ └── AdMobPlugin │ │ ├── Helper │ │ └── AuthorizationStatusEnum.swift │ │ ├── Banner │ │ ├── BannerAdPluginEvents.swift │ │ └── BannerAdSizeEnum.swift │ │ ├── Interstitial │ │ ├── InterstitialAdPluginEvents.swift │ │ └── AdInterstitialExecutor.swift │ │ ├── Rewarded │ │ ├── RewardAdPluginEvents.swift │ │ └── AdRewardExecutor.swift │ │ ├── RewardedInterstitial │ │ └── RewardInterstitialAdPluginEvents.swift │ │ └── Models │ │ └── FullScreenAdEventName.swift └── Tests │ └── AdMobPluginTests │ └── AdMobPluginTests.swift ├── tsconfig.json ├── rollup.config.mjs ├── CapacitorCommunityAdmob.podspec ├── Package.resolved ├── LICENSE ├── .gitignore ├── Package.swift ├── CONTRIBUTING.md ├── .cursor └── rules │ └── angular-default.mdc ├── BREAKING.md └── package.json /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /demo/angular/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab1/tab1.page.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab2/tab2.page.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab3/tab3.page.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/angular/ios/debug.xcconfig: -------------------------------------------------------------------------------- 1 | CAPACITOR_DEBUG = true 2 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tabs/tabs.page.scss: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /demo/angular/android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build/* 2 | !/build/.npmkeep 3 | -------------------------------------------------------------------------------- /src/shared/ad-load-info.interface.ts: -------------------------------------------------------------------------------- 1 | export interface AdLoadInfo { 2 | adUnitId: string 3 | } -------------------------------------------------------------------------------- /demo/angular/ios/App/CapApp-SPM/Sources/CapApp-SPM/CapApp-SPM.swift: -------------------------------------------------------------------------------- 1 | public let isCapacitorApp = true 2 | -------------------------------------------------------------------------------- /demo/angular/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /demo/angular/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /demo/screenshots/ios_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/screenshots/ios_banner.png -------------------------------------------------------------------------------- /demo/screenshots/ios_reward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/screenshots/ios_reward.png -------------------------------------------------------------------------------- /demo/screenshots/md_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/screenshots/md_banner.png -------------------------------------------------------------------------------- /demo/screenshots/md_reward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/screenshots/md_reward.png -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners 2 | -------------------------------------------------------------------------------- /demo/screenshots/md_interstitial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/screenshots/md_interstitial.png -------------------------------------------------------------------------------- /demo/angular/ios/App/App/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /demo/screenshots/ios_interstitial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/screenshots/ios_interstitial.png -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /demo/angular/src/assets/icon/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/src/assets/icon/favicon.png -------------------------------------------------------------------------------- /src/interstitial/index.ts: -------------------------------------------------------------------------------- 1 | export * from './interstitial-ad-plugin-events.enum'; 2 | export * from './interstitial-definitions.interface'; 3 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':capacitor-android' 2 | project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') -------------------------------------------------------------------------------- /demo/angular/ionic.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-app-base", 3 | "integrations": { 4 | "capacitor": {} 5 | }, 6 | "type": "angular" 7 | } 8 | -------------------------------------------------------------------------------- /src/shared/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ad-load-info.interface'; 2 | export * from './ad-options.interface'; 3 | export * from './admob-error.interface'; 4 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributing to this project 3 | 4 | Describe the steps a developer should go through in order to contribute to this project 5 | -------------------------------------------------------------------------------- /demo/angular/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/drawable/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/drawable/splash.png -------------------------------------------------------------------------------- /android/.npmignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/assets/capacitor.plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pkg": "@capacitor-community/admob", 4 | "classpath": "com.getcapacitor.community.admob.AdMob" 5 | } 6 | ] 7 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/drawable-land-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/drawable-land-hdpi/splash.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/drawable-land-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/drawable-land-mdpi/splash.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/drawable-land-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/drawable-land-xhdpi/splash.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/drawable-port-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/drawable-port-hdpi/splash.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/drawable-port-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/drawable-port-mdpi/splash.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/drawable-port-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/drawable-port-xhdpi/splash.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/drawable-land-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/drawable-land-xxhdpi/splash.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/drawable-land-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/drawable-land-xxxhdpi/splash.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/drawable-port-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/drawable-port-xxhdpi/splash.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/drawable-port-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/drawable-port-xxxhdpi/splash.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/angular/src/app/shared/interfaces.ts: -------------------------------------------------------------------------------- 1 | export interface ITestItems { 2 | type: 'method' | 'event' 3 | name: string; 4 | result?: boolean; 5 | expect?: number | string | string[] | number[]; 6 | } 7 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /demo/angular/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png -------------------------------------------------------------------------------- /demo/angular/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png -------------------------------------------------------------------------------- /demo/angular/ios/App/CapApp-SPM/README.md: -------------------------------------------------------------------------------- 1 | # CapApp-SPM 2 | 3 | This SPM is used to host SPM dependencies for you Capacitor project 4 | 5 | Do not modify the contents of it or there may be unintended consequences. 6 | -------------------------------------------------------------------------------- /src/banner/banner-size.interface.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * When notice listener of OnAdLoaded, you can get banner size. 4 | */ 5 | export interface AdMobBannerSize { 6 | width: number; 7 | height: number; 8 | } -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /demo/angular/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png -------------------------------------------------------------------------------- /demo/angular/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/admob/HEAD/demo/angular/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png -------------------------------------------------------------------------------- /src/reward/index.ts: -------------------------------------------------------------------------------- 1 | export * from './reward-ad-plugin-events.enum'; 2 | export * from './reward-definitions.interface'; 3 | export * from './reward-item.interface'; 4 | export * from './reward-ad-options.interface'; 5 | -------------------------------------------------------------------------------- /demo/angular/capacitor.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "appId": "io.ionic.starter", 3 | "appName": "capacitor-admob", 4 | "bundledWebRuntime": false, 5 | "npmClient": "npm", 6 | "webDir": "www/browser", 7 | "cordova": {} 8 | } 9 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/helpers/AuthorizationStatusEnum.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.helpers 2 | 3 | enum class AuthorizationStatusEnum(val status: String) { 4 | AUTHORIZED("authorized"); 5 | } -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/java/io/ionic/starter/MainActivity.java: -------------------------------------------------------------------------------- 1 | package io.ionic.starter; 2 | 3 | import android.os.Bundle; 4 | import com.getcapacitor.BridgeActivity; 5 | 6 | public class MainActivity extends BridgeActivity {} 7 | -------------------------------------------------------------------------------- /demo/angular/ios/App/App/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/assets/capacitor.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "appId": "io.ionic.starter", 3 | "appName": "capacitor-admob", 4 | "bundledWebRuntime": false, 5 | "npmClient": "npm", 6 | "webDir": "www/browser", 7 | "cordova": {} 8 | } 9 | -------------------------------------------------------------------------------- /demo/angular/ios/App/CapApp-SPM/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/config/registries.json 8 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 9 | .netrc 10 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/xml/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo/angular/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | include ':capacitor-cordova-android-plugins' 3 | project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/') 4 | 5 | apply from: 'capacitor.settings.gradle' -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/models/LoadPluginEventNames.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.models 2 | 3 | interface LoadPluginEventNames { 4 | val Showed: String 5 | val FailedToShow: String 6 | val Dismissed: String 7 | } -------------------------------------------------------------------------------- /ios/Sources/AdMobPlugin/Helper/AuthorizationStatusEnum.swift: -------------------------------------------------------------------------------- 1 | public enum AuthorizationStatusEnum: String { 2 | case Authorized = "authorized" 3 | case Denied = "denied" 4 | case NotDetermined = "notDetermined" 5 | case Restricted = "restricted" 6 | } 7 | -------------------------------------------------------------------------------- /src/consent/index.ts: -------------------------------------------------------------------------------- 1 | export * from './consent-status.enum'; 2 | export * from './consent-debug-geography.enum'; 3 | export * from './consent-request-options.interface'; 4 | export * from './consent-info.interface'; 5 | export * from './consent-definition.interface'; 6 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/reward-interstitial/index.ts: -------------------------------------------------------------------------------- 1 | export * from './reward-interstitial-ad-plugin-events.enum'; 2 | export * from './reward-interstitial-definitions.interface'; 3 | export * from './reward-interstitial-item.interface'; 4 | export * from './reward-interstitial-ad-options.interface'; 5 | -------------------------------------------------------------------------------- /demo/angular/ios/.gitignore: -------------------------------------------------------------------------------- 1 | App/build 2 | App/Pods 3 | App/output 4 | App/App/public 5 | DerivedData 6 | xcuserdata 7 | 8 | # Cordova plugins for Capacitor 9 | capacitor-cordova-ios-plugins 10 | 11 | # Generated Config files 12 | App/App/capacitor.config.json 13 | App/App/config.xml 14 | -------------------------------------------------------------------------------- /demo/angular/ios/App/App/capacitor.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "appId": "io.ionic.starter", 3 | "appName": "capacitor-admob", 4 | "bundledWebRuntime": false, 5 | "npmClient": "npm", 6 | "webDir": "www/browser", 7 | "cordova": {}, 8 | "packageClassList": [ 9 | "AdMobPlugin" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /demo/angular/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.deepCss('app-root ion-content')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /demo/angular/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/banner/index.ts: -------------------------------------------------------------------------------- 1 | export * from './banner-ad-options.interface'; 2 | export * from './banner-ad-plugin-events.enum'; 3 | export * from './banner-ad-position.enum'; 4 | export * from './banner-ad-size.enum'; 5 | export * from './banner-definitions.interface'; 6 | export * from './banner-size.interface'; 7 | -------------------------------------------------------------------------------- /src/shared/tracking-authorization-status.interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @url https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus 3 | */ 4 | export interface TrackingAuthorizationStatusInterface { 5 | status: 'authorized' | 'denied' | 'notDetermined' | 'restricted'; 6 | } 7 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /demo/angular/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/angular/ios/App/App.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /demo/angular/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AppIcon-512@2x.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ios/Sources/AdMobPlugin/Banner/BannerAdPluginEvents.swift: -------------------------------------------------------------------------------- 1 | public enum BannerAdPluginEvents: String { 2 | case SizeChanged = "bannerAdSizeChanged" 3 | case Closed = "bannerAdClosed" 4 | case FailedToLoad = "bannerAdFailedToLoad" 5 | case Opened = "bannerAdOpened" 6 | case Loaded = "bannerAdLoaded" 7 | case AdImpression = "bannerAdImpression" 8 | } 9 | -------------------------------------------------------------------------------- /ios/Sources/AdMobPlugin/Interstitial/InterstitialAdPluginEvents.swift: -------------------------------------------------------------------------------- 1 | public enum InterstitialAdPluginEvents: String { 2 | case Loaded = "interstitialAdLoaded" 3 | case FailedToLoad = "interstitialAdFailedToLoad" 4 | case Showed = "interstitialAdShowed" 5 | case FailedToShow = "interstitialAdFailedToShow" 6 | case Dismissed = "interstitialAdDismissed" 7 | } 8 | -------------------------------------------------------------------------------- /src/reward/reward-item.interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * For more information 3 | * https://developers.google.com/admob/android/rewarded-video-adapters?hl=en 4 | */ 5 | export interface AdMobRewardItem { 6 | /** 7 | * Rewarded type user got 8 | */ 9 | type: string; 10 | 11 | /** 12 | * Rewarded amount user got 13 | */ 14 | amount: number; 15 | } -------------------------------------------------------------------------------- /demo/angular/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /demo/angular/android/capacitor.settings.gradle: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN 2 | include ':capacitor-android' 3 | project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') 4 | 5 | include ':capacitor-community-admob' 6 | project(':capacitor-community-admob').projectDir = new File('../../../android') 7 | -------------------------------------------------------------------------------- /demo/angular/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('new App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should be blank', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toContain('Start with Ionic UI Components'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/reward-interstitial/reward-interstitial-item.interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * For more information 3 | * https://developers.google.com/admob/android/rewarded-video-adapters?hl=en 4 | */ 5 | export interface AdMobRewardInterstitialItem { 6 | /** 7 | * Rewarded type user got 8 | */ 9 | type: string; 10 | 11 | /** 12 | * Rewarded amount user got 13 | */ 14 | amount: number; 15 | } 16 | -------------------------------------------------------------------------------- /src/shared/admob-error.interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * For more information 3 | * https://developers.google.com/android/reference/com/google/android/gms/ads/AdError 4 | */ 5 | export interface AdMobError { 6 | /** 7 | * Gets the error's code. 8 | */ 9 | code: number; 10 | 11 | /** 12 | * Gets the message describing the error. 13 | */ 14 | message: string; 15 | } 16 | -------------------------------------------------------------------------------- /demo/angular/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | ], 13 | "include": [ 14 | "src/**/*.spec.ts", 15 | "src/**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /ios/Sources/AdMobPlugin/Rewarded/RewardAdPluginEvents.swift: -------------------------------------------------------------------------------- 1 | public enum RewardAdPluginEvents: String { 2 | case Loaded = "onRewardedVideoAdLoaded" 3 | case FailedToLoad = "onRewardedVideoAdFailedToLoad" 4 | case Showed = "onRewardedVideoAdShowed" 5 | case FailedToShow = "onRewardedVideoAdFailedToShow" 6 | case Dismissed = "onRewardedVideoAdDismissed" 7 | case Rewarded = "onRewardedVideoAdReward" 8 | } 9 | -------------------------------------------------------------------------------- /ios/Sources/AdMobPlugin/Banner/BannerAdSizeEnum.swift: -------------------------------------------------------------------------------- 1 | public enum BannerAdSizeEnum: String { 2 | case BANNER = "BANNER" 3 | case FULL_BANNER = "FULL_BANNER" 4 | case LARGE_BANNER = "LARGE_BANNER" 5 | case LEADERBOARD = "LEADERBOARD" 6 | case MEDIUM_RECTANGLE = "MEDIUM_RECTANGLE" 7 | case WIDE_SKYSCRAPER = "WIDE_SKYSCRAPER" 8 | case ADAPTIVE_BANNER = "ADAPTIVE_BANNER" 9 | // case FLUID = "FLUID" 10 | } 11 | -------------------------------------------------------------------------------- /demo/angular/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | last 3 iOS versions 9 | last 3 ChromeAndroid versions 10 | -------------------------------------------------------------------------------- /demo/angular/src/app/home/home.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HomePage } from './home.page'; 5 | 6 | import { HomePageRoutingModule } from './home-routing.module'; 7 | 8 | @NgModule({ 9 | imports: [CommonModule, FormsModule, HomePageRoutingModule, HomePage], 10 | }) 11 | export class HomePageModule {} 12 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab1/tab1.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { Tab1Page } from './tab1.page'; 5 | 6 | import { Tab1PageRoutingModule } from './tab1-routing.module'; 7 | 8 | @NgModule({ 9 | imports: [CommonModule, FormsModule, Tab1PageRoutingModule, Tab1Page], 10 | }) 11 | export class Tab1PageModule {} 12 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab2/tab2.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { Tab2Page } from './tab2.page'; 5 | 6 | import { Tab2PageRoutingModule } from './tab2-routing.module'; 7 | 8 | @NgModule({ 9 | imports: [CommonModule, FormsModule, Tab2PageRoutingModule, Tab2Page], 10 | }) 11 | export class Tab2PageModule {} 12 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | capacitor-admob 4 | capacitor-admob 5 | io.ionic.starter 6 | io.ionic.starter 7 | ca-app-pub-3940256099942544~3347511713 8 | 9 | -------------------------------------------------------------------------------- /demo/angular/src/app/home/home-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { HomePage } from './home.page'; 4 | 5 | const routes: Routes = [ 6 | { 7 | path: '', 8 | component: HomePage, 9 | }, 10 | ]; 11 | 12 | @NgModule({ 13 | imports: [RouterModule.forChild(routes)], 14 | exports: [RouterModule], 15 | }) 16 | export class HomePageRoutingModule {} 17 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tabs/tabs.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { FormsModule } from '@angular/forms'; 4 | 5 | import { TabsPageRoutingModule } from './tabs-routing.module'; 6 | 7 | import { TabsPage } from './tabs.page'; 8 | 9 | @NgModule({ 10 | imports: [CommonModule, FormsModule, TabsPageRoutingModule, TabsPage], 11 | }) 12 | export class TabsPageModule {} 13 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab1/tab1-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { Tab1Page } from './tab1.page'; 4 | 5 | const routes: Routes = [ 6 | { 7 | path: '', 8 | component: Tab1Page, 9 | }, 10 | ]; 11 | 12 | @NgModule({ 13 | imports: [RouterModule.forChild(routes)], 14 | exports: [RouterModule], 15 | }) 16 | export class Tab1PageRoutingModule {} 17 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab2/tab2-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { Tab2Page } from './tab2.page'; 4 | 5 | const routes: Routes = [ 6 | { 7 | path: '', 8 | component: Tab2Page, 9 | }, 10 | ]; 11 | 12 | @NgModule({ 13 | imports: [RouterModule.forChild(routes)], 14 | exports: [RouterModule], 15 | }) 16 | export class Tab2PageRoutingModule {} 17 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab3/tab3-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { Tab3Page } from './tab3.page'; 4 | 5 | const routes: Routes = [ 6 | { 7 | path: '', 8 | component: Tab3Page, 9 | }, 10 | ]; 11 | 12 | @NgModule({ 13 | imports: [RouterModule.forChild(routes)], 14 | exports: [RouterModule], 15 | }) 16 | export class Tab3PageRoutingModule {} 17 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/banner/BannerAdPluginEvents.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.banner 2 | 3 | enum class BannerAdPluginEvents(val webEventName: String) { 4 | SizeChanged("bannerAdSizeChanged"), 5 | Closed("bannerAdClosed"), 6 | FailedToLoad("bannerAdFailedToLoad"), 7 | Opened("bannerAdOpened"), 8 | Loaded("bannerAdLoaded"), 9 | Clicked("bannerAdClicked"), 10 | AdImpression("bannerAdImpression"), 11 | } -------------------------------------------------------------------------------- /demo/angular/src/app/home/home.page.scss: -------------------------------------------------------------------------------- 1 | #container { 2 | text-align: center; 3 | 4 | position: absolute; 5 | left: 0; 6 | right: 0; 7 | top: 50%; 8 | transform: translateY(-50%); 9 | } 10 | 11 | #container strong { 12 | font-size: 20px; 13 | line-height: 26px; 14 | } 15 | 16 | #container p { 17 | font-size: 16px; 18 | line-height: 22px; 19 | 20 | color: #8c8c8c; 21 | 22 | margin: 0; 23 | } 24 | 25 | #container a { 26 | text-decoration: none; 27 | } -------------------------------------------------------------------------------- /ios/Sources/AdMobPlugin/RewardedInterstitial/RewardInterstitialAdPluginEvents.swift: -------------------------------------------------------------------------------- 1 | public enum RewardInterstitialAdPluginEvents: String { 2 | case Loaded = "onRewardedInterstitialAdLoaded" 3 | case FailedToLoad = "onRewardedInterstitialAdFailedToLoad" 4 | case Showed = "onRewardedInterstitialAdShowed" 5 | case FailedToShow = "onRewardedInterstitialAdFailedToShow" 6 | case Dismissed = "onRewardedInterstitialAdDismissed" 7 | case Rewarded = "onRewardedInterstitialAdReward" 8 | } 9 | -------------------------------------------------------------------------------- /src/banner/banner-ad-position.enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @see https://developer.android.com/reference/android/widget/LinearLayout#attr_android:gravity 3 | */ 4 | export enum BannerAdPosition { 5 | /** 6 | * Banner position be top-center 7 | */ 8 | TOP_CENTER = 'TOP_CENTER', 9 | 10 | /** 11 | * Banner position be center 12 | */ 13 | CENTER = 'CENTER', 14 | 15 | /** 16 | * Banner position be bottom-center(default) 17 | */ 18 | BOTTOM_CENTER = 'BOTTOM_CENTER', 19 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowUnreachableCode": false, 4 | "declaration": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2017"], 7 | "module": "esnext", 8 | "moduleResolution": "node", 9 | "noFallthroughCasesInSwitch": true, 10 | "noUnusedLocals": true, 11 | "noUnusedParameters": true, 12 | "outDir": "dist/esm", 13 | "pretty": true, 14 | "sourceMap": true, 15 | "strict": true, 16 | "target": "es2017" 17 | }, 18 | "files": ["src/index.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /demo/angular/android/app/capacitor.build.gradle: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN 2 | 3 | android { 4 | compileOptions { 5 | sourceCompatibility JavaVersion.VERSION_21 6 | targetCompatibility JavaVersion.VERSION_21 7 | } 8 | } 9 | 10 | apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" 11 | dependencies { 12 | implementation project(':capacitor-community-admob') 13 | 14 | } 15 | 16 | 17 | if (hasProperty('postBuildExtras')) { 18 | postBuildExtras() 19 | } 20 | -------------------------------------------------------------------------------- /demo/angular/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; 6 | 7 | // First, initialize the Angular testing environment. 8 | getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { 9 | teardown: { destroyAfterEach: false }, 10 | }); 11 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.myapp; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | 14 | @Test 15 | public void addition_isCorrect() throws Exception { 16 | assertEquals(4, 2 + 2); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { registerPlugin } from '@capacitor/core'; 2 | 3 | import type { AdMobPlugin } from './definitions'; 4 | 5 | const AdMob = registerPlugin('AdMob', { 6 | web: () => import('./web').then((m) => new m.AdMobWeb()), 7 | }); 8 | 9 | export * from './definitions'; 10 | export * from './banner/index'; 11 | export * from './interstitial/index'; 12 | export * from './reward-interstitial/index'; 13 | export * from './reward/index'; 14 | export * from './consent/index'; 15 | export * from './shared/index'; 16 | export { AdMob }; 17 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | input: 'dist/esm/index.js', 3 | output: [ 4 | { 5 | file: 'dist/plugin.js', 6 | format: 'iife', 7 | name: 'capacitorStripe', 8 | globals: { 9 | '@capacitor/core': 'capacitorExports', 10 | }, 11 | sourcemap: true, 12 | inlineDynamicImports: true, 13 | }, 14 | { 15 | file: 'dist/plugin.cjs.js', 16 | format: 'cjs', 17 | sourcemap: true, 18 | inlineDynamicImports: true, 19 | }, 20 | ], 21 | external: ['@capacitor/core'], 22 | }; 23 | -------------------------------------------------------------------------------- /demo/angular/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "splash-2732x2732-2.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "splash-2732x2732-1.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "splash-2732x2732.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdPluginPluginEvent.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.interstitial 2 | 3 | import com.getcapacitor.community.admob.models.LoadPluginEventNames 4 | 5 | object InterstitialAdPluginPluginEvent: LoadPluginEventNames { 6 | const val Loaded = "interstitialAdLoaded" 7 | const val FailedToLoad = "interstitialAdFailedToLoad" 8 | override val Showed = "interstitialAdShowed" 9 | override val FailedToShow = "interstitialAdFailedToShow" 10 | override val Dismissed = "interstitialAdDismissed" 11 | } -------------------------------------------------------------------------------- /demo/angular/android/variables.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | minSdkVersion = 23 3 | compileSdkVersion = 35 4 | targetSdkVersion = 35 5 | androidxActivityVersion = '1.9.2' 6 | androidxAppCompatVersion = '1.7.0' 7 | androidxCoordinatorLayoutVersion = '1.2.0' 8 | androidxCoreVersion = '1.15.0' 9 | androidxFragmentVersion = '1.8.4' 10 | junitVersion = '4.13.2' 11 | androidxJunitVersion = '1.2.1' 12 | androidxEspressoCoreVersion = '3.6.1' 13 | cordovaAndroidVersion = '10.1.1' 14 | coreSplashScreenVersion = '1.0.1' 15 | androidxWebkitVersion = '1.12.1' 16 | } -------------------------------------------------------------------------------- /ios/Tests/AdMobPluginTests/AdMobPluginTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import AdMobPlugin 3 | 4 | class AdMobTests: XCTestCase { 5 | func testEcho() { 6 | // This is an example of a functional test case for a plugin. 7 | // Use XCTAssert and related functions to verify your tests produce the correct results. 8 | 9 | // let implementation = AdMob() 10 | // let value = "Hello, World!" 11 | // let result = implementation.echo(value) 12 | // 13 | // XCTAssertEqual(value, result) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /demo/angular/.gitignore: -------------------------------------------------------------------------------- 1 | /.angular/cache 2 | # Specifies intentionally untracked files to ignore when using Git 3 | # http://git-scm.com/docs/gitignore 4 | 5 | *~ 6 | *.sw[mnpcod] 7 | .tmp 8 | *.tmp 9 | *.tmp.* 10 | *.sublime-project 11 | *.sublime-workspace 12 | .DS_Store 13 | Thumbs.db 14 | UserInterfaceState.xcuserstate 15 | $RECYCLE.BIN/ 16 | 17 | *.log 18 | log.txt 19 | npm-debug.log* 20 | 21 | /.idea 22 | /.ionic 23 | /.sass-cache 24 | /.sourcemaps 25 | /.versions 26 | /.vscode 27 | /coverage 28 | /dist 29 | /node_modules 30 | /platforms 31 | /plugins 32 | /www 33 | /.angular 34 | /.nx 35 | -------------------------------------------------------------------------------- /demo/angular/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { PreloadAllModules, RouterModule, Routes } from '@angular/router'; 3 | 4 | const routes: Routes = [ 5 | { 6 | path: '', 7 | loadChildren: () => import('./validation/tabs/tabs.module').then((m) => m.TabsPageModule), 8 | }, 9 | { 10 | path: '', 11 | redirectTo: '', 12 | pathMatch: 'full', 13 | }, 14 | ]; 15 | 16 | @NgModule({ 17 | imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })], 18 | exports: [RouterModule], 19 | }) 20 | export class AppRoutingModule {} 21 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab3/tab3.module.ts: -------------------------------------------------------------------------------- 1 | import { RouterModule } from '@angular/router'; 2 | import { NgModule } from '@angular/core'; 3 | import { CommonModule } from '@angular/common'; 4 | import { FormsModule } from '@angular/forms'; 5 | import { Tab3Page } from './tab3.page'; 6 | 7 | import { Tab3PageRoutingModule } from './tab3-routing.module'; 8 | 9 | @NgModule({ 10 | imports: [ 11 | CommonModule, 12 | FormsModule, 13 | RouterModule.forChild([{ path: '', component: Tab3Page }]), 14 | Tab3PageRoutingModule, 15 | Tab3Page, 16 | ], 17 | }) 18 | export class Tab3PageModule {} 19 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tabs/tabs.page.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { addIcons } from 'ionicons'; 3 | import { easel, play, reader, videocam } from 'ionicons/icons'; 4 | import { IonIcon, IonLabel, IonTabBar, IonTabButton, IonTabs } from '@ionic/angular/standalone'; 5 | 6 | @Component({ 7 | selector: 'app-tabs', 8 | templateUrl: 'tabs.page.html', 9 | styleUrls: ['tabs.page.scss'], 10 | imports: [IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel], 11 | }) 12 | export class TabsPage { 13 | constructor() { 14 | addIcons({ play, easel, reader, videocam }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/consent/privacy-options-requirement-status.enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * For more information: 3 | * https://developers.google.com/admob/unity/reference/namespace/google-mobile-ads/ump/api#privacyoptionsrequirementstatus 4 | * 5 | * */ 6 | 7 | export enum PrivacyOptionsRequirementStatus { 8 | /** 9 | * Privacy options entry point is not required. 10 | */ 11 | NOT_REQUIRED = 'NOT_REQUIRED', 12 | 13 | /** 14 | * Privacy options entry point is required. 15 | */ 16 | REQUIRED = 'REQUIRED', 17 | 18 | /** 19 | * Privacy options requirement status is unknown. 20 | */ 21 | UNKNOWN = 'UNKNOWN', 22 | } 23 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardAdPluginEvents.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.rewarded 2 | 3 | import com.getcapacitor.community.admob.models.LoadPluginEventNames 4 | 5 | object RewardAdPluginEvents: LoadPluginEventNames { 6 | const val Loaded = "onRewardedVideoAdLoaded" 7 | const val FailedToLoad = "onRewardedVideoAdFailedToLoad" 8 | const val Rewarded = "onRewardedVideoAdReward" 9 | override val Showed = "onRewardedVideoAdShowed" 10 | override val FailedToShow = "onRewardedVideoAdFailedToShow" 11 | override val Dismissed = "onRewardedVideoAdDismissed" 12 | } -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Sources/AdMobPlugin/Models/FullScreenAdEventName.swift: -------------------------------------------------------------------------------- 1 | public enum FullScreenAdEventName: String { 2 | case onAdLoaded = "onAdLoaded" 3 | case onAdFailedToLoad = "onAdFailedToLoad" 4 | case adDidPresentFullScreenContent = "adDidPresentFullScreenContent" 5 | case didFailToPresentFullScreenContentWithError = "didFailToPresentFullScreenContentWithError" 6 | 7 | /** 8 | * Follow iOS Event Name 9 | * https://developers.google.com/admob/ios/api/reference/Protocols/GADFullScreenContentDelegate#-addidpresentfullscreencontent: 10 | */ 11 | case adDidDismissFullScreenContent = "adDidDismissFullScreenContent" 12 | } 13 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/models/AdMobPluginError.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.models 2 | 3 | import com.getcapacitor.JSObject 4 | import com.google.android.gms.ads.AdError 5 | 6 | data class AdMobPluginError(val code: Int, val message: String) : JSObject() { 7 | override fun put(key: String, value: Int): JSObject { 8 | throw Exception("Do not put elements directly here use the constructor") 9 | } 10 | init { 11 | super.put("code", this.code) 12 | super.put("message", this.message) 13 | } 14 | constructor(adError: AdError): this(adError.code, adError.message) 15 | } 16 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/rewarded/models/SsvInfo.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.rewarded.models 2 | 3 | import com.getcapacitor.PluginCall 4 | 5 | class SsvInfo( 6 | val customData: String? = null, 7 | val userId: String? = null) { 8 | 9 | constructor(pluginCall: PluginCall?) : this( 10 | pluginCall?.getObject("ssv")?.getString("customData"), 11 | pluginCall?.getObject("ssv")?.getString("userId") 12 | ) 13 | 14 | constructor() : this(null, null) 15 | 16 | val hasInfo 17 | get(): Boolean { 18 | return customData != null || userId != null 19 | } 20 | } -------------------------------------------------------------------------------- /demo/angular/src/zone-flags.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file configures zone.js for the application. 3 | * Zone.js is required by Angular for change detection. 4 | */ 5 | 6 | // Disable zone.js patches for specific APIs if needed 7 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 8 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 9 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 10 | 11 | // Enable cross context check for IE/Edge 12 | // (window as any).__Zone_enable_cross_context_check = true; 13 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/models/SsvInfo.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.rewardedinterstitial.models 2 | 3 | import com.getcapacitor.PluginCall 4 | 5 | class SsvInfo( 6 | val customData: String? = null, 7 | val userId: String? = null) { 8 | 9 | constructor(pluginCall: PluginCall?) : this( 10 | pluginCall?.getObject("ssv")?.getString("customData"), 11 | pluginCall?.getObject("ssv")?.getString("userId") 12 | ) 13 | 14 | constructor() : this(null, null) 15 | 16 | val hasInfo 17 | get(): Boolean { 18 | return customData != null || userId != null 19 | } 20 | } -------------------------------------------------------------------------------- /src/consent/consent-status.enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * For more information: 3 | * https://developers.google.com/admob/unity/reference/namespace/google-mobile-ads/ump/api#consentstatus 4 | * 5 | * */ 6 | 7 | export enum AdmobConsentStatus { 8 | /** 9 | * User consent not required. 10 | */ 11 | NOT_REQUIRED = 'NOT_REQUIRED', 12 | 13 | /** 14 | * User consent already obtained. 15 | */ 16 | OBTAINED = 'OBTAINED', 17 | 18 | /** 19 | * User consent required but not yet obtained. 20 | */ 21 | REQUIRED = 'REQUIRED', 22 | 23 | /** 24 | * Unknown consent status, AdsConsent.requestInfoUpdate needs to be called to update it. 25 | */ 26 | UNKNOWN = 'UNKNOWN', 27 | } 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardInterstitialAdPluginEvents.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.rewardedinterstitial 2 | 3 | import com.getcapacitor.community.admob.models.LoadPluginEventNames 4 | 5 | object RewardInterstitialAdPluginEvents: LoadPluginEventNames { 6 | const val Loaded = "onRewardedInterstitialAdLoaded" 7 | const val FailedToLoad = "onRewardedInterstitialAdFailedToLoad" 8 | const val Rewarded = "onRewardedInterstitialAdReward" 9 | override val Showed = "onRewardedInterstitialAdShowed" 10 | override val FailedToShow = "onRewardedInterstitialAdFailedToShow" 11 | override val Dismissed = "onRewardedInterstitialAdDismissed" 12 | } -------------------------------------------------------------------------------- /src/banner/banner-ad-plugin-events.enum.ts: -------------------------------------------------------------------------------- 1 | // This enum should be keep in sync with their native equivalents with the same name 2 | export enum BannerAdPluginEvents { 3 | SizeChanged = "bannerAdSizeChanged", 4 | Loaded = "bannerAdLoaded", 5 | FailedToLoad = "bannerAdFailedToLoad", 6 | 7 | /** 8 | * Open "Adsense" Event after user click banner 9 | */ 10 | Opened = "bannerAdOpened", 11 | 12 | /** 13 | * Close "Adsense" Event after user click banner 14 | */ 15 | Closed = "bannerAdClosed", 16 | 17 | /** 18 | * Similarly, this method should be called when an impression is recorded for the ad by the mediated SDK. 19 | */ 20 | AdImpression = "bannerAdImpression", 21 | } 22 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tabs/tabs.page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | DEMO 7 | 8 | 9 | 10 | 11 | BANNER 12 | 13 | 14 | 15 | 16 | INTERSTITIAL 17 | 18 | 19 | 20 | 21 | REWARD 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/banner/BannerAdSizeEnum.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.banner 2 | 3 | import com.google.android.gms.ads.AdSize 4 | 5 | /** 6 | * https://developers.google.com/admob/android/banner#banner_sizes 7 | */ 8 | enum class BannerAdSizeEnum(val size: AdSize) { 9 | BANNER(AdSize.BANNER), 10 | FULL_BANNER(AdSize.FULL_BANNER), 11 | LARGE_BANNER(AdSize.LARGE_BANNER), 12 | MEDIUM_RECTANGLE(AdSize.MEDIUM_RECTANGLE), 13 | LEADERBOARD(AdSize.LEADERBOARD), 14 | ADAPTIVE_BANNER(AdSize.INVALID), // We should not use the AdSize here but calculate the device size 15 | SMART_BANNER(AdSize.SMART_BANNER); 16 | 17 | override fun toString(): String { 18 | return name 19 | } 20 | } -------------------------------------------------------------------------------- /demo/angular/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false, 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/banner/BannerAdSizeInfo.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.banner 2 | 3 | import com.getcapacitor.JSObject 4 | import com.google.android.gms.ads.AdError 5 | import com.google.android.gms.ads.AdView 6 | import java.util.* 7 | 8 | data class BannerAdSizeInfo(val width: Int, val height: Int) : JSObject() { 9 | override fun put(key: String, value: Int): JSObject { 10 | throw Exception("Do not put elements directly here use the constructor") 11 | } 12 | init { 13 | super.put("width", width) 14 | super.put("height", height) 15 | } 16 | constructor(mAdView: AdView): this(Objects.requireNonNull(mAdView.adSize)!!.width, Objects.requireNonNull(mAdView.adSize)!!.height) 17 | } 18 | -------------------------------------------------------------------------------- /src/consent/consent-request-options.interface.ts: -------------------------------------------------------------------------------- 1 | import type { AdmobConsentDebugGeography } from './consent-debug-geography.enum'; 2 | 3 | export interface AdmobConsentRequestOptions { 4 | /** 5 | * Sets the debug geography to test the consent locally. 6 | * @since 5.0.0 7 | */ 8 | debugGeography?: AdmobConsentDebugGeography; 9 | 10 | /** 11 | * An array of test device IDs to allow. 12 | * Note: On iOS, the ID may renew if you uninstall and reinstall the app. 13 | * @since 5.0.0 14 | */ 15 | testDeviceIdentifiers?: string[]; 16 | 17 | /** 18 | * Set to `true` to provide the option for the user to accept being shown personalized ads. 19 | * @default false 20 | * @since 5.0.0 21 | */ 22 | tagForUnderAgeOfConsent?: boolean; 23 | } 24 | -------------------------------------------------------------------------------- /src/consent/consent-debug-geography.enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * For more information: 3 | * https://developers.google.com/admob/unity/reference/namespace/google-mobile-ads/ump/api#debuggeography 4 | * 5 | * */ 6 | 7 | export enum AdmobConsentDebugGeography { 8 | /** 9 | * Debug geography disabled. 10 | */ 11 | DISABLED = 0, 12 | 13 | /** 14 | * Geography appears as in EEA for debug devices. 15 | */ 16 | EEA = 1, 17 | 18 | /** 19 | * Geography appears as not in EEA for debug devices. 20 | * @deprecated 21 | */ 22 | NOT_EEA = 2, 23 | 24 | /** 25 | * Geography appears as in regulated US state for debug devices. 26 | */ 27 | US = 3, 28 | 29 | /** 30 | * Geography appears as OTHER state for debug devices. 31 | */ 32 | OTHER = 4, 33 | } 34 | -------------------------------------------------------------------------------- /CapacitorCommunityAdmob.podspec: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'CapacitorCommunityAdmob' 7 | s.version = package['version'] 8 | s.summary = package['description'] 9 | s.license = package['license'] 10 | s.homepage = package['repository']['url'] 11 | s.author = package['author'] 12 | s.source = { :git => package['repository']['url'], :tag => s.version.to_s } 13 | s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}' 14 | s.ios.deployment_target = '15.0' 15 | s.swift_version = '5.1' 16 | s.static_framework = true 17 | s.dependency 'Capacitor' 18 | s.dependency 'Google-Mobile-Ads-SDK', '12.12.0' 19 | s.dependency 'GoogleUserMessagingPlatform', '3.0.0' 20 | end 21 | -------------------------------------------------------------------------------- /demo/angular/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | mavenCentral() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:8.7.2' 11 | classpath 'com.google.gms:google-services:4.4.2' 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | apply from: "variables.gradle" 19 | 20 | allprojects { 21 | repositories { 22 | google() 23 | mavenCentral() 24 | } 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/consent/consent-info.interface.ts: -------------------------------------------------------------------------------- 1 | import type { AdmobConsentStatus } from './consent-status.enum'; 2 | import type { PrivacyOptionsRequirementStatus } from './privacy-options-requirement-status.enum'; 3 | 4 | export interface AdmobConsentInfo { 5 | /** 6 | * The consent status of the user. 7 | * @since 5.0.0 8 | */ 9 | status: AdmobConsentStatus; 10 | 11 | /** 12 | * If `true` a consent form is available and vice versa. 13 | * @since 5.0.0 14 | */ 15 | isConsentFormAvailable?: boolean; 16 | 17 | /** 18 | * If `true` an ad can be shown. 19 | * @since 7.0.3 20 | */ 21 | canRequestAds: boolean; 22 | 23 | /** 24 | * Privacy options requirement status of the user. 25 | * @since 7.0.3 26 | */ 27 | privacyOptionsRequirementStatus: PrivacyOptionsRequirementStatus; 28 | } 29 | -------------------------------------------------------------------------------- /android/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /demo/angular/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Ionic App 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/banner/banner-ad-options.interface.ts: -------------------------------------------------------------------------------- 1 | import type { AdOptions } from '../shared'; 2 | 3 | import type { BannerAdPosition } from './banner-ad-position.enum'; 4 | import type { BannerAdSize } from './banner-ad-size.enum'; 5 | 6 | /** 7 | * This interface extends AdOptions 8 | */ 9 | export interface BannerAdOptions extends AdOptions { 10 | /** 11 | * Banner Ad Size, defaults to ADAPTIVE_BANNER. 12 | * IT can be: ADAPTIVE_BANNER, SMART_BANNER, BANNER, 13 | * MEDIUM_RECTANGLE, FULL_BANNER, LEADERBOARD 14 | * 15 | * @default ADAPTIVE_BANNER 16 | * @since 3.0.0 17 | */ 18 | adSize?: BannerAdSize; 19 | 20 | /** 21 | * Set Banner Ad position. 22 | * TOP_CENTER or CENTER or BOTTOM_CENTER 23 | * 24 | * @default TOP_CENTER 25 | * @since 1.1.2 26 | */ 27 | position?: BannerAdPosition; 28 | } 29 | -------------------------------------------------------------------------------- /demo/angular/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab1/tab1.page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | BANNER 4 | 5 | 6 | 7 | 8 | 9 | PROGRESS 10 | @for (item of eventItems; track item; let i = $index) { 11 | 12 | 13 | {{item.name}} 14 | @if (item.result !== undefined) { 15 | 16 | } 17 | 18 | } 19 | 20 | 21 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab3/tab3.page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | REWARD 4 | 5 | 6 | 7 | 8 | 9 | PROGRESS 10 | @for (item of eventItems; track item; let i = $index) { 11 | 12 | 13 | {{item.name}} 14 | @if (item.result !== undefined) { 15 | 16 | } 17 | 18 | } 19 | 20 | 21 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab2/tab2.page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | INTERSTITIAL 4 | 5 | 6 | 7 | 8 | 9 | PROGRESS 10 | @for (item of eventItems; track item; let i = $index) { 11 | 12 | 13 | {{item.name}} 14 | @if (item.result !== undefined) { 15 | 16 | } 17 | 18 | } 19 | 20 | 21 | -------------------------------------------------------------------------------- /demo/angular/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/interstitial/interstitial-ad-plugin-events.enum.ts: -------------------------------------------------------------------------------- 1 | // This enum should be keep in sync with their native equivalents with the same name 2 | export enum InterstitialAdPluginEvents { 3 | /** 4 | * Emits after trying to prepare and Interstitial, when it is loaded and ready to be show 5 | */ 6 | Loaded = 'interstitialAdLoaded', 7 | /** 8 | * Emits after trying to prepare and Interstitial, when it could not be loaded 9 | */ 10 | FailedToLoad = 'interstitialAdFailedToLoad', 11 | /** 12 | * Emits when the Interstitial ad is visible to the user 13 | */ 14 | Showed = 'interstitialAdShowed', 15 | /** 16 | * Emits when the Interstitial ad is failed to show 17 | */ 18 | FailedToShow = 'interstitialAdFailedToShow', 19 | /** 20 | * Emits when the Interstitial ad is not visible to the user anymore. 21 | */ 22 | Dismissed= 'interstitialAdDismissed', 23 | } 24 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 17 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/private/validate-all-events-implemented.type.ts: -------------------------------------------------------------------------------- 1 | import type { PluginListenerHandle } from '@capacitor/core'; 2 | 3 | type Contra = (x: T) => void; 4 | type UnwrapContra = [T] extends [Contra] ? S : never; 5 | type UnionToIntersection = UnwrapContra : never>; 6 | 7 | type Overload = ( 8 | eventName: T, 9 | listenerFunc: (...args: any[]) => any, 10 | ) => Promise; 11 | type OverloadUnionForEnum = T extends any ? Overload : never; 12 | 13 | type OverloadUnion = OverloadUnionForEnum; 14 | // Overload | Overload | Overload 15 | 16 | type Overloads = UnionToIntersection>; 17 | 18 | export type ValidateAllEventsEnumAreImplemented< 19 | TEventsEnum, 20 | TDefinitionInterface extends { addListener: Overloads }, 21 | > = TDefinitionInterface; 22 | -------------------------------------------------------------------------------- /android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.android; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import android.content.Context; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | import androidx.test.platform.app.InstrumentationRegistry; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * @see Testing documentation 15 | */ 16 | @RunWith(AndroidJUnit4.class) 17 | public class ExampleInstrumentedTest { 18 | 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 23 | 24 | assertEquals("com.getcapacitor.android", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.myapp; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import android.content.Context; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | import androidx.test.platform.app.InstrumentationRegistry; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * @see Testing documentation 15 | */ 16 | @RunWith(AndroidJUnit4.class) 17 | public class ExampleInstrumentedTest { 18 | 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 23 | 24 | assertEquals("com.getcapacitor.app", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demo/angular/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode, importProvidersFrom } from '@angular/core'; 2 | 3 | import { environment } from './environments/environment'; 4 | import { RouteReuseStrategy } from '@angular/router'; 5 | import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone'; 6 | import { bootstrapApplication, BrowserModule } from '@angular/platform-browser'; 7 | import { AppRoutingModule } from './app/app-routing.module'; 8 | import { AppComponent } from './app/app.component'; 9 | import * as allIcons from 'ionicons/icons'; 10 | import { addIcons } from 'ionicons'; 11 | 12 | addIcons(allIcons); 13 | 14 | if (environment.production) { 15 | enableProdMode(); 16 | } 17 | 18 | bootstrapApplication(AppComponent, { 19 | providers: [ 20 | importProvidersFrom(BrowserModule, AppRoutingModule), 21 | { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, 22 | provideIonicAngular({}), 23 | ], 24 | }).catch((err) => console.log(err)); 25 | -------------------------------------------------------------------------------- /demo/angular/ios/App/CapApp-SPM/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.9 2 | import PackageDescription 3 | 4 | // DO NOT MODIFY THIS FILE - managed by Capacitor CLI commands 5 | let package = Package( 6 | name: "CapApp-SPM", 7 | platforms: [.iOS(.v15)], 8 | products: [ 9 | .library( 10 | name: "CapApp-SPM", 11 | targets: ["CapApp-SPM"]) 12 | ], 13 | dependencies: [ 14 | .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "8.0.0"), 15 | .package(name: "CapacitorCommunityAdmob", path: "../../../../..") 16 | ], 17 | targets: [ 18 | .target( 19 | name: "CapApp-SPM", 20 | dependencies: [ 21 | .product(name: "Capacitor", package: "capacitor-swift-pm"), 22 | .product(name: "Cordova", package: "capacitor-swift-pm"), 23 | .product(name: "CapacitorCommunityAdmob", package: "CapacitorCommunityAdmob") 24 | ] 25 | ) 26 | ] 27 | ) 28 | -------------------------------------------------------------------------------- /demo/angular/src/app/shared/ad.options.ts: -------------------------------------------------------------------------------- 1 | import { BannerAdOptions, BannerAdPosition, BannerAdSize } from '../../../../../dist/esm/banner'; 2 | import { AdOptions } from '../../../../../dist/esm/shared'; 3 | 4 | export const bannerTopOptions: BannerAdOptions = { 5 | adId: 'ca-app-pub-3940256099942544/2934735716', 6 | adSize: BannerAdSize.ADAPTIVE_BANNER, 7 | position: BannerAdPosition.TOP_CENTER, 8 | // npa: false, 9 | }; 10 | 11 | export const bannerBottomOptions: BannerAdOptions = { 12 | adId: 'ca-app-pub-3940256099942544/2934735716', 13 | adSize: BannerAdSize.ADAPTIVE_BANNER, 14 | position: BannerAdPosition.BOTTOM_CENTER, 15 | npa: true, 16 | }; 17 | 18 | export const rewardOptions: AdOptions = { 19 | adId: 'ca-app-pub-3940256099942544/5224354917', 20 | }; 21 | 22 | export const rewardInterstitialOptions: AdOptions = { 23 | adId: 'ca-app-pub-3940256099942544/5354046379', 24 | }; 25 | 26 | export const interstitialOptions: AdOptions = { 27 | adId: 'ca-app-pub-3940256099942544/1033173712', 28 | }; 29 | -------------------------------------------------------------------------------- /demo/angular/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "esModuleInterop": true, 9 | "strict": true, 10 | "noImplicitOverride": true, 11 | "noPropertyAccessFromIndexSignature": true, 12 | "noImplicitReturns": true, 13 | "noFallthroughCasesInSwitch": true, 14 | "sourceMap": true, 15 | "declaration": false, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "es2022", 20 | "module": "es2020", 21 | "lib": ["es2018", "dom"], 22 | "useDefineForClassFields": false 23 | }, 24 | "angularCompilerOptions": { 25 | "enableI18nLegacyMessageIdFormat": false, 26 | "strictInjectionParameters": true, 27 | "strictInputAccessModifiers": true, 28 | "strictTemplates": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demo/angular/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | import { IonApp, IonRouterOutlet, Platform } from '@ionic/angular/standalone'; 4 | 5 | import { AdMob } from '@capacitor-community/admob'; 6 | 7 | @Component({ 8 | selector: 'app-root', 9 | templateUrl: 'app.component.html', 10 | styleUrls: ['app.component.scss'], 11 | imports: [IonApp, IonRouterOutlet], 12 | }) 13 | export class AppComponent { 14 | constructor(private platform: Platform) { 15 | this.initializeApp(); 16 | } 17 | 18 | initializeApp() { 19 | this.platform.ready().then(() => { 20 | /** 21 | * initialize() require after platform.ready(); 22 | */ 23 | AdMob.initialize({ 24 | testingDevices: ['2077ef9a63d2b398840261c8221a0c9b'], 25 | initializeForTesting: true, 26 | }); 27 | 28 | AdMob.setApplicationMuted({ 29 | muted: false, 30 | }); 31 | 32 | AdMob.setApplicationVolume({ 33 | volume: 0.5, 34 | }); 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/reward/reward-ad-options.interface.ts: -------------------------------------------------------------------------------- 1 | import type { AdOptions } from '../shared/ad-options.interface'; 2 | 3 | // This is a type to ensure that IF ssv is provided, at least one of userId or customData is required. 4 | type AtLeastOne = {[K in keyof T]: Pick}[keyof T]; 5 | 6 | // Because only RewardedAds use SSV. This interface is only available for RewardedAds 7 | export interface RewardAdOptions extends AdOptions { 8 | /** 9 | * If you have enabled SSV in your AdMob Application. You can provide customData or 10 | * a userId be passed to your callback to do further processing on. 11 | * 12 | * *Important* You *HAVE* to define one of them. 13 | * 14 | * @see https://support.google.com/admob/answer/9603226?hl=en-GB 15 | */ 16 | ssv?: AtLeastOne<{ 17 | /** 18 | * An optional UserId to pass to your SSV callback function. 19 | */ 20 | userId: string; 21 | /** 22 | * An optional custom set of data to pass to your SSV callback function. 23 | */ 24 | customData: string; 25 | }>; 26 | } -------------------------------------------------------------------------------- /src/reward-interstitial/reward-interstitial-ad-options.interface.ts: -------------------------------------------------------------------------------- 1 | import type { AdOptions } from '../shared/ad-options.interface'; 2 | 3 | // This is a type to ensure that IF ssv is provided, at least one of userId or customData is required. 4 | type AtLeastOne = { [K in keyof T]: Pick }[keyof T]; 5 | 6 | // Because only RewardedAds use SSV. This interface is only available for RewardedAds 7 | export interface RewardInterstitialAdOptions extends AdOptions { 8 | /** 9 | * If you have enabled SSV in your AdMob Application. You can provide customData or 10 | * a userId be passed to your callback to do further processing on. 11 | * 12 | * *Important* You *HAVE* to define one of them. 13 | * 14 | * @see https://support.google.com/admob/answer/9603226?hl=en-GB 15 | */ 16 | ssv?: AtLeastOne<{ 17 | /** 18 | * An optional UserId to pass to your SSV callback function. 19 | */ 20 | userId: string; 21 | /** 22 | * An optional custom set of data to pass to your SSV callback function. 23 | */ 24 | customData: string; 25 | }>; 26 | } 27 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | # AndroidX package structure to make it clearer which packages are bundled with the 20 | # Android operating system, and which are packaged with your app's APK 21 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 22 | android.useAndroidX=true 23 | 24 | -------------------------------------------------------------------------------- /demo/angular/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | # AndroidX package structure to make it clearer which packages are bundled with the 20 | # Android operating system, and which are packaged with your app's APK 21 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 22 | android.useAndroidX=true 23 | 24 | -------------------------------------------------------------------------------- /demo/angular/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /demo/angular/ios/App/App/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "capacitor-swift-pm", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/ionic-team/capacitor-swift-pm.git", 7 | "state" : { 8 | "revision" : "bc99a4197e8a966c99912a644a9aa5710f7e3409", 9 | "version" : "7.0.1" 10 | } 11 | }, 12 | { 13 | "identity" : "swift-package-manager-google-mobile-ads", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", 16 | "state" : { 17 | "revision" : "c79144a4a0a5bbc2019f9030af66d6573e348daf", 18 | "version" : "12.11.0" 19 | } 20 | }, 21 | { 22 | "identity" : "swift-package-manager-google-user-messaging-platform", 23 | "kind" : "remoteSourceControl", 24 | "location" : "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git", 25 | "state" : { 26 | "revision" : "69b53394c5258b3fe688e625a998047d1f393497", 27 | "version" : "3.0.0" 28 | } 29 | } 30 | ], 31 | "version" : 2 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Capacitor Community 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /demo/angular/src/assets/shapes.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/consent/consent-definition.interface.ts: -------------------------------------------------------------------------------- 1 | import type { AdmobConsentInfo } from './consent-info.interface'; 2 | import type { AdmobConsentRequestOptions } from './consent-request-options.interface'; 3 | 4 | export interface AdmobConsentDefinitions { 5 | /** 6 | * Request user consent information 7 | * 8 | * @group Consent 9 | * @param options ConsentRequestOptions 10 | * @since 5.0.0 11 | */ 12 | requestConsentInfo(options?: AdmobConsentRequestOptions): Promise; 13 | 14 | /** 15 | * Shows a google privacy options form (rendered from your GDPR message config). 16 | * 17 | * @group Consent 18 | * @since 7.0.3 19 | */ 20 | showPrivacyOptionsForm(): Promise; 21 | 22 | /** 23 | * Shows a google user consent form (rendered from your GDPR message config). 24 | * 25 | * @group Consent 26 | * @since 5.0.0 27 | */ 28 | showConsentForm(): Promise; 29 | 30 | /** 31 | * Resets the UMP SDK state. Call requestConsentInfo function again to allow user modify their consent 32 | * 33 | * @group Consent 34 | * @since 5.0.0 35 | */ 36 | 37 | resetConsentInfo(): Promise; 38 | } 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # node files 2 | dist/ 3 | node_modules/ 4 | 5 | # iOS files 6 | Pods 7 | Build 8 | xcuserdata 9 | .swiftpm 10 | 11 | # macOS files 12 | .DS_Store 13 | 14 | 15 | 16 | # Based on Android gitignore template: https://github.com/github/gitignore/blob/master/Android.gitignore 17 | 18 | # Built application files 19 | *.apk 20 | *.ap_ 21 | 22 | # Files for the ART/Dalvik VM 23 | *.dex 24 | 25 | # Java class files 26 | *.class 27 | 28 | # Generated files 29 | bin/ 30 | gen/ 31 | out/ 32 | 33 | # Gradle files 34 | .gradle/ 35 | build/ 36 | 37 | # Local configuration file (sdk path, etc) 38 | local.properties 39 | 40 | # Proguard folder generated by Eclipse 41 | proguard/ 42 | 43 | # Log Files 44 | *.log 45 | 46 | # Android Studio Navigation editor temp files 47 | .navigation/ 48 | 49 | # Android Studio captures folder 50 | captures/ 51 | 52 | # IntelliJ 53 | *.iml 54 | .idea 55 | 56 | # Keystore files 57 | # Uncomment the following line if you do not want to check your keystore files in. 58 | #*.jks 59 | 60 | # External native build folder generated in Android Studio 2.2 and later 61 | .externalNativeBuild 62 | 63 | # vscode generates some debug.log files on some machines 64 | debug.log 65 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this Capacitor Community project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities. 4 | 5 | Communication through this repository must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 6 | 7 | We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to this Capacitor Community project to do the same. 8 | 9 | If any member of the community violates this code of conduct, the maintainers of this Capacitor Community and/or the Ionic project may take action, including but not limited to removing issues, comments, and PRs or blocking accounts as deemed appropriate. 10 | 11 | If you are subject to or witness unacceptable behavior, or have any other concerns, please contact the maintainer of this repository or email hi@ionicframework.com. 12 | -------------------------------------------------------------------------------- /demo/angular/src/global.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * App Global CSS 3 | * ---------------------------------------------------------------------------- 4 | * Put style rules here that you want to apply globally. These styles are for 5 | * the entire app and not just one component. Additionally, this file can be 6 | * used as an entry point to import other CSS/Sass files to be included in the 7 | * output CSS. 8 | * For more information on global stylesheets, visit the documentation: 9 | * https://ionicframework.com/docs/layout/global-stylesheets 10 | */ 11 | 12 | /* Core CSS required for Ionic components to work properly */ 13 | @import "@ionic/angular/css/core.css"; 14 | 15 | /* Basic CSS for apps built with Ionic */ 16 | @import "@ionic/angular/css/normalize.css"; 17 | @import "@ionic/angular/css/structure.css"; 18 | @import "@ionic/angular/css/typography.css"; 19 | @import '@ionic/angular/css/display.css'; 20 | 21 | /* Optional CSS utils that can be commented out */ 22 | @import "@ionic/angular/css/padding.css"; 23 | @import "@ionic/angular/css/float-elements.css"; 24 | @import "@ionic/angular/css/text-alignment.css"; 25 | @import "@ionic/angular/css/text-transformation.css"; 26 | @import "@ionic/angular/css/flex-utils.css"; 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | 15 | 16 | 17 | **To Reproduce** 18 | Steps to reproduce the behavior: 19 | 1. Go to '...' 20 | 2. Click on '....' 21 | 3. Scroll down to '....' 22 | 4. See error 23 | 24 | **Expected behavior** 25 | A clear and concise description of what you expected to happen. 26 | 27 | **Screenshots** 28 | If applicable, add screenshots to help explain your problem. 29 | 30 | **Desktop (please complete the following information):** 31 | - OS: [e.g. iOS] 32 | - Browser [e.g. chrome, safari] 33 | - Version [e.g. 22] 34 | 35 | **Smartphone (please complete the following information):** 36 | - Device: [e.g. iPhone6] 37 | - OS: [e.g. iOS8.1] 38 | - Browser [e.g. stock browser, safari] 39 | - Version [e.g. 22] 40 | 41 | **Additional context** 42 | Add any other context about the problem here. 43 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/helpers/AdViewIdHelper.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.helpers; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | import com.getcapacitor.community.admob.models.AdOptions; 6 | import com.google.android.gms.ads.AdRequest; 7 | import com.google.android.gms.ads.AdView; 8 | 9 | public final class AdViewIdHelper { 10 | 11 | private AdViewIdHelper() {} 12 | 13 | public static String getFinalAdId(AdOptions adOptions, AdRequest adRequest, String logTag, Context context) { 14 | if (!adOptions.isTesting) { 15 | return adOptions.adId; 16 | } 17 | 18 | if (adRequest.isTestDevice(context)) { 19 | Log.w(logTag, "This device is registered as Testing Device. The real Ad Id will be used"); 20 | return adOptions.adId; 21 | } 22 | 23 | return adOptions.getTestingId(); 24 | } 25 | 26 | public static void assignIdToAdView(AdView adView, AdOptions adOptions, AdRequest adRequest, String logTag, Context context) { 27 | String finalId = getFinalAdId(adOptions, adRequest, logTag, context); 28 | adView.setAdUnitId(finalId); 29 | Log.d(logTag, "Ad ID: " + finalId); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tabs/tabs-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { TabsPage } from './tabs.page'; 4 | 5 | const routes: Routes = [ 6 | { 7 | path: 'tabs', 8 | component: TabsPage, 9 | children: [ 10 | { 11 | path: 'home', 12 | loadChildren: () => import('../../home/home.module').then((m) => m.HomePageModule), 13 | }, 14 | { 15 | path: 'tab1', 16 | loadChildren: () => import('../tab1/tab1.module').then((m) => m.Tab1PageModule), 17 | }, 18 | { 19 | path: 'tab2', 20 | loadChildren: () => import('../tab2/tab2.module').then((m) => m.Tab2PageModule), 21 | }, 22 | { 23 | path: 'tab3', 24 | loadChildren: () => import('../tab3/tab3.module').then((m) => m.Tab3PageModule), 25 | }, 26 | { 27 | path: '', 28 | redirectTo: '/tabs/home', 29 | pathMatch: 'full', 30 | }, 31 | ], 32 | }, 33 | { 34 | path: '', 35 | redirectTo: '/tabs/home', 36 | pathMatch: 'full', 37 | }, 38 | ]; 39 | 40 | @NgModule({ 41 | imports: [RouterModule.forChild(routes)], 42 | }) 43 | export class TabsPageRoutingModule {} 44 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/helpers/FullscreenPluginCallback.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.helpers 2 | 3 | import com.getcapacitor.JSObject 4 | import com.getcapacitor.community.admob.models.AdMobPluginError 5 | import com.getcapacitor.community.admob.models.LoadPluginEventNames 6 | import com.google.android.gms.ads.AdError 7 | import com.google.android.gms.ads.FullScreenContentCallback 8 | import com.google.android.gms.common.util.BiConsumer 9 | 10 | class FullscreenPluginCallback(private val loadPluginObject: LoadPluginEventNames, 11 | private val notifyListenersFunction: BiConsumer): FullScreenContentCallback() { 12 | 13 | override fun onAdShowedFullScreenContent() { 14 | notifyListenersFunction.accept(loadPluginObject.Showed, JSObject()) 15 | } 16 | 17 | override fun onAdFailedToShowFullScreenContent(adError: AdError) { 18 | val adMobError = AdMobPluginError(adError) 19 | notifyListenersFunction.accept( 20 | loadPluginObject.FailedToShow, adMobError 21 | ) 22 | } 23 | 24 | override fun onAdDismissedFullScreenContent() { 25 | notifyListenersFunction.accept(loadPluginObject.Dismissed, JSObject()) 26 | } 27 | } -------------------------------------------------------------------------------- /demo/angular/ios/App/App.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "c7bb1381c3e0db11b5a7a523cfc56903afb9c5151dffa9616686b7f962ec5946", 3 | "pins" : [ 4 | { 5 | "identity" : "capacitor-swift-pm", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/ionic-team/capacitor-swift-pm.git", 8 | "state" : { 9 | "revision" : "596259033e94829dffc552a40e7129262122995e", 10 | "version" : "8.0.0" 11 | } 12 | }, 13 | { 14 | "identity" : "swift-package-manager-google-mobile-ads", 15 | "kind" : "remoteSourceControl", 16 | "location" : "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", 17 | "state" : { 18 | "revision" : "1239c23464503053c17d37ee5daa70de3455e9c8", 19 | "version" : "12.14.0" 20 | } 21 | }, 22 | { 23 | "identity" : "swift-package-manager-google-user-messaging-platform", 24 | "kind" : "remoteSourceControl", 25 | "location" : "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git", 26 | "state" : { 27 | "revision" : "13b248eaa73b7826f0efb1bcf455e251d65ecb1b", 28 | "version" : "3.1.0" 29 | } 30 | } 31 | ], 32 | "version" : 3 33 | } 34 | -------------------------------------------------------------------------------- /src/reward/reward-ad-plugin-events.enum.ts: -------------------------------------------------------------------------------- 1 | // This enum should be keep in sync with their native equivalents with the same name 2 | export enum RewardAdPluginEvents { 3 | /** 4 | * Emits after trying to prepare a RewardAd and the Video is loaded and ready to be show 5 | */ 6 | Loaded = 'onRewardedVideoAdLoaded', 7 | /** 8 | * Emits after trying to prepare a RewardAd when it could not be loaded 9 | */ 10 | FailedToLoad = 'onRewardedVideoAdFailedToLoad', 11 | /** 12 | * Emits when the AdReward video is visible to the user 13 | */ 14 | Showed = 'onRewardedVideoAdShowed', 15 | /** 16 | * Emits when the AdReward video is failed to show 17 | */ 18 | FailedToShow = 'onRewardedVideoAdFailedToShow', 19 | /** 20 | * Emits when the AdReward video is not visible to the user anymore. 21 | * 22 | * **Important**: This has nothing to do with the reward it self. This event 23 | * will emits in this two cases: 24 | * 1. The user starts the video ad but close it before the reward emit. 25 | * 2. The user start the video and see it until end, then gets the reward 26 | * and after that the ad is closed. 27 | */ 28 | Dismissed= 'onRewardedVideoAdDismissed', 29 | /** 30 | * Emits when user get rewarded from AdReward 31 | */ 32 | Rewarded= 'onRewardedVideoAdReward', 33 | } 34 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/models/Executor.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.models; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import androidx.core.util.Supplier; 6 | import com.getcapacitor.JSObject; 7 | import com.getcapacitor.Plugin; 8 | import com.google.android.gms.common.util.BiConsumer; 9 | 10 | public abstract class Executor { 11 | 12 | protected final Supplier contextSupplier; 13 | protected final Supplier activitySupplier; 14 | protected BiConsumer notifyListenersFunction; 15 | protected final String logTag; 16 | 17 | // Eventually we can change the notification directly here! 18 | protected void notifyListeners(String eventName, JSObject data) { 19 | notifyListenersFunction.accept(eventName, data); 20 | } 21 | 22 | public Executor( 23 | Supplier contextSupplier, 24 | Supplier activitySupplier, 25 | BiConsumer notifyListenersFunction, 26 | String pluginLogTag, 27 | String executorTag 28 | ) { 29 | this.contextSupplier = contextSupplier; 30 | this.activitySupplier = activitySupplier; 31 | this.notifyListenersFunction = notifyListenersFunction; 32 | this.logTag = pluginLogTag + "|" + executorTag; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/reward-interstitial/reward-interstitial-ad-plugin-events.enum.ts: -------------------------------------------------------------------------------- 1 | // This enum should be keep in sync with their native equivalents with the same name 2 | export enum RewardInterstitialAdPluginEvents { 3 | /** 4 | * Emits after trying to prepare a RewardAd and the Video is loaded and ready to be show 5 | */ 6 | Loaded = 'onRewardedInterstitialAdLoaded', 7 | /** 8 | * Emits after trying to prepare a RewardAd when it could not be loaded 9 | */ 10 | FailedToLoad = 'onRewardedInterstitialAdFailedToLoad', 11 | /** 12 | * Emits when the AdReward video is visible to the user 13 | */ 14 | Showed = 'onRewardedInterstitialAdShowed', 15 | /** 16 | * Emits when the AdReward video is failed to show 17 | */ 18 | FailedToShow = 'onRewardedInterstitialAdFailedToShow', 19 | /** 20 | * Emits when the AdReward video is not visible to the user anymore. 21 | * 22 | * **Important**: This has nothing to do with the reward it self. This event 23 | * will emits in this two cases: 24 | * 1. The user starts the video ad but close it before the reward emit. 25 | * 2. The user start the video and see it until end, then gets the reward 26 | * and after that the ad is closed. 27 | */ 28 | Dismissed = 'onRewardedInterstitialAdDismissed', 29 | /** 30 | * Emits when user get rewarded from AdReward 31 | */ 32 | Rewarded = 'onRewardedInterstitialAdReward', 33 | } 34 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.9 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "CapacitorCommunityAdmob", 6 | platforms: [.iOS(.v15)], 7 | products: [ 8 | .library( 9 | name: "CapacitorCommunityAdmob", 10 | targets: ["AdMobPlugin"]) 11 | ], 12 | dependencies: [ 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: "12.12.0"), 15 | .package(url: "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git", from: "3.0.0") 16 | ], 17 | targets: [ 18 | .target( 19 | name: "AdMobPlugin", 20 | dependencies: [ 21 | .product(name: "Capacitor", package: "capacitor-swift-pm"), 22 | .product(name: "Cordova", package: "capacitor-swift-pm"), 23 | .product(name: "GoogleMobileAds", package: "swift-package-manager-google-mobile-ads"), 24 | .product(name: "GoogleUserMessagingPlatform", package: "swift-package-manager-google-user-messaging-platform") 25 | ], 26 | path: "ios/Sources/AdMobPlugin"), 27 | .testTarget( 28 | name: "AdMobPluginTests", 29 | dependencies: ["AdMobPlugin"], 30 | path: "ios/Tests/AdMobPluginTests") 31 | ] 32 | ) 33 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | This guide provides instructions for contributing to this Capacitor plugin. 4 | 5 | ## Developing 6 | 7 | ### Local Setup 8 | 9 | 1. Fork and clone the repo. 10 | 1. Install the dependencies. 11 | 12 | ```shell 13 | npm install 14 | ``` 15 | 16 | 1. Install SwiftLint if you're on macOS. 17 | 18 | ```shell 19 | brew install swiftlint 20 | ``` 21 | 22 | ### Scripts 23 | 24 | #### `npm run build` 25 | 26 | Build the plugin web assets and generate plugin API documentation using [`@capacitor/docgen`](https://github.com/ionic-team/capacitor-docgen). 27 | 28 | It will compile the TypeScript code from `src/` into ESM JavaScript in `dist/esm/`. These files are used in apps with bundlers when your plugin is imported. 29 | 30 | Then, Rollup will bundle the code into a single file at `dist/plugin.js`. This file is used in apps without bundlers by including it as a script in `index.html`. 31 | 32 | #### `npm run verify` 33 | 34 | Build and validate the web and native projects. 35 | 36 | This is useful to run in CI to verify that the plugin builds for all platforms. 37 | 38 | #### `npm run lint` / `npm run fmt` 39 | 40 | Check formatting and code quality, autoformat/autofix if possible. 41 | 42 | This template is integrated with ESLint, Prettier, and SwiftLint. Using these tools is completely optional, but the [Capacitor Community](https://github.com/capacitor-community/) strives to have consistent code style and structure for easier cooperation. 43 | -------------------------------------------------------------------------------- /src/banner/banner-ad-size.enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * For more information: 3 | * https://developers.google.com/admob/ios/banner#banner_sizes 4 | * https://developers.google.com/android/reference/com/google/android/gms/ads/AdSize 5 | * 6 | * */ 7 | export enum BannerAdSize { 8 | /** 9 | * Mobile Marketing Association (MMA) 10 | * banner ad size (320x50 density-independent pixels). 11 | */ 12 | BANNER = 'BANNER', 13 | 14 | /** 15 | * Interactive Advertising Bureau (IAB) 16 | * full banner ad size (468x60 density-independent pixels). 17 | */ 18 | FULL_BANNER = 'FULL_BANNER', 19 | 20 | /** 21 | * Large banner ad size (320x100 density-independent pixels). 22 | */ 23 | LARGE_BANNER = 'LARGE_BANNER', 24 | 25 | /** 26 | * Interactive Advertising Bureau (IAB) 27 | * medium rectangle ad size (300x250 density-independent pixels). 28 | */ 29 | MEDIUM_RECTANGLE = 'MEDIUM_RECTANGLE', 30 | 31 | /** 32 | * Interactive Advertising Bureau (IAB) 33 | * leaderboard ad size (728x90 density-independent pixels). 34 | */ 35 | LEADERBOARD = 'LEADERBOARD', 36 | 37 | /** 38 | * A dynamically sized banner that is full-width and auto-height. 39 | */ 40 | ADAPTIVE_BANNER = 'ADAPTIVE_BANNER', 41 | 42 | /** 43 | * @deprecated 44 | * Will be removed in next AdMob versions use `ADAPTIVE_BANNER` 45 | * Screen width x 32|50|90 46 | */ 47 | SMART_BANNER = 'SMART_BANNER', 48 | 49 | } 50 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | permissions: 9 | id-token: write 10 | contents: write 11 | 12 | jobs: 13 | release: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@v4 19 | 20 | - name: Setup Node.js 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: 22 24 | registry-url: 'https://registry.npmjs.org' 25 | 26 | - name: Update npm 27 | run: npm install -g npm@latest 28 | 29 | - name: Extract version from tag 30 | id: tag_version 31 | run: | 32 | TAG_NAME=${GITHUB_REF#refs/tags/} 33 | VERSION=${TAG_NAME#v} 34 | echo "version=$VERSION" >> $GITHUB_OUTPUT 35 | echo "tag=$TAG_NAME" >> $GITHUB_OUTPUT 36 | echo "Extracted version: $VERSION from tag: $TAG_NAME" 37 | 38 | - name: Install dependencies 39 | run: npm install 40 | 41 | - name: Build workspaces 42 | run: npm run build 43 | 44 | - name: Publish packages 45 | run: | 46 | VERSION="${{ steps.tag_version.outputs.version }}" 47 | IS_STABLE=$(echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' && echo true || echo false) 48 | 49 | echo "Publishing... $IS_STABLE" 50 | if [ "$IS_STABLE" = "true" ]; then 51 | npm publish --provenance --access public 52 | else 53 | npm publish --provenance --access public --tag next 54 | fi 55 | 56 | -------------------------------------------------------------------------------- /.github/workflows/validation.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: validation 4 | 5 | # Controls when the action will run. 6 | on: [push, pull_request] 7 | 8 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 9 | jobs: 10 | lint: 11 | runs-on: macos-14 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: actions/setup-node@v3 15 | with: 16 | node-version: 22 17 | - run: npm install 18 | - run: npm run lint 19 | 20 | test: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v3 24 | - uses: actions/setup-node@v3 25 | with: 26 | node-version: 22 27 | - run: npm install 28 | - run: npm run lint 29 | 30 | verify-web: 31 | runs-on: ubuntu-latest 32 | steps: 33 | - uses: actions/checkout@v3 34 | - uses: actions/setup-node@v3 35 | with: 36 | node-version: 22 37 | - run: npm install 38 | - run: npm run verify:web 39 | 40 | verify-android: 41 | runs-on: ubuntu-latest 42 | steps: 43 | - name: set up JDK 21 44 | uses: actions/setup-java@v3 45 | with: 46 | java-version: '21' 47 | distribution: 'zulu' 48 | - uses: actions/checkout@v3 49 | - uses: actions/setup-node@v3 50 | with: 51 | node-version: 22 52 | - run: npm install 53 | - run: npm run verify:android 54 | 55 | verify-ios: 56 | runs-on: macos-15 57 | steps: 58 | - uses: actions/checkout@v3 59 | - uses: actions/setup-node@v3 60 | with: 61 | node-version: 22 62 | - run: npm run verify:ios 63 | -------------------------------------------------------------------------------- /android/src/test/java/com/getcapacitor/community/admob/helpers/RequestHelperTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.helpers; 2 | 3 | import static org.mockito.Mockito.verify; 4 | 5 | import android.os.Bundle; 6 | import com.getcapacitor.community.admob.models.AdOptions; 7 | import com.google.ads.mediation.admob.AdMobAdapter; 8 | import com.google.android.gms.ads.AdRequest; 9 | import org.junit.jupiter.api.DisplayName; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.extension.ExtendWith; 12 | import org.mockito.MockedConstruction; 13 | import org.mockito.Mockito; 14 | import org.mockito.junit.jupiter.MockitoExtension; 15 | 16 | @ExtendWith(MockitoExtension.class) 17 | class RequestHelperTest { 18 | 19 | @Test 20 | @DisplayName("#createRequest should add npa to the bundle if npa is requested") 21 | void npa() { 22 | try (MockedConstruction adRequestBuilderMockedConstruction = Mockito.mockConstruction(AdRequest.Builder.class)) { 23 | try (MockedConstruction bundleMockedConstruction = Mockito.mockConstruction(Bundle.class)) { 24 | AdOptions adOptions = new AdOptions.TesterAdOptionsBuilder().setNpa(true).build(); 25 | 26 | // Act 27 | RequestHelper.createRequest(adOptions); 28 | 29 | Bundle mockedBundle = bundleMockedConstruction.constructed().get(0); 30 | AdRequest.Builder adRequestBuilder = adRequestBuilderMockedConstruction.constructed().get(0); 31 | verify(mockedBundle).putString("npa", "1"); 32 | verify(adRequestBuilder).addNetworkExtrasBundle(AdMobAdapter.class, mockedBundle); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /android/src/test/java/com/getcapacitor/community/admob/interstitial/InterstitialAdStub.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.interstitial 2 | 3 | import android.app.Activity 4 | import com.google.android.gms.ads.FullScreenContentCallback 5 | import com.google.android.gms.ads.OnPaidEventListener 6 | import com.google.android.gms.ads.ResponseInfo 7 | import com.google.android.gms.ads.interstitial.InterstitialAd 8 | 9 | internal class InterstitialAdStub: InterstitialAd() { 10 | 11 | private var immersiveMode = false; 12 | private var fullScreenContentCallback: FullScreenContentCallback? = null 13 | 14 | override fun getAdUnitId(): String { 15 | return "adUnit" 16 | } 17 | 18 | override fun show(p0: Activity) { 19 | TODO("Not yet implemented") 20 | } 21 | 22 | override fun setFullScreenContentCallback(p0: FullScreenContentCallback?) { 23 | fullScreenContentCallback = p0 24 | } 25 | 26 | override fun getFullScreenContentCallback(): FullScreenContentCallback? { 27 | return fullScreenContentCallback 28 | } 29 | 30 | override fun setImmersiveMode(p0: Boolean) { 31 | immersiveMode = p0 32 | } 33 | 34 | override fun getResponseInfo(): ResponseInfo { 35 | TODO("Not yet implemented") 36 | } 37 | 38 | override fun setOnPaidEventListener(p0: OnPaidEventListener?) { 39 | TODO("Not yet implemented") 40 | } 41 | 42 | override fun getOnPaidEventListener(): OnPaidEventListener? { 43 | TODO("Not yet implemented") 44 | } 45 | 46 | override fun getPlacementId(): Long { 47 | return 0L 48 | } 49 | 50 | override fun setPlacementId(p0: Long) { 51 | TODO("Not yet implemented") 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /src/shared/ad-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface AdOptions { 2 | /** 3 | * The ad unit ID that you want to request 4 | * 5 | * @see https://support.google.com/admob/answer/7356431?hl=en 6 | * @since 1.1.2 7 | */ 8 | adId: string; 9 | 10 | /** 11 | * You can use test mode of ad. 12 | * 13 | * @default false 14 | * @since 1.1.2 15 | */ 16 | isTesting?: boolean; 17 | 18 | /** 19 | * Margin Banner. Default is 0px; 20 | * If position is BOTTOM_CENTER, margin is be margin-bottom. 21 | * If position is TOP_CENTER, margin is be margin-top. 22 | * 23 | * @default 0 24 | * @since 1.1.2 25 | */ 26 | margin?: number; 27 | 28 | /** 29 | * The default behavior of the Google Mobile Ads SDK is to serve personalized ads. 30 | * Set this to true to request Non-Personalized Ads 31 | * 32 | * @see https://developers.google.com/admob/ios/eu-consent 33 | * @see https://developers.google.com/admob/android/eu-consent 34 | * @default false 35 | * @since 1.2.0 36 | */ 37 | npa?: boolean; 38 | 39 | /** 40 | * Sets a flag that controls if this interstitial or reward object will be displayed in immersive mode. 41 | * Call this method before show. 42 | * During show, if this flag is on and immersive mode is supported, 43 | * SYSTEM_UI_FLAG_IMMERSIVE_STICKY &SYSTEM_UI_FLAG_HIDE_NAVIGATION will be turned on for interstitial or reward ad. 44 | * 45 | * @see https://developers.google.com/admob/android/reference/com/google/android/gms/ads/interstitial/InterstitialAd#setImmersiveMode(boolean) 46 | * @see https://developers.google.com/admob/android/reference/com/google/android/gms/ads/rewarded/RewardedAd#setImmersiveMode(boolean) 47 | * @since 7.0.3 48 | */ 49 | immersiveMode?: boolean; 50 | } 51 | -------------------------------------------------------------------------------- /demo/angular/eslint.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | const eslint = require("@eslint/js"); 3 | const tseslint = require("typescript-eslint"); 4 | const angular = require("angular-eslint"); 5 | const rdlabo = require('@rdlabo/eslint-plugin-rules'); 6 | 7 | module.exports = tseslint.config( 8 | { 9 | files: ["**/*.ts"], 10 | plugins: { 11 | '@rdlabo/rules': rdlabo, 12 | }, 13 | extends: [ 14 | eslint.configs.recommended, 15 | ...tseslint.configs.recommended, 16 | ...tseslint.configs.stylistic, 17 | ...angular.configs.tsRecommended, 18 | ], 19 | processor: angular.processInlineTemplates, 20 | rules: { 21 | "@typescript-eslint/no-explicit-any": "off", 22 | "@typescript-eslint/no-unused-vars": "off", 23 | "@angular-eslint/directive-selector": "off", 24 | "@angular-eslint/component-selector": "off", 25 | "@angular-eslint/no-empty-lifecycle-method": "off", 26 | "@typescript-eslint/no-empty-function": "off", 27 | '@rdlabo/rules/deny-constructor-di': 'error', 28 | '@rdlabo/rules/deny-import-from-ionic-module': 'error', 29 | '@rdlabo/rules/implements-ionic-lifecycle': 'error', 30 | '@rdlabo/rules/deny-soft-private-modifier': 'error', 31 | '@rdlabo/rules/signal-use-as-signal': 'error', 32 | '@rdlabo/rules/signal-use-as-signal-template': 'error', 33 | '@rdlabo/rules/component-property-use-readonly': 'error', 34 | }, 35 | }, 36 | { 37 | files: ["**/*.html"], 38 | plugins: { 39 | '@rdlabo/rules': rdlabo, 40 | }, 41 | extends: [ 42 | ...angular.configs.templateRecommended, 43 | ...angular.configs.templateAccessibility, 44 | ], 45 | rules: { 46 | '@rdlabo/rules/ionic-attr-type-check': 'error', 47 | }, 48 | } 49 | ); 50 | -------------------------------------------------------------------------------- /demo/angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-app-base", 3 | "version": "0.0.0", 4 | "author": "Ionic Framework", 5 | "homepage": "https://ionicframework.com/", 6 | "scripts": { 7 | "ng": "ng", 8 | "start": "ng serve", 9 | "build": "ng build", 10 | "lint": "ng lint", 11 | "e2e": "ng e2e", 12 | "cap": "ng build --configuration production && npx cap copy" 13 | }, 14 | "private": true, 15 | "dependencies": { 16 | "@angular/common": "^20.3.7", 17 | "@angular/core": "^20.3.7", 18 | "@angular/forms": "^20.3.7", 19 | "@angular/platform-browser": "^20.3.7", 20 | "@angular/platform-browser-dynamic": "^20.3.7", 21 | "@angular/router": "^20.3.7", 22 | "@capacitor-community/admob": "file:../..", 23 | "@capacitor/android": "^8.0.0", 24 | "@capacitor/core": "^8.0.0", 25 | "@capacitor/ios": "^8.0.0", 26 | "@ionic/angular": "^7.4.3", 27 | "rxjs": "~7.8.0", 28 | "tslib": "^2.3.0", 29 | "zone.js": "~0.15.0" 30 | }, 31 | "devDependencies": { 32 | "@angular-devkit/build-angular": "^20.3.7", 33 | "@angular/cli": "^20.3.7", 34 | "@angular/compiler": "^20.3.7", 35 | "@angular/compiler-cli": "^20.3.7", 36 | "@angular/language-service": "^20.3.7", 37 | "@capacitor/cli": "^8.0.0", 38 | "@ionic/angular-toolkit": "^12.3.0", 39 | "@types/jasmine": "~3.5.0", 40 | "@types/jasminewd2": "~2.0.3", 41 | "angular-eslint": "20.4.0", 42 | "eslint": "^9.37.0", 43 | "jasmine-core": "~5.1.0", 44 | "jasmine-spec-reporter": "~5.0.0", 45 | "karma": "~6.4.0", 46 | "karma-chrome-launcher": "~3.2.0", 47 | "karma-coverage": "~2.2.0", 48 | "karma-jasmine": "~5.1.0", 49 | "karma-jasmine-html-reporter": "~2.1.0", 50 | "native-run": "^1.7.2", 51 | "typescript": "~5.8.0", 52 | "typescript-eslint": "8.46.0" 53 | } 54 | } -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/helpers/RequestHelper.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.helpers; 2 | 3 | import android.os.Bundle; 4 | import com.getcapacitor.community.admob.models.AdOptions; 5 | import com.google.ads.mediation.admob.AdMobAdapter; 6 | import com.google.android.gms.ads.AdRequest; 7 | 8 | public final class RequestHelper { 9 | 10 | private RequestHelper() {} 11 | 12 | /** 13 | * Use this function to create all requests, here we can centralize request extras 14 | * @param adOptions 15 | * @return 16 | */ 17 | public static AdRequest createRequest(AdOptions adOptions) { 18 | AdRequest.Builder adRequestBuilder = new AdRequest.Builder(); 19 | 20 | // TODO: Allow more key/value extras? 21 | if (adOptions.npa) { 22 | Bundle extras = new Bundle(); 23 | extras.putString("npa", "1"); 24 | adRequestBuilder.addNetworkExtrasBundle(AdMobAdapter.class, extras); 25 | } 26 | 27 | return adRequestBuilder.build(); 28 | } 29 | 30 | /** 31 | * Gets a string error reason from an error code. 32 | */ 33 | public static String getRequestErrorReason(int errorCode) { 34 | switch (errorCode) { 35 | case AdRequest.ERROR_CODE_INTERNAL_ERROR: 36 | return "Internal error"; 37 | case AdRequest.ERROR_CODE_INVALID_REQUEST: 38 | return "Invalid request"; 39 | case AdRequest.ERROR_CODE_NETWORK_ERROR: 40 | return "Network Error"; 41 | case AdRequest.ERROR_CODE_NO_FILL: 42 | return "No fill"; 43 | case AdRequest.ERROR_CODE_APP_ID_MISSING: 44 | return "App Id Missing"; 45 | default: 46 | return "Unknown error"; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/interstitial/interstitial-definitions.interface.ts: -------------------------------------------------------------------------------- 1 | import type { PluginListenerHandle } from '@capacitor/core'; 2 | 3 | import type { ValidateAllEventsEnumAreImplemented } from '../private/validate-all-events-implemented.type'; 4 | import type { AdLoadInfo, AdMobError, AdOptions } from '../shared'; 5 | 6 | import type { InterstitialAdPluginEvents } from './interstitial-ad-plugin-events.enum'; 7 | 8 | // This is just to validate that we do not forget to implement any event name 9 | export type InterstitialDefinitionsHasAllEvents = 10 | ValidateAllEventsEnumAreImplemented< 11 | InterstitialAdPluginEvents, 12 | InterstitialDefinitions 13 | >; 14 | 15 | export interface InterstitialDefinitions { 16 | /** 17 | * Prepare interstitial banner 18 | * 19 | * @group Interstitial 20 | * @param options AdOptions 21 | * @since 1.1.2 22 | */ 23 | prepareInterstitial(options: AdOptions): Promise; 24 | 25 | /** 26 | * Show interstitial ad when it’s ready 27 | * 28 | * @group Interstitial 29 | * @since 1.1.2 30 | */ 31 | showInterstitial(): Promise; 32 | 33 | addListener( 34 | eventName: InterstitialAdPluginEvents.FailedToLoad, 35 | listenerFunc: (error: AdMobError) => void, 36 | ): Promise; 37 | 38 | addListener( 39 | eventName: InterstitialAdPluginEvents.Loaded, 40 | listenerFunc: (info: AdLoadInfo) => void, 41 | ): Promise; 42 | 43 | addListener( 44 | eventName: InterstitialAdPluginEvents.Dismissed, 45 | listenerFunc: () => void, 46 | ): Promise; 47 | 48 | addListener( 49 | eventName: InterstitialAdPluginEvents.FailedToShow, 50 | listenerFunc: (error: AdMobError) => void, 51 | ): Promise; 52 | 53 | addListener( 54 | eventName: InterstitialAdPluginEvents.Showed, 55 | listenerFunc: () => void, 56 | ): Promise; 57 | } 58 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdCallbackAndListeners.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.interstitial 2 | 3 | import com.getcapacitor.JSObject 4 | import com.getcapacitor.PluginCall 5 | import com.getcapacitor.community.admob.helpers.FullscreenPluginCallback 6 | import com.getcapacitor.community.admob.models.AdMobPluginError 7 | import com.google.android.gms.ads.LoadAdError 8 | import com.google.android.gms.ads.interstitial.InterstitialAd 9 | import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback 10 | import com.google.android.gms.common.util.BiConsumer 11 | 12 | object InterstitialAdCallbackAndListeners { 13 | 14 | fun getInterstitialAdLoadCallback(call: PluginCall, 15 | notifyListenersFunction: BiConsumer, 16 | ): InterstitialAdLoadCallback { 17 | return object : InterstitialAdLoadCallback() { 18 | override fun onAdLoaded(ad: InterstitialAd) { 19 | val immersiveMode = call.getBoolean("immersiveMode") 20 | ad.fullScreenContentCallback = FullscreenPluginCallback(InterstitialAdPluginPluginEvent, notifyListenersFunction) 21 | ad.setImmersiveMode(immersiveMode ?: false) 22 | 23 | AdInterstitialExecutor.interstitialAd = ad 24 | 25 | val adInfo = JSObject() 26 | adInfo.put("adUnitId", ad.adUnitId) 27 | call.resolve(adInfo) 28 | 29 | notifyListenersFunction.accept(InterstitialAdPluginPluginEvent.Loaded, adInfo) 30 | } 31 | 32 | override fun onAdFailedToLoad(adError: LoadAdError) { 33 | val adMobError = AdMobPluginError(adError) 34 | 35 | notifyListenersFunction.accept(InterstitialAdPluginPluginEvent.FailedToLoad, adMobError) 36 | call.reject(adError.message) 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /demo/angular/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /demo/angular/src/app/shared/helper.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, NgZone } from '@angular/core'; 2 | import { ITestItems } from './interfaces'; 3 | import { BannerAdPluginEvents } from '../../../../../dist/esm'; 4 | 5 | @Injectable({ 6 | providedIn: 'root', 7 | }) 8 | export class HelperService { 9 | constructor(private zone: NgZone) {} 10 | 11 | /** 12 | * items is not Deep Copy, this is substitution 13 | */ 14 | public async updateItem(items: ITestItems[], name: string, result: boolean | undefined, value: unknown = undefined) { 15 | this.zone.run(() => { 16 | let isChanged = false; 17 | items = items.map((item) => { 18 | if (item.name === name && item.result === undefined && !isChanged) { 19 | isChanged = true; 20 | if (item.expect === undefined) { 21 | item.result = result; 22 | } else if (Array.isArray(item.expect) && value) { 23 | // @ts-ignore 24 | item.result = item.expect.includes(value.toString()); 25 | } else { 26 | if (item.name === BannerAdPluginEvents.SizeChanged) { 27 | item.result = this.bannerAdPluginEventsSizeChanged( 28 | item.expect as number, 29 | value as { width: number; height: number }, 30 | ); 31 | } else if (item.expect === 'error') { 32 | item.result = this.receiveErrorValue(value); 33 | } 34 | } 35 | } 36 | return item; 37 | }); 38 | }); 39 | await new Promise((resolve) => setTimeout(() => resolve(), 1000)); 40 | } 41 | 42 | private bannerAdPluginEventsSizeChanged(expect: number | string, value: { width: number; height: number }): boolean { 43 | if (expect === 0) { 44 | return value.width === 0 && value.height === 0; 45 | } 46 | return value.width > 0 && value.height > 0; 47 | } 48 | 49 | private receiveErrorValue(value: unknown): boolean { 50 | return typeof value === 'object' && value !== null && 'code' in value && 'message' in value; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /demo/angular/android/.gitignore: -------------------------------------------------------------------------------- 1 | # Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore 2 | 3 | # Built application files 4 | *.apk 5 | *.aar 6 | *.ap_ 7 | *.aab 8 | 9 | # Files for the ART/Dalvik VM 10 | *.dex 11 | 12 | # Java class files 13 | *.class 14 | 15 | # Generated files 16 | bin/ 17 | gen/ 18 | out/ 19 | # Uncomment the following line in case you need and you don't have the release build type files in your app 20 | # release/ 21 | 22 | # Gradle files 23 | .gradle/ 24 | build/ 25 | 26 | # Local configuration file (sdk path, etc) 27 | local.properties 28 | 29 | # Proguard folder generated by Eclipse 30 | proguard/ 31 | 32 | # Log Files 33 | *.log 34 | 35 | # Android Studio Navigation editor temp files 36 | .navigation/ 37 | 38 | # Android Studio captures folder 39 | captures/ 40 | 41 | # IntelliJ 42 | *.iml 43 | .idea/workspace.xml 44 | .idea/tasks.xml 45 | .idea/gradle.xml 46 | .idea/assetWizardSettings.xml 47 | .idea/dictionaries 48 | .idea/libraries 49 | # Android Studio 3 in .gitignore file. 50 | .idea/caches 51 | .idea/modules.xml 52 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 53 | .idea/navEditor.xml 54 | 55 | # Keystore files 56 | # Uncomment the following lines if you do not want to check your keystore files in. 57 | #*.jks 58 | #*.keystore 59 | 60 | # External native build folder generated in Android Studio 2.2 and later 61 | .externalNativeBuild 62 | .cxx/ 63 | 64 | # Google Services (e.g. APIs or Firebase) 65 | # google-services.json 66 | 67 | # Freeline 68 | freeline.py 69 | freeline/ 70 | freeline_project_description.json 71 | 72 | # fastlane 73 | fastlane/report.xml 74 | fastlane/Preview.html 75 | fastlane/screenshots 76 | fastlane/test_output 77 | fastlane/readme.md 78 | 79 | # Version control 80 | vcs.xml 81 | 82 | # lint 83 | lint/intermediates/ 84 | lint/generated/ 85 | lint/outputs/ 86 | lint/tmp/ 87 | # lint/reports/ 88 | 89 | # Android Profiling 90 | *.hprof 91 | 92 | # Cordova plugins for Capacitor 93 | capacitor-cordova-android-plugins 94 | 95 | # Copied web assets 96 | app/src/main/assets/public 97 | -------------------------------------------------------------------------------- /demo/angular/ios/App/App/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/reward/reward-definitions.interface.ts: -------------------------------------------------------------------------------- 1 | import type { PluginListenerHandle } from '@capacitor/core'; 2 | 3 | import type { ValidateAllEventsEnumAreImplemented } from '../private/validate-all-events-implemented.type'; 4 | import type { AdLoadInfo, AdMobError } from '../shared'; 5 | 6 | import type { RewardAdOptions } from './reward-ad-options.interface'; 7 | import type { RewardAdPluginEvents } from './reward-ad-plugin-events.enum'; 8 | import type { AdMobRewardItem } from './reward-item.interface'; 9 | 10 | // This is just to validate that we do not forget to implement any event name 11 | export type RewardDefinitionsHasAllEvents = ValidateAllEventsEnumAreImplemented< 12 | RewardAdPluginEvents, 13 | RewardDefinitions 14 | >; 15 | 16 | export interface RewardDefinitions { 17 | /** 18 | * Prepare a reward video ad 19 | * 20 | * @group RewardVideo 21 | * @param options RewardAdOptions 22 | * @since 1.1.2 23 | */ 24 | prepareRewardVideoAd(options: RewardAdOptions): Promise; 25 | 26 | /** 27 | * Show a reward video ad 28 | * 29 | * @group RewardVideo 30 | * @since 1.1.2 31 | */ 32 | showRewardVideoAd(): Promise; 33 | 34 | addListener( 35 | eventName: RewardAdPluginEvents.FailedToLoad, 36 | listenerFunc: (error: AdMobError) => void, 37 | ): Promise; 38 | 39 | addListener( 40 | eventName: RewardAdPluginEvents.Loaded, 41 | listenerFunc: (info: AdLoadInfo) => void, 42 | ): Promise; 43 | 44 | addListener( 45 | eventName: RewardAdPluginEvents.Rewarded, 46 | listenerFunc: (reward: AdMobRewardItem) => void, 47 | ): Promise; 48 | 49 | addListener( 50 | eventName: RewardAdPluginEvents.Dismissed, 51 | listenerFunc: () => void, 52 | ): Promise; 53 | 54 | addListener( 55 | eventName: RewardAdPluginEvents.FailedToShow, 56 | listenerFunc: (error: AdMobError) => void, 57 | ): Promise; 58 | 59 | addListener( 60 | eventName: RewardAdPluginEvents.Showed, 61 | listenerFunc: () => void, 62 | ): Promise; 63 | } 64 | -------------------------------------------------------------------------------- /.cursor/rules/angular-default.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | alwaysApply: true 3 | --- 4 | 5 | You are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices. 6 | 7 | ## TypeScript Best Practices 8 | 9 | - Use strict type checking 10 | - Prefer type inference when the type is obvious 11 | - Avoid the `any` type; use `unknown` when type is uncertain 12 | 13 | ## Angular Best Practices 14 | 15 | - Always use standalone components over NgModules 16 | - Must NOT set `standalone: true` inside Angular decorators. It's the default. 17 | - Use signals for state management 18 | - Implement lazy loading for feature routes 19 | - Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead 20 | - Use `NgOptimizedImage` for all static images. 21 | - `NgOptimizedImage` does not work for inline base64 images. 22 | 23 | ## Components 24 | 25 | - Keep components small and focused on a single responsibility 26 | - Use `input()` and `output()` functions instead of decorators 27 | - Use `computed()` for derived state 28 | - Set `changeDetection: ChangeDetectionStrategy.OnPush` in `@Component` decorator 29 | - Prefer inline templates for small components 30 | - Prefer Reactive forms instead of Template-driven ones 31 | - Do NOT use `ngClass`, use `class` bindings instead 32 | - Do NOT use `ngStyle`, use `style` bindings instead 33 | 34 | ## State Management 35 | 36 | - Use signals for local component state 37 | - Use `computed()` for derived state 38 | - Keep state transformations pure and predictable 39 | - Do NOT use `mutate` on signals, use `update` or `set` instead 40 | 41 | ## Templates 42 | 43 | - Keep templates simple and avoid complex logic 44 | - Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch` 45 | - Use the async pipe to handle observables 46 | 47 | ## Services 48 | 49 | - Design services around a single responsibility 50 | - Use the `providedIn: 'root'` option for singleton services 51 | - Use the `inject()` function instead of constructor injection 52 | -------------------------------------------------------------------------------- /demo/angular/ios/App/App/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | capacitor-admob 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | GADApplicationIdentifier 24 | ca-app-pub-3940256099942544~1458002511 25 | GADIsAdManagerApp 26 | 27 | LSRequiresIPhoneOS 28 | 29 | NSUserTrackingUsageDescription 30 | This identifier will be used to deliver personalized ads to you 31 | SKAdNetworkItems 32 | 33 | 34 | SKAdNetworkIdentifier 35 | cstr6suwn9.skadnetwork 36 | 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIMainStoryboardFile 41 | Main 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | UISupportedInterfaceOrientations 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UISupportedInterfaceOrientations~ipad 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationPortraitUpsideDown 56 | UIInterfaceOrientationLandscapeLeft 57 | UIInterfaceOrientationLandscapeRight 58 | 59 | UIViewControllerBasedStatusBarAppearance 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /demo/angular/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | namespace "io.ionic.starter" 5 | compileSdk rootProject.ext.compileSdkVersion 6 | defaultConfig { 7 | applicationId "io.ionic.starter" 8 | minSdkVersion rootProject.ext.minSdkVersion 9 | targetSdkVersion rootProject.ext.targetSdkVersion 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | aaptOptions { 14 | // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. 15 | // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61 16 | ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~' 17 | } 18 | } 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | } 26 | 27 | repositories { 28 | flatDir{ 29 | dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' 30 | } 31 | } 32 | 33 | dependencies { 34 | implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion" 35 | implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion" 36 | implementation fileTree(include: ['*.jar'], dir: 'libs') 37 | implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" 38 | implementation project(':capacitor-android') 39 | testImplementation "junit:junit:$junitVersion" 40 | androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" 41 | androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" 42 | implementation project(':capacitor-cordova-android-plugins') 43 | } 44 | 45 | apply from: 'capacitor.build.gradle' 46 | 47 | try { 48 | def servicesJSON = file('google-services.json') 49 | if (servicesJSON.text) { 50 | apply plugin: 'com.google.gms.google-services' 51 | } 52 | } catch(Exception e) { 53 | logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work") 54 | } 55 | -------------------------------------------------------------------------------- /src/reward-interstitial/reward-interstitial-definitions.interface.ts: -------------------------------------------------------------------------------- 1 | import type { PluginListenerHandle } from '@capacitor/core'; 2 | 3 | import type { ValidateAllEventsEnumAreImplemented } from '../private/validate-all-events-implemented.type'; 4 | import type { AdLoadInfo, AdMobError } from '../shared'; 5 | 6 | import type { RewardInterstitialAdOptions } from './reward-interstitial-ad-options.interface'; 7 | import type { RewardInterstitialAdPluginEvents } from './reward-interstitial-ad-plugin-events.enum'; 8 | import type { AdMobRewardInterstitialItem } from './reward-interstitial-item.interface'; 9 | 10 | // This is just to validate that we do not forget to implement any event name 11 | export type RewardInterstitialDefinitionsHasAllEvents = 12 | ValidateAllEventsEnumAreImplemented< 13 | RewardInterstitialAdPluginEvents, 14 | RewardInterstitialDefinitions 15 | >; 16 | 17 | export interface RewardInterstitialDefinitions { 18 | /** 19 | * Prepare a reward video ad 20 | * 21 | * @group RewardVideo 22 | * @param options RewardAdOptions 23 | * @since 1.1.2 24 | */ 25 | prepareRewardInterstitialAd( 26 | options: RewardInterstitialAdOptions, 27 | ): Promise; 28 | 29 | /** 30 | * Show a reward video ad 31 | * 32 | * @group RewardVideo 33 | * @since 1.1.2 34 | */ 35 | showRewardInterstitialAd(): Promise; 36 | 37 | addListener( 38 | eventName: RewardInterstitialAdPluginEvents.FailedToLoad, 39 | listenerFunc: (error: AdMobError) => void, 40 | ): Promise; 41 | 42 | addListener( 43 | eventName: RewardInterstitialAdPluginEvents.Loaded, 44 | listenerFunc: (info: AdLoadInfo) => void, 45 | ): Promise; 46 | 47 | addListener( 48 | eventName: RewardInterstitialAdPluginEvents.Rewarded, 49 | listenerFunc: (reward: AdMobRewardInterstitialItem) => void, 50 | ): Promise; 51 | 52 | addListener( 53 | eventName: RewardInterstitialAdPluginEvents.Dismissed, 54 | listenerFunc: () => void, 55 | ): Promise; 56 | 57 | addListener( 58 | eventName: RewardInterstitialAdPluginEvents.FailedToShow, 59 | listenerFunc: (error: AdMobError) => void, 60 | ): Promise; 61 | 62 | addListener( 63 | eventName: RewardInterstitialAdPluginEvents.Showed, 64 | listenerFunc: () => void, 65 | ): Promise; 66 | } 67 | -------------------------------------------------------------------------------- /demo/angular/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags.ts'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | import './zone-flags'; 46 | 47 | /*************************************************************************************************** 48 | * Zone JS is required by default for Angular itself. 49 | */ 50 | import 'zone.js'; // Included with Angular CLI. 51 | 52 | /*************************************************************************************************** 53 | * APPLICATION IMPORTS 54 | */ 55 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardedInterstitialAdCallbackAndListeners.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.rewardedinterstitial 2 | 3 | import com.getcapacitor.JSObject 4 | import com.getcapacitor.PluginCall 5 | import com.getcapacitor.community.admob.helpers.FullscreenPluginCallback 6 | import com.getcapacitor.community.admob.models.AdMobPluginError 7 | import com.getcapacitor.community.admob.models.AdOptions 8 | import com.google.android.gms.ads.LoadAdError 9 | import com.google.android.gms.ads.OnUserEarnedRewardListener 10 | import com.google.android.gms.ads.rewarded.RewardItem 11 | import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd 12 | import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAdLoadCallback 13 | import com.google.android.gms.common.util.BiConsumer 14 | 15 | object RewardedInterstitialAdCallbackAndListeners { 16 | 17 | fun getOnUserEarnedRewardListener(call: PluginCall, notifyListenersFunction: BiConsumer): OnUserEarnedRewardListener { 18 | return OnUserEarnedRewardListener { item: RewardItem -> 19 | val response = JSObject() 20 | response.put("type", item.type) 21 | .put("amount", item.amount) 22 | notifyListenersFunction.accept(RewardInterstitialAdPluginEvents.Rewarded, response) 23 | call.resolve(response) 24 | } 25 | } 26 | 27 | fun getRewardedAdLoadCallback(call: PluginCall, notifyListenersFunction: BiConsumer, adOptions: AdOptions): RewardedInterstitialAdLoadCallback { 28 | return object : RewardedInterstitialAdLoadCallback() { 29 | override fun onAdLoaded(ad: RewardedInterstitialAd) { 30 | AdRewardInterstitialExecutor.mRewardedInterstitialAd = ad 31 | AdRewardInterstitialExecutor.mRewardedInterstitialAd.fullScreenContentCallback = FullscreenPluginCallback( 32 | RewardInterstitialAdPluginEvents, notifyListenersFunction) 33 | 34 | val adInfo = JSObject() 35 | adInfo.put("adUnitId", ad.adUnitId) 36 | call.resolve(adInfo) 37 | 38 | notifyListenersFunction.accept(RewardInterstitialAdPluginEvents.Loaded, adInfo) 39 | } 40 | 41 | override fun onAdFailedToLoad(adError: LoadAdError) { 42 | val adMobError = AdMobPluginError(adError) 43 | 44 | notifyListenersFunction.accept(RewardInterstitialAdPluginEvents.FailedToLoad, adMobError) 45 | call.reject(adError.message) 46 | } 47 | } 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /BREAKING.md: -------------------------------------------------------------------------------- 1 | # Breaking Changes 2 | ## 1.1.0 3 | - Prepare for iOS 14+ 4 | - In file `ios/App/App/AppDelegate.swift` remove the following: 5 | 6 | ```diff 7 | - import GoogleMobileAds 8 | 9 | @UIApplicationMain 10 | class AppDelegate: UIResponder, UIApplicationDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 15 | - // Override point for customization after application launch. 16 | - GADMobileAds.sharedInstance().start(completionHandler: nil) 17 | ``` 18 | 19 | ## 0.2.13 20 | - isTest: 'LIVE' | 'TESTING' => boolean 21 | 22 | ## 0.2.12 23 | __app.component.ts__ 24 | ```ts 25 | import { Plugins } from '@capacitor/core'; 26 | 27 | const { AdMob } = Plugins; 28 | 29 | @Component({ 30 | selector: 'app-root', 31 | templateUrl: 'app.component.html', 32 | styleUrls: ['app.component.scss'] 33 | }) 34 | export class AppComponent { 35 | constructor(){ 36 | // Initialize AdMob for your Application 37 | + AdMob.initialize('[APP_ID]'); 38 | - AdMob.initialize(); 39 | } 40 | } 41 | ``` 42 | 43 | __admob.component.ts__ 44 | ```ts 45 | import { Plugins } from '@capacitor/core'; 46 | import { AdOptions, AdSize, AdPosition } from '@rdlabo/capacitor-admob'; 47 | 48 | const { AdMob } = Plugins; 49 | 50 | @Component({ 51 | selector: 'admob', 52 | templateUrl: 'admob.component.html', 53 | styleUrls: ['admob.component.scss'] 54 | }) 55 | export class AdMobComponent { 56 | 57 | const options: AdOptions = { 58 | adId: 'YOUR ADID', 59 | adSize: AdSize.BANNER, 60 | position: AdPosition.BOTTOM_CENTER, 61 | - margin: '0', 62 | + margin: 0, 63 | } 64 | 65 | constructor(){ 66 | // Show Banner Ad 67 | AdMob.showBanner(this.options) 68 | .then( 69 | (value) => { 70 | console.log(value); // true 71 | }, 72 | (error) => { 73 | console.error(error); // show error 74 | } 75 | ); 76 | 77 | // Subscibe Banner Event Listener 78 | AdMob.addListener('onAdLoaded', (info: boolean) => { 79 | console.log("Banner Ad Loaded"); 80 | }); 81 | 82 | + // Get Banner Size 83 | + AdMob.addListener('onAdSize', (info: boolean) => { 84 | + console.log(info); 85 | + }); 86 | } 87 | } 88 | ``` 89 | -------------------------------------------------------------------------------- /ios/Sources/AdMobPlugin/Interstitial/AdInterstitialExecutor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Capacitor 3 | import GoogleMobileAds 4 | 5 | class AdInterstitialExecutor: NSObject, FullScreenContentDelegate { 6 | weak var plugin: AdMobPlugin? 7 | var interstitial: InterstitialAd! 8 | 9 | func prepareInterstitial(_ call: CAPPluginCall, _ request: Request, _ adUnitID: String) { 10 | InterstitialAd.load( 11 | with: adUnitID, 12 | request: request, 13 | completionHandler: { (ad, error) in 14 | if let error = error { 15 | NSLog("Rewarded ad failed to load with error: \(error.localizedDescription)") 16 | self.plugin?.notifyListeners(InterstitialAdPluginEvents.FailedToLoad.rawValue, data: [ 17 | "code": 0, 18 | "message": error.localizedDescription 19 | ]) 20 | call.reject("Loading failed") 21 | return 22 | } 23 | 24 | self.interstitial = ad 25 | self.interstitial.fullScreenContentDelegate = self 26 | self.plugin?.notifyListeners(InterstitialAdPluginEvents.Loaded.rawValue, data: [ 27 | "adUnitId": adUnitID 28 | ]) 29 | call.resolve([ 30 | "adUnitId": adUnitID 31 | ]) 32 | } 33 | ) 34 | } 35 | 36 | func showInterstitial(_ call: CAPPluginCall) { 37 | if let rootViewController = plugin?.getRootVC() { 38 | if let ad = self.interstitial { 39 | ad.present(from: rootViewController) 40 | call.resolve([:]) 41 | } else { 42 | NSLog("Ad wasn't ready") 43 | call.reject("Ad wasn't ready") 44 | } 45 | } 46 | } 47 | 48 | func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) { 49 | NSLog("InterstitialFullScreenDelegate Ad failed to present full screen content with error \(error.localizedDescription).") 50 | self.plugin?.notifyListeners(InterstitialAdPluginEvents.FailedToShow.rawValue, data: [ 51 | "code": 0, 52 | "message": error.localizedDescription 53 | ]) 54 | } 55 | 56 | func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) { 57 | NSLog("InterstitialFullScreenDelegate Ad did present full screen content.") 58 | self.plugin?.notifyListeners(InterstitialAdPluginEvents.Showed.rawValue, data: [:]) 59 | } 60 | 61 | func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) { 62 | NSLog("InterstitialFullScreenDelegate Ad did dismiss full screen content.") 63 | self.plugin?.notifyListeners(InterstitialAdPluginEvents.Dismissed.rawValue, data: [:]) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardedAdCallbackAndListeners.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.rewarded 2 | 3 | import com.getcapacitor.JSObject 4 | import com.getcapacitor.PluginCall 5 | import com.getcapacitor.community.admob.helpers.FullscreenPluginCallback 6 | import com.getcapacitor.community.admob.models.AdMobPluginError 7 | import com.getcapacitor.community.admob.models.AdOptions 8 | import com.google.android.gms.ads.LoadAdError 9 | import com.google.android.gms.ads.OnUserEarnedRewardListener 10 | import com.google.android.gms.ads.rewarded.RewardItem 11 | import com.google.android.gms.ads.rewarded.RewardedAd 12 | import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback 13 | import com.google.android.gms.ads.rewarded.ServerSideVerificationOptions 14 | import com.google.android.gms.common.util.BiConsumer 15 | 16 | object RewardedAdCallbackAndListeners { 17 | 18 | fun getOnUserEarnedRewardListener(call: PluginCall, notifyListenersFunction: BiConsumer): OnUserEarnedRewardListener { 19 | return OnUserEarnedRewardListener { item: RewardItem -> 20 | val response = JSObject() 21 | response.put("type", item.type) 22 | .put("amount", item.amount) 23 | notifyListenersFunction.accept(RewardAdPluginEvents.Rewarded, response) 24 | call.resolve(response) 25 | } 26 | } 27 | 28 | fun getRewardedAdLoadCallback(call: PluginCall, notifyListenersFunction: BiConsumer, adOptions: AdOptions): RewardedAdLoadCallback { 29 | return object : RewardedAdLoadCallback() { 30 | override fun onAdLoaded(ad: RewardedAd) { 31 | val immersiveMode = call.getBoolean("immersiveMode") 32 | ad.setImmersiveMode(immersiveMode ?: false) 33 | 34 | AdRewardExecutor.mRewardedAd = ad 35 | AdRewardExecutor.mRewardedAd.fullScreenContentCallback = FullscreenPluginCallback( 36 | RewardAdPluginEvents, notifyListenersFunction) 37 | 38 | if(adOptions.ssvInfo.hasInfo){ 39 | val ssvOptions = ServerSideVerificationOptions.Builder() 40 | adOptions.ssvInfo.customData?.let { 41 | ssvOptions.setCustomData(it) 42 | } 43 | 44 | adOptions.ssvInfo.userId?.let { 45 | ssvOptions.setUserId(it) 46 | } 47 | AdRewardExecutor.mRewardedAd.setServerSideVerificationOptions(ssvOptions.build()) 48 | } 49 | 50 | val adInfo = JSObject() 51 | adInfo.put("adUnitId", ad.adUnitId) 52 | call.resolve(adInfo) 53 | 54 | notifyListenersFunction.accept(RewardAdPluginEvents.Loaded, adInfo) 55 | } 56 | 57 | override fun onAdFailedToLoad(adError: LoadAdError) { 58 | val adMobError = AdMobPluginError(adError) 59 | 60 | notifyListenersFunction.accept(RewardAdPluginEvents.FailedToLoad, adMobError) 61 | call.reject(adError.message) 62 | } 63 | } 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /demo/angular/ios/App/App/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Capacitor 3 | 4 | @UIApplicationMain 5 | class AppDelegate: UIResponder, UIApplicationDelegate { 6 | 7 | var window: UIWindow? 8 | 9 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 10 | // Override point for customization after application launch. 11 | return true 12 | } 13 | 14 | func applicationWillResignActive(_ application: UIApplication) { 15 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 16 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 17 | } 18 | 19 | func applicationDidEnterBackground(_ application: UIApplication) { 20 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 21 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 22 | } 23 | 24 | func applicationWillEnterForeground(_ application: UIApplication) { 25 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 26 | } 27 | 28 | func applicationDidBecomeActive(_ application: UIApplication) { 29 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 30 | } 31 | 32 | func applicationWillTerminate(_ application: UIApplication) { 33 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 34 | } 35 | 36 | func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { 37 | // Called when the app was launched with a url. Feel free to add additional processing here, 38 | // but if you want the App API to support tracking app url opens, make sure to keep this call 39 | return ApplicationDelegateProxy.shared.application(app, open: url, options: options) 40 | } 41 | 42 | func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { 43 | // Called when the app was launched with an activity, including Universal Links. 44 | // Feel free to add additional processing here, but if you want the App API to support 45 | // tracking app url opens, make sure to keep this call 46 | return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler) 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /android/src/test/java/com/getcapacitor/community/admob/helpers/FullscreenPluginCallbackTest.kt: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.helpers 2 | 3 | import com.getcapacitor.JSObject 4 | import com.getcapacitor.community.admob.models.LoadPluginEventNames 5 | import com.google.android.gms.ads.AdError 6 | import com.google.android.gms.ads.FullScreenContentCallback 7 | import com.google.android.gms.common.util.BiConsumer 8 | import org.junit.jupiter.api.* 9 | import org.junit.jupiter.api.extension.ExtendWith 10 | import org.mockito.ArgumentCaptor 11 | import org.mockito.ArgumentMatchers 12 | import org.mockito.Mock 13 | import org.mockito.Mockito 14 | import org.mockito.junit.jupiter.MockitoExtension 15 | 16 | @ExtendWith(MockitoExtension::class) 17 | @TestInstance(TestInstance.Lifecycle.PER_METHOD) 18 | internal class FullscreenPluginCallbackTest { 19 | 20 | object LoadPluginObject: LoadPluginEventNames { 21 | override val Showed: String 22 | get() = "ShowedEvent" 23 | override val FailedToShow: String 24 | get() = "FailedToShowEvent" 25 | override val Dismissed: String 26 | get() = "DismissedEvent" 27 | } 28 | 29 | @Mock 30 | lateinit var notifierMock: BiConsumer 31 | 32 | private lateinit var argumentCaptor: ArgumentCaptor 33 | private lateinit var sut: FullScreenContentCallback 34 | 35 | @BeforeEach 36 | fun beforeEach() { 37 | argumentCaptor = ArgumentCaptor.forClass(JSObject::class.java) 38 | sut = FullscreenPluginCallback(LoadPluginObject, notifierMock) 39 | } 40 | 41 | @Nested 42 | inner class AdShowedFullScreenContent { 43 | 44 | @Test 45 | fun `onAdShowedFullScreenContent call Showed event listener `() { 46 | 47 | // ACt 48 | sut.onAdShowedFullScreenContent() 49 | 50 | Mockito.verify(notifierMock).accept(ArgumentMatchers.eq(LoadPluginObject.Showed), argumentCaptor.capture()) 51 | } 52 | 53 | @Test 54 | fun `onAdFailedToShowFullScreenContent call FailedToShow event listener `() { 55 | val wantedReason = "This is the reason" 56 | val wantedErrorCode = 1 57 | val adErrorMock = Mockito.mock(AdError::class.java); 58 | Mockito.`when`(adErrorMock.code).thenReturn(wantedErrorCode) 59 | Mockito.`when`(adErrorMock.message).thenReturn(wantedReason) 60 | 61 | // ACt 62 | sut.onAdFailedToShowFullScreenContent(adErrorMock) 63 | 64 | Mockito.verify(notifierMock).accept(ArgumentMatchers.eq(LoadPluginObject.FailedToShow), argumentCaptor.capture()) 65 | val emittedError = argumentCaptor.value 66 | 67 | Assertions.assertEquals(wantedErrorCode, emittedError.getInt("code")) 68 | Assertions.assertEquals(wantedReason, emittedError.getString("message")) 69 | } 70 | 71 | @Test 72 | fun `onAdDismissedFullScreenContent call Dismissed event listener `() { 73 | 74 | // ACt 75 | sut.onAdDismissedFullScreenContent() 76 | 77 | Mockito.verify(notifierMock).accept(ArgumentMatchers.eq(LoadPluginObject.Dismissed), argumentCaptor.capture()) 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /android/src/test/java/com/getcapacitor/community/admob/helpers/AdViewIdHelperTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.helpers; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.mockito.ArgumentMatchers.any; 5 | import static org.mockito.Mockito.mock; 6 | import static org.mockito.Mockito.when; 7 | 8 | import android.content.Context; 9 | import android.util.Log; 10 | import com.getcapacitor.community.admob.models.AdOptions; 11 | import com.google.android.gms.ads.AdRequest; 12 | import org.junit.jupiter.api.AfterEach; 13 | import org.junit.jupiter.api.BeforeEach; 14 | import org.junit.jupiter.api.DisplayName; 15 | import org.junit.jupiter.api.Nested; 16 | import org.junit.jupiter.api.Test; 17 | import org.junit.jupiter.api.TestInstance; 18 | import org.junit.jupiter.api.extension.ExtendWith; 19 | import org.mockito.Mock; 20 | import org.mockito.MockedStatic; 21 | import org.mockito.Mockito; 22 | import org.mockito.junit.jupiter.MockitoExtension; 23 | 24 | @ExtendWith(MockitoExtension.class) 25 | @TestInstance(TestInstance.Lifecycle.PER_METHOD) 26 | class AdViewIdHelperTest { 27 | 28 | @Mock 29 | Context contextMock; 30 | 31 | MockedStatic logMockedStatic; 32 | 33 | @BeforeEach 34 | void setUp() { 35 | logMockedStatic = Mockito.mockStatic(Log.class); 36 | } 37 | 38 | @AfterEach 39 | void tearDown() { 40 | logMockedStatic.close(); 41 | } 42 | 43 | @Nested 44 | @DisplayName("#getFinalAdId()") 45 | class GeFinalAdId { 46 | 47 | @Test 48 | @DisplayName("Returns the real adId if the adOptions is not for testing") 49 | void notAdOptionsForTesting() { 50 | final AdOptions adOptions = new AdOptions.TesterAdOptionsBuilder().setIsTesting(false).build(); 51 | 52 | final String returnedId = AdViewIdHelper.getFinalAdId(adOptions, mock(AdRequest.class), "test", contextMock); 53 | 54 | assertEquals(adOptions.adId, returnedId); 55 | } 56 | 57 | @Test 58 | @DisplayName("Returns the real adId if the adOptions is for testing but we are on a registered testing device") 59 | void testingWithATestingDevice() { 60 | final AdOptions adOptions = new AdOptions.TesterAdOptionsBuilder().setIsTesting(true).build(); 61 | final AdRequest adRequest = mock(AdRequest.class); 62 | when(adRequest.isTestDevice(any())).thenReturn(true); 63 | 64 | final String returnedId = AdViewIdHelper.getFinalAdId(adOptions, adRequest, "test", contextMock); 65 | 66 | assertEquals(adOptions.adId, returnedId); 67 | } 68 | 69 | @Test 70 | @DisplayName("Returns the testingId when options are for testing and we are not in a testing device") 71 | void testingWithoutTestingDevice() { 72 | final AdOptions adOptions = new AdOptions.TesterAdOptionsBuilder().setIsTesting(true).build(); 73 | final AdRequest adRequest = mock(AdRequest.class); 74 | when(adRequest.isTestDevice(any())).thenReturn(false); 75 | 76 | final String returnedId = AdViewIdHelper.getFinalAdId(adOptions, adRequest, "test", contextMock); 77 | 78 | assertEquals(adOptions.getTestingId(), returnedId); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /demo/angular/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@capacitor-community/admob", 3 | "version": "8.0.0-0", 4 | "description": "A native plugin for AdMob", 5 | "main": "dist/plugin.cjs.js", 6 | "module": "dist/esm/index.js", 7 | "types": "dist/esm/index.d.ts", 8 | "unpkg": "dist/plugin.js", 9 | "engines": { 10 | "node": ">=22.0.0" 11 | }, 12 | "files": [ 13 | "android/src/main/", 14 | "android/build.gradle", 15 | "dist/", 16 | "ios/Sources", 17 | "ios/Tests", 18 | "Package.swift", 19 | "CapacitorCommunityAdmob.podspec" 20 | ], 21 | "author": "Masahiko Sakakibara ", 22 | "license": "MIT", 23 | "repository": { 24 | "type": "git", 25 | "url": "git@github.com:capacitor-community/admob.git" 26 | }, 27 | "bugs": { 28 | "url": "git@github.com:capacitor-community/admob.git/issues" 29 | }, 30 | "scripts": { 31 | "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", 32 | "verify:ios": "xcodebuild -scheme CapacitorCommunityAdmob -destination generic/platform=iOS", 33 | "verify:android": "cd android && ./gradlew clean build test && cd ..", 34 | "verify:web": "npm run build", 35 | "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", 36 | "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format", 37 | "eslint": "eslint src/. --ext ts", 38 | "prettier": "prettier \"{src/*.ts,**/*.java}\" --plugin=prettier-plugin-java", 39 | "swiftlint": "node-swiftlint", 40 | "docgen": "docgen --api AdMobPlugin --output-readme README.md --output-json dist/docs.json", 41 | "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs", 42 | "clean": "rimraf ./dist", 43 | "watch": "tsc --watch", 44 | "prepublishOnly": "npm run build", 45 | "release": "np --no-tests --no-publish", 46 | "prepare": "husky" 47 | }, 48 | "devDependencies": { 49 | "@capacitor/android": "^8.0.0", 50 | "@capacitor/cli": "^8.0.0", 51 | "@capacitor/core": "^8.0.0", 52 | "@capacitor/ios": "^8.0.0", 53 | "@ionic/eslint-config": "^0.4.0", 54 | "@ionic/prettier-config": "^4.0.0", 55 | "@ionic/swiftlint-config": "^2.0.0", 56 | "@typescript-eslint/eslint-plugin": "^5.27.1", 57 | "eslint": "^8.57.1", 58 | "husky": "^9.1.7", 59 | "lint-staged": "^15.2.10", 60 | "np": "^8.0.4", 61 | "pre-commit": "^1.2.2", 62 | "prettier": "^3.6.2", 63 | "prettier-plugin-java": "^2.7.7", 64 | "rimraf": "^6.1.0", 65 | "rollup": "^4.53.2", 66 | "swiftlint": "^2.0.0", 67 | "typescript": "^5.9.3" 68 | }, 69 | "dependencies": { 70 | "@capacitor/core": "^8.0.0", 71 | "@rdlabo/capacitor-docgen": "^0.4.1" 72 | }, 73 | "lint-staged": { 74 | "*.{ts}": [ 75 | "npm run prettier -- --write", 76 | "git add" 77 | ], 78 | "*.{java}": [ 79 | "npm run prettier -- --write", 80 | "git add" 81 | ] 82 | }, 83 | "prettier": "@ionic/prettier-config", 84 | "swiftlint": "@ionic/swiftlint-config", 85 | "eslintConfig": { 86 | "extends": "@ionic/eslint-config/recommended" 87 | }, 88 | "keywords": [ 89 | "capacitor", 90 | "plugin", 91 | "native" 92 | ], 93 | "capacitor": { 94 | "ios": { 95 | "src": "ios" 96 | }, 97 | "android": { 98 | "src": "android" 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/rewarded/AdRewardExecutor.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.rewarded; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import androidx.core.util.Supplier; 6 | import com.getcapacitor.JSObject; 7 | import com.getcapacitor.PluginCall; 8 | import com.getcapacitor.PluginMethod; 9 | import com.getcapacitor.community.admob.helpers.AdViewIdHelper; 10 | import com.getcapacitor.community.admob.helpers.RequestHelper; 11 | import com.getcapacitor.community.admob.models.AdMobPluginError; 12 | import com.getcapacitor.community.admob.models.AdOptions; 13 | import com.getcapacitor.community.admob.models.Executor; 14 | import com.google.android.gms.ads.AdRequest; 15 | import com.google.android.gms.ads.rewarded.RewardedAd; 16 | import com.google.android.gms.common.util.BiConsumer; 17 | 18 | public class AdRewardExecutor extends Executor { 19 | 20 | public static RewardedAd mRewardedAd; 21 | 22 | public AdRewardExecutor( 23 | Supplier contextSupplier, 24 | Supplier activitySupplier, 25 | BiConsumer notifyListenersFunction, 26 | String pluginLogTag 27 | ) { 28 | super(contextSupplier, activitySupplier, notifyListenersFunction, pluginLogTag, "AdRewardExecutor"); 29 | } 30 | 31 | @PluginMethod 32 | public void prepareRewardVideoAd(final PluginCall call, BiConsumer notifyListenersFunction) { 33 | final AdOptions adOptions = AdOptions.getFactory().createRewardVideoOptions(call); 34 | 35 | activitySupplier 36 | .get() 37 | .runOnUiThread(() -> { 38 | try { 39 | final AdRequest adRequest = RequestHelper.createRequest(adOptions); 40 | final String id = AdViewIdHelper.getFinalAdId(adOptions, adRequest, logTag, contextSupplier.get()); 41 | RewardedAd.load( 42 | contextSupplier.get(), 43 | id, 44 | adRequest, 45 | RewardedAdCallbackAndListeners.INSTANCE.getRewardedAdLoadCallback(call, notifyListenersFunction, adOptions) 46 | ); 47 | } catch (Exception ex) { 48 | call.reject(ex.getLocalizedMessage(), ex); 49 | } 50 | }); 51 | } 52 | 53 | @PluginMethod 54 | public void showRewardVideoAd(final PluginCall call, BiConsumer notifyListenersFunction) { 55 | if (mRewardedAd == null) { 56 | String errorMessage = "No Reward Video Ad can be shown. It was not prepared or maybe it failed to be prepared."; 57 | call.reject(errorMessage); 58 | AdMobPluginError errorObject = new AdMobPluginError(-1, errorMessage); 59 | notifyListenersFunction.accept(RewardAdPluginEvents.FailedToLoad, errorObject); 60 | return; 61 | } 62 | 63 | try { 64 | activitySupplier 65 | .get() 66 | .runOnUiThread(() -> { 67 | mRewardedAd.show( 68 | activitySupplier.get(), 69 | RewardedAdCallbackAndListeners.INSTANCE.getOnUserEarnedRewardListener(call, notifyListenersFunction) 70 | ); 71 | }); 72 | } catch (Exception ex) { 73 | call.reject(ex.getLocalizedMessage(), ex); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /demo/angular/src/app/home/home.page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | capacitor-admob 4 | 5 | 6 | 7 | 8 | 9 | 10 | capacitor-admob 11 | 12 | 13 | 14 | @if (isLoading) { 15 |
16 | 17 |
18 | } 19 | 20 | 21 | 22 | Consent 23 | 24 | Request Consent Info 25 | Show Consent Form 26 | Reset Consent Info 27 | 28 | 29 | 30 | Banner 31 | @if (lastBannerEvent$ | async; as lastBannerEvent) { 32 |
(Last Event: {{lastBannerEvent.name }} | {{lastBannerEvent.value | json}}) 33 | } 34 |
35 | 36 | Banner Size 37 | 38 | Default 39 | @for (size of bannerSizes; track size) { 40 | {{size}} 41 | } 42 | 43 | 44 | Show Top Banner 45 | Show Bottom Banner 46 | Hide Banner 47 | Resume Banner 48 | Remove Banner 49 |
50 | 51 | 52 | Interstitial 53 | @if (lastInterstitialEvent$ | async; as lastInterstitialEvent) { 54 |
(Last Event: {{lastInterstitialEvent.name }} | {{lastInterstitialEvent.value | json}}) 55 | } 56 | 57 |
58 | 59 | Prepare Interstitial 60 | Show Interstitial 61 |
62 | 63 | 64 | Reward 65 | @if (lastRewardEvent$ | async; as lastRewardEvent) { 66 |
(Last Event: {{lastRewardEvent.name }} | {{lastRewardEvent.value | json}}) 67 | } 68 | 69 |
70 | Prepare Reward 71 | Show Reward 72 |
73 |
74 | 75 | 76 | Footer Components 77 | 78 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/interstitial/AdInterstitialExecutor.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.interstitial; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import androidx.core.util.Supplier; 6 | import com.getcapacitor.JSObject; 7 | import com.getcapacitor.PluginCall; 8 | import com.getcapacitor.community.admob.helpers.AdViewIdHelper; 9 | import com.getcapacitor.community.admob.helpers.RequestHelper; 10 | import com.getcapacitor.community.admob.models.AdMobPluginError; 11 | import com.getcapacitor.community.admob.models.AdOptions; 12 | import com.getcapacitor.community.admob.models.Executor; 13 | import com.google.android.gms.ads.AdRequest; 14 | import com.google.android.gms.ads.interstitial.InterstitialAd; 15 | import com.google.android.gms.common.util.BiConsumer; 16 | 17 | public class AdInterstitialExecutor extends Executor { 18 | 19 | public static InterstitialAd interstitialAd; 20 | 21 | InterstitialAdCallbackAndListeners adCallbackAndListeners; 22 | 23 | public AdInterstitialExecutor( 24 | Supplier contextSupplier, 25 | Supplier activitySupplier, 26 | BiConsumer notifyListenersFunction, 27 | String pluginLogTag, 28 | InterstitialAdCallbackAndListeners adCallbackAndListeners 29 | ) { 30 | super(contextSupplier, activitySupplier, notifyListenersFunction, pluginLogTag, "AdRewardExecutor"); 31 | this.adCallbackAndListeners = adCallbackAndListeners; 32 | } 33 | 34 | public void prepareInterstitial(final PluginCall call, BiConsumer notifyListenersFunction) { 35 | final AdOptions.AdOptionsFactory factory = AdOptions.getFactory(); 36 | final AdOptions adOptions = factory.createInterstitialOptions(call); 37 | 38 | try { 39 | activitySupplier 40 | .get() 41 | .runOnUiThread(() -> { 42 | final AdRequest adRequest = RequestHelper.createRequest(adOptions); 43 | final String id = AdViewIdHelper.getFinalAdId(adOptions, adRequest, logTag, contextSupplier.get()); 44 | InterstitialAd.load( 45 | activitySupplier.get(), 46 | id, 47 | adRequest, 48 | adCallbackAndListeners.getInterstitialAdLoadCallback(call, notifyListenersFunction) 49 | ); 50 | }); 51 | } catch (Exception ex) { 52 | call.reject(ex.getLocalizedMessage(), ex); 53 | } 54 | } 55 | 56 | public void showInterstitial(final PluginCall call, BiConsumer notifyListenersFunction) { 57 | if (interstitialAd == null) { 58 | String errorMessage = "No Interstitial can be shown. It was not prepared or maybe it failed to be prepared."; 59 | call.reject(errorMessage); 60 | AdMobPluginError errorObject = new AdMobPluginError(-1, errorMessage); 61 | notifyListenersFunction.accept(InterstitialAdPluginPluginEvent.FailedToLoad, errorObject); 62 | return; 63 | } 64 | 65 | activitySupplier 66 | .get() 67 | .runOnUiThread(() -> { 68 | try { 69 | interstitialAd.show(activitySupplier.get()); 70 | call.resolve(); 71 | } catch (Exception ex) { 72 | call.reject(ex.getLocalizedMessage(), ex); 73 | } 74 | }); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/banner/banner-definitions.interface.ts: -------------------------------------------------------------------------------- 1 | import type { PluginListenerHandle } from '@capacitor/core'; 2 | 3 | import type { ValidateAllEventsEnumAreImplemented } from '../private/validate-all-events-implemented.type'; 4 | import type { AdMobError } from '../shared'; 5 | 6 | import type { BannerAdOptions } from './banner-ad-options.interface'; 7 | import type { BannerAdPluginEvents } from './banner-ad-plugin-events.enum'; 8 | import type { AdMobBannerSize } from './banner-size.interface'; 9 | 10 | // This is just to validate that we do not forget to implement any event name 11 | export type BannerDefinitionsHasAllEvents = ValidateAllEventsEnumAreImplemented< 12 | BannerAdPluginEvents, 13 | BannerDefinitions 14 | >; 15 | 16 | export interface BannerDefinitions { 17 | /** 18 | * Show a banner Ad 19 | * 20 | * @group Banner 21 | * @param options AdOptions 22 | * @since 1.1.2 23 | */ 24 | showBanner(options: BannerAdOptions): Promise; 25 | 26 | /** 27 | * Hide the banner, remove it from screen, but can show it later 28 | * 29 | * @group Banner 30 | * @since 1.1.2 31 | */ 32 | hideBanner(): Promise; 33 | 34 | /** 35 | * Resume the banner, show it after hide 36 | * 37 | * @group Banner 38 | * @since 1.1.2 39 | */ 40 | resumeBanner(): Promise; 41 | 42 | /** 43 | * Destroy the banner, remove it from screen. 44 | * 45 | * @group Banner 46 | * @since 1.1.2 47 | */ 48 | removeBanner(): Promise; 49 | 50 | /** 51 | * 52 | * @group Banner 53 | * @param eventName bannerAdSizeChanged 54 | * @param listenerFunc 55 | * @since 3.0.0 56 | */ 57 | addListener( 58 | eventName: BannerAdPluginEvents.SizeChanged, 59 | listenerFunc: (info: AdMobBannerSize) => void, 60 | ): Promise; 61 | 62 | /** 63 | * Notice: request loaded Banner ad 64 | * 65 | * @group Banner 66 | * @param eventName bannerAdLoaded 67 | * @param listenerFunc 68 | * @since 3.0.0 69 | */ 70 | addListener( 71 | eventName: BannerAdPluginEvents.Loaded, 72 | listenerFunc: () => void, 73 | ): Promise; 74 | 75 | /** 76 | * Notice: request failed Banner ad 77 | * 78 | * @group Banner 79 | * @param eventName bannerAdFailedToLoad 80 | * @param listenerFunc 81 | * @since 3.0.0 82 | */ 83 | addListener( 84 | eventName: BannerAdPluginEvents.FailedToLoad, 85 | listenerFunc: (info: AdMobError) => void, 86 | ): Promise; 87 | 88 | /** 89 | * Notice: full-screen banner view will be presented in response to the user clicking on an ad. 90 | * 91 | * @group Banner 92 | * @param eventName bannerAdOpened 93 | * @param listenerFunc 94 | * @since 3.0.0 95 | */ 96 | addListener( 97 | eventName: BannerAdPluginEvents.Opened, 98 | listenerFunc: () => void, 99 | ): Promise; 100 | 101 | /** 102 | * Notice: The full-screen banner view will been dismissed. 103 | * 104 | * @group Banner 105 | * @param eventName bannerAdClosed 106 | * @param listenerFunc 107 | * @since 3.0.0 108 | */ 109 | addListener( 110 | eventName: BannerAdPluginEvents.Closed, 111 | listenerFunc: () => void, 112 | ): Promise; 113 | 114 | /** 115 | * Unimplemented 116 | * 117 | * @group Banner 118 | * @param eventName AdImpression 119 | * @param listenerFunc 120 | * @since 3.0.0 121 | */ 122 | addListener( 123 | eventName: BannerAdPluginEvents.AdImpression, 124 | listenerFunc: () => void, 125 | ): Promise; 126 | } 127 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab2/tab2.page.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { AdMob, InterstitialAdPluginEvents } from '@capacitor-community/admob'; 3 | import { ITestItems } from '../../shared/interfaces'; 4 | import { PluginListenerHandle } from '@capacitor/core'; 5 | import { 6 | IonContent, 7 | IonHeader, 8 | IonIcon, 9 | IonItem, 10 | IonLabel, 11 | IonList, 12 | IonListHeader, 13 | IonTitle, 14 | IonToolbar, 15 | ViewDidEnter, 16 | ViewWillEnter, 17 | ViewWillLeave, 18 | } from '@ionic/angular/standalone'; 19 | import { interstitialOptions } from '../../shared/ad.options'; 20 | import { HelperService } from '../../shared/helper.service'; 21 | import { addIcons } from 'ionicons'; 22 | import { checkmarkCircle, notificationsCircleOutline, playOutline } from 'ionicons/icons'; 23 | 24 | const tryItems: ITestItems[] = [ 25 | { 26 | type: 'method', 27 | name: 'prepareInterstitial', 28 | }, 29 | { 30 | type: 'method', 31 | name: 'showInterstitial', 32 | }, 33 | { 34 | type: 'event', 35 | name: InterstitialAdPluginEvents.Loaded, 36 | }, 37 | { 38 | type: 'event', 39 | name: InterstitialAdPluginEvents.Showed, 40 | }, 41 | { 42 | type: 'event', 43 | name: InterstitialAdPluginEvents.Dismissed, 44 | }, 45 | { 46 | type: 'method', 47 | name: 'prepareInterstitialFailed', 48 | }, 49 | { 50 | type: 'event', 51 | name: InterstitialAdPluginEvents.FailedToLoad, 52 | expect: 'error', 53 | }, 54 | ]; 55 | 56 | @Component({ 57 | selector: 'app-tab2', 58 | templateUrl: 'tab2.page.html', 59 | styleUrls: ['tab2.page.scss'], 60 | imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonListHeader, IonLabel, IonItem, IonIcon], 61 | }) 62 | export class Tab2Page implements ViewDidEnter, ViewWillEnter, ViewWillLeave { 63 | private readonly listenerHandlers: PluginListenerHandle[] = []; 64 | public eventItems: ITestItems[] = []; 65 | constructor(private helper: HelperService) { 66 | addIcons({ playOutline, notificationsCircleOutline, checkmarkCircle }); 67 | } 68 | 69 | ionViewWillEnter() { 70 | const eventKeys = Object.keys(InterstitialAdPluginEvents); 71 | eventKeys.forEach(async (key) => { 72 | const eventName = InterstitialAdPluginEvents[key as keyof typeof InterstitialAdPluginEvents]; 73 | const handler = AdMob.addListener(eventName as any, (value: unknown) => { 74 | this.helper.updateItem(this.eventItems, eventName, true, value); 75 | if (key === 'Dismissed') { 76 | AdMob.prepareInterstitial({ adId: 'failed' }) 77 | .then(async () => await this.helper.updateItem(this.eventItems, 'prepareInterstitialFailed', false)) 78 | .catch(async () => await this.helper.updateItem(this.eventItems, 'prepareInterstitialFailed', true)); 79 | } 80 | }); 81 | this.listenerHandlers.push(await handler); 82 | }); 83 | 84 | this.eventItems = JSON.parse(JSON.stringify(tryItems)); 85 | } 86 | 87 | async ionViewDidEnter() { 88 | await AdMob.prepareInterstitial(interstitialOptions) 89 | .then(async (data) => await this.helper.updateItem(this.eventItems, 'prepareInterstitial', !!data.adUnitId)) 90 | .catch(async () => await this.helper.updateItem(this.eventItems, 'prepareInterstitial', false)); 91 | 92 | await AdMob.showInterstitial() 93 | .then(async () => await this.helper.updateItem(this.eventItems, 'showInterstitial', true)) 94 | .catch(async () => await this.helper.updateItem(this.eventItems, 'showInterstitial', false)); 95 | } 96 | 97 | ionViewWillLeave() { 98 | this.listenerHandlers.forEach((handler) => handler.remove()); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/AdRewardInterstitialExecutor.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.admob.rewardedinterstitial; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import androidx.core.util.Supplier; 6 | import com.getcapacitor.JSObject; 7 | import com.getcapacitor.PluginCall; 8 | import com.getcapacitor.PluginMethod; 9 | import com.getcapacitor.community.admob.helpers.AdViewIdHelper; 10 | import com.getcapacitor.community.admob.helpers.RequestHelper; 11 | import com.getcapacitor.community.admob.models.AdMobPluginError; 12 | import com.getcapacitor.community.admob.models.AdOptions; 13 | import com.getcapacitor.community.admob.models.Executor; 14 | import com.google.android.gms.ads.AdRequest; 15 | import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd; 16 | import com.google.android.gms.common.util.BiConsumer; 17 | 18 | public class AdRewardInterstitialExecutor extends Executor { 19 | 20 | public static RewardedInterstitialAd mRewardedInterstitialAd; 21 | 22 | public AdRewardInterstitialExecutor( 23 | Supplier contextSupplier, 24 | Supplier activitySupplier, 25 | BiConsumer notifyListenersFunction, 26 | String pluginLogTag 27 | ) { 28 | super(contextSupplier, activitySupplier, notifyListenersFunction, pluginLogTag, "AdRewardExecutor"); 29 | } 30 | 31 | @PluginMethod 32 | public void prepareRewardInterstitialAd(final PluginCall call, BiConsumer notifyListenersFunction) { 33 | final AdOptions adOptions = AdOptions.getFactory().createRewardInterstitialOptions(call); 34 | 35 | activitySupplier 36 | .get() 37 | .runOnUiThread(() -> { 38 | try { 39 | final AdRequest adRequest = RequestHelper.createRequest(adOptions); 40 | final String id = AdViewIdHelper.getFinalAdId(adOptions, adRequest, logTag, contextSupplier.get()); 41 | RewardedInterstitialAd.load( 42 | contextSupplier.get(), 43 | id, 44 | adRequest, 45 | RewardedInterstitialAdCallbackAndListeners.INSTANCE.getRewardedAdLoadCallback( 46 | call, 47 | notifyListenersFunction, 48 | adOptions 49 | ) 50 | ); 51 | } catch (Exception ex) { 52 | call.reject(ex.getLocalizedMessage(), ex); 53 | } 54 | }); 55 | } 56 | 57 | @PluginMethod 58 | public void showRewardInterstitialAd(final PluginCall call, BiConsumer notifyListenersFunction) { 59 | if (mRewardedInterstitialAd == null) { 60 | String errorMessage = "No Reward Interstitial Video Ad can be shown. It was not prepared or maybe it failed to be prepared."; 61 | call.reject(errorMessage); 62 | AdMobPluginError errorObject = new AdMobPluginError(-1, errorMessage); 63 | notifyListenersFunction.accept(RewardInterstitialAdPluginEvents.FailedToLoad, errorObject); 64 | return; 65 | } 66 | 67 | try { 68 | activitySupplier 69 | .get() 70 | .runOnUiThread(() -> { 71 | mRewardedInterstitialAd.show( 72 | activitySupplier.get(), 73 | RewardedInterstitialAdCallbackAndListeners.INSTANCE.getOnUserEarnedRewardListener(call, notifyListenersFunction) 74 | ); 75 | }); 76 | } catch (Exception ex) { 77 | call.reject(ex.getLocalizedMessage(), ex); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /demo/angular/src/app/validation/tab3/tab3.page.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { AdMob, RewardAdPluginEvents } from '@capacitor-community/admob'; 3 | import { ITestItems } from '../../shared/interfaces'; 4 | import { 5 | IonContent, 6 | IonHeader, 7 | IonIcon, 8 | IonItem, 9 | IonLabel, 10 | IonList, 11 | IonListHeader, 12 | IonTitle, 13 | IonToolbar, 14 | ViewDidEnter, 15 | ViewWillEnter, 16 | ViewWillLeave, 17 | } from '@ionic/angular/standalone'; 18 | import { PluginListenerHandle } from '@capacitor/core'; 19 | import { rewardOptions } from '../../shared/ad.options'; 20 | import { HelperService } from '../../shared/helper.service'; 21 | import { addIcons } from 'ionicons'; 22 | import { checkmarkCircle, notificationsCircleOutline, playOutline } from 'ionicons/icons'; 23 | 24 | const tryItems: ITestItems[] = [ 25 | { 26 | type: 'method', 27 | name: 'prepareRewardVideoAd', 28 | }, 29 | { 30 | type: 'method', 31 | name: 'showRewardVideoAd', 32 | }, 33 | { 34 | type: 'event', 35 | name: RewardAdPluginEvents.Loaded, 36 | }, 37 | { 38 | type: 'event', 39 | name: RewardAdPluginEvents.Showed, 40 | }, 41 | { 42 | type: 'event', 43 | name: RewardAdPluginEvents.Rewarded, 44 | }, 45 | { 46 | type: 'event', 47 | name: RewardAdPluginEvents.Dismissed, 48 | }, 49 | { 50 | type: 'method', 51 | name: 'prepareRewardVideoAdFailed', 52 | }, 53 | { 54 | type: 'event', 55 | name: RewardAdPluginEvents.FailedToLoad, 56 | expect: 'error', 57 | }, 58 | ]; 59 | 60 | @Component({ 61 | selector: 'app-tab3', 62 | templateUrl: 'tab3.page.html', 63 | styleUrls: ['tab3.page.scss'], 64 | imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonListHeader, IonLabel, IonItem, IonIcon], 65 | }) 66 | export class Tab3Page implements ViewDidEnter, ViewWillEnter, ViewWillLeave { 67 | private readonly listenerHandlers: PluginListenerHandle[] = []; 68 | public eventItems: ITestItems[] = []; 69 | constructor(private helper: HelperService) { 70 | addIcons({ playOutline, notificationsCircleOutline, checkmarkCircle }); 71 | } 72 | 73 | ionViewWillEnter() { 74 | const eventKeys = Object.keys(RewardAdPluginEvents); 75 | eventKeys.forEach(async (key) => { 76 | const eventName = RewardAdPluginEvents[key as keyof typeof RewardAdPluginEvents]; 77 | const handler = AdMob.addListener(eventName as any, (value: unknown) => { 78 | if (key === 'Dismissed') { 79 | AdMob.prepareRewardVideoAd({ adId: 'failed' }) 80 | .then(async () => await this.helper.updateItem(this.eventItems, 'prepareRewardVideoAdFailed', false)) 81 | .catch(async () => await this.helper.updateItem(this.eventItems, 'prepareRewardVideoAdFailed', true)); 82 | } 83 | this.helper.updateItem(this.eventItems, eventName, true, value); 84 | }); 85 | this.listenerHandlers.push(await handler); 86 | }); 87 | 88 | this.eventItems = JSON.parse(JSON.stringify(tryItems)); 89 | } 90 | 91 | async ionViewDidEnter() { 92 | await AdMob.prepareRewardVideoAd(rewardOptions) 93 | .then(async (data) => await this.helper.updateItem(this.eventItems, 'prepareRewardVideoAd', !!data.adUnitId)) 94 | .catch(async () => await this.helper.updateItem(this.eventItems, 'prepareRewardVideoAd', false)); 95 | await AdMob.showRewardVideoAd() 96 | .then(async () => await this.helper.updateItem(this.eventItems, 'showRewardVideoAd', true)) 97 | .catch(async () => await this.helper.updateItem(this.eventItems, 'showRewardVideoAd', false)); 98 | } 99 | 100 | ionViewWillLeave() { 101 | this.listenerHandlers.forEach((handler) => handler.remove()); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /ios/Sources/AdMobPlugin/Rewarded/AdRewardExecutor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Capacitor 3 | import GoogleMobileAds 4 | 5 | class AdRewardExecutor: NSObject, FullScreenContentDelegate { 6 | weak var plugin: AdMobPlugin? 7 | var rewardedAd: RewardedAd! 8 | 9 | func prepareRewardVideoAd(_ call: CAPPluginCall, _ request: Request, _ adUnitID: String) { 10 | RewardedAd.load( 11 | with: adUnitID, 12 | request: request, 13 | completionHandler: { (ad, error) in 14 | if let error = error { 15 | NSLog("Rewarded ad failed to load with error: \(error.localizedDescription)") 16 | self.plugin?.notifyListeners(RewardAdPluginEvents.FailedToLoad.rawValue, data: [ 17 | "code": 0, 18 | "message": error.localizedDescription 19 | ]) 20 | call.reject("Loading failed") 21 | return 22 | } 23 | 24 | self.rewardedAd = ad 25 | 26 | if let providedOptions = call.getObject("ssv") { 27 | let ssvOptions = ServerSideVerificationOptions() 28 | 29 | if let customData = providedOptions["customData"] as? String { 30 | NSLog("Sending Custom Data: \(customData) to SSV callback") 31 | ssvOptions.customRewardText = customData 32 | } 33 | 34 | if let userId = providedOptions["userId"] as? String { 35 | NSLog("Sending UserId: \(userId) to SSV callback") 36 | ssvOptions.userIdentifier = userId 37 | } 38 | 39 | self.rewardedAd?.serverSideVerificationOptions = ssvOptions 40 | } 41 | 42 | self.rewardedAd?.fullScreenContentDelegate = self 43 | self.plugin?.notifyListeners(RewardAdPluginEvents.Loaded.rawValue, data: [ 44 | "adUnitId": adUnitID 45 | ]) 46 | call.resolve([ 47 | "adUnitId": adUnitID 48 | ]) 49 | } 50 | ) 51 | } 52 | 53 | func showRewardVideoAd(_ call: CAPPluginCall) { 54 | if let rootViewController = plugin?.getRootVC() { 55 | if let ad = self.rewardedAd { 56 | ad.present(from: rootViewController, 57 | userDidEarnRewardHandler: { 58 | let reward = ad.adReward 59 | self.plugin?.notifyListeners(RewardAdPluginEvents.Rewarded.rawValue, data: ["type": reward.type, "amount": reward.amount]) 60 | call.resolve(["type": reward.type, "amount": reward.amount]) 61 | } 62 | ) 63 | } else { 64 | call.reject("Reward Video is Not Ready Yet") 65 | } 66 | } 67 | } 68 | 69 | func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) { 70 | NSLog("RewardFullScreenDelegate Ad failed to present full screen content with error \(error.localizedDescription).") 71 | self.plugin?.notifyListeners(RewardAdPluginEvents.FailedToShow.rawValue, data: [ 72 | "code": 0, 73 | "message": error.localizedDescription 74 | ]) 75 | } 76 | 77 | func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) { 78 | NSLog("RewardFullScreenDelegate Ad did present full screen content.") 79 | self.plugin?.notifyListeners(RewardAdPluginEvents.Showed.rawValue, data: [:]) 80 | } 81 | 82 | func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) { 83 | NSLog("RewardFullScreenDelegate Ad did dismiss full screen content.") 84 | self.plugin?.notifyListeners(RewardAdPluginEvents.Dismissed.rawValue, data: [:]) 85 | } 86 | } 87 | --------------------------------------------------------------------------------