Skip to content

[Feature]: Loading and showing ads are too slow #10

Description

@ezzuah

What i've noticed is, its very slow when you intialized the sdk and show a banner, it something takes between 5 to 7 seconds to complete the initialization and then show the banner. I do call the ads initialize function in the app.component so i get it to run quickly but like i said its slow.
Another thing on interstitials is also it something takes about 5 to 6 seconds to load it.
I'm reporting because as compared to the admob-plus plugin, it takes between 2 to 3 seconds to load a banner or an interstitial.
Its a great work you've done so far

I'm pasting my code below

import { Injectable, NgZone } from '@angular/core';
import { Platform } from '@ionic/angular';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';

import { environment } from 'src/environments/environment';

declare var admobNextGen: any;



@Injectable({
  providedIn: 'root',
})
export class AdmobServices {

  private admob: any = null;
  private isSdkInitialized = false;
  private pendingLoadOnPause = false;



  isShowingFullscreenAd = false;
  isAdSuppressed = false;

  private lastFullscreenDismissedTime = 0;
  private readonly FULLSCREEN_RESUME_DELAY = 1500;



  rewardedAd: any;
  hasUserGotReward = false;
  rewardEarned$ = new Subject<void>();

  private rewardResolver: ((rewarded: boolean) => void) | null = null;
  private rewardPendingShow = false;



  bannerAd: any;



  appOpenAd: any;
  appOpenDismissed$ = new Subject<void>();
  lastAppOpenShownTime = 0;
  readonly APP_OPEN_COOLDOWN = 30000;

  constructor(
    private platform: Platform,
    private zone: NgZone,
  ) {
    this.setupAdEvents();
    this.setupAppOpenLifecycle();
  }

  // Helper to dynamically resolve global plugin reference
  private resolveAdMob(): any {
    if (this.admob) return this.admob;
    this.admob =
      (window as any).admobNextGen ||
      (typeof admobNextGen !== 'undefined' ? admobNextGen : null);
    return this.admob;
  }

  // ==================================================
  // INITIALIZATION
  // ==================================================

  async initializeAds(): Promise<void> {
    await this.platform.ready();

    const admob = this.resolveAdMob();

    if (!admob) {
      console.error('AdMob Next Gen not available.');
      return;
    }

    admob.initialize(
      {
        maxAdContentRating: 'G',
        tagForChildDirectedTreatment: false,
        tagForUnderAgeOfConsent: false,
      },
      () => {
        this.zone.run(() => {
          this.isSdkInitialized = true;
          this.showBannerAd();

          // If the user backgrounded the app while SDK was initializing, trigger load now
          if (this.pendingLoadOnPause) {
            this.pendingLoadOnPause = false;
            this.loadAppOpenAd();
          }
        });
      },
      (error: any) => console.error('AdMob initialization failed:', error),
    );
  }

  // ==================================================
  // BANNER
  // ==================================================

  async showBannerAd(): Promise<void> {
    await this.platform.ready();
    const admob = this.resolveAdMob();
    if (!admob || this.bannerAd) {
      return;
    }

    try {
      admob.createBanner({
        adUnitId: environment.androidBannerAdId,
        position: 'bottom',
        size: 'ADAPTIVE',
        isOverlapping: false,
        collapsible: true,
        retryInterval: 5000,
      });
      this.bannerAd = true;
    } catch (error) {
      console.error('Error creating banner:', error);
    }
  }

  async hideBanner(): Promise<void> {
    await this.platform.ready();
    const admob = this.resolveAdMob();
    if (!admob || !this.bannerAd) {
      return;
    }

    try {
      admob.removeBanner();
      this.bannerAd = false;
    } catch (error) {
      console.error('Error removing banner:', error);
    }
  }

  // ==================================================
  // INTERSTITIAL
  // ==================================================

  async loadInterstitialAd(): Promise<void> {
    await this.platform.ready();
    const admob = this.resolveAdMob();
    if (!admob) {
      return;
    }

    try {
      admob.createInterstitial({
        adUnitId: environment.androidInterstitialAdId,
        isAutoShow: false,
        retryInterval: 5000,
      });
    } catch (error) {
      console.error('Error creating interstitial:', error);
    }
  }

  async showInterstitialAd() {
    await this.platform.ready();
    const admob = this.resolveAdMob();

    this.isShowingFullscreenAd = true;

    try {
      admob.showInterstitial();
    } catch (error) {
      console.error('Error showing interstitial:', error);
      this.isShowingFullscreenAd = false;
      this.lastFullscreenDismissedTime = Date.now();
    }
  }

  // ==================================================
  // REWARDED
  // ==================================================

  async loadAdReward(): Promise<boolean> {
    await this.platform.ready();
    const admob = this.resolveAdMob();
    if (!admob || this.rewardResolver) {
      return false;
    }

    this.hasUserGotReward = false;

    const result = new Promise<boolean>((resolve) => {
      this.rewardResolver = resolve;
    });

    if (this.rewardedAd === true) {
      this.rewardedAd = false;
      this.showRewardedNow();
      return result;
    }

    if (this.rewardedAd === 'loading') {
      this.rewardPendingShow = true;
      return result;
    }

    this.rewardedAd = 'loading';
    this.rewardPendingShow = true;

    try {
      admob.createRewarded({
        adUnitId: environment.androidRewardAdId,
        isAutoShow: false,
        retryInterval: 5000,
      });
    } catch (error) {
      console.error('Error creating rewarded ad:', error);
      this.rewardedAd = false;
      this.rewardPendingShow = false;
      this.resolveReward(false);
    }

    return result;
  }

  private showRewardedNow(): void {
    const admob = this.resolveAdMob();
    try {
      this.isShowingFullscreenAd = true;
      admob.showRewarded();
    } catch (error) {
      console.error('Error showing rewarded ad:', error);
      this.isShowingFullscreenAd = false;
      this.lastFullscreenDismissedTime = Date.now();
      this.resolveReward(false);
    }
  }

  private resolveReward(value: boolean): void {
    if (!this.rewardResolver) {
      return;
    }
    const resolve = this.rewardResolver;
    this.rewardResolver = null;
    resolve(value);
  }

  // ==================================================
  // APP OPEN
  // ==================================================

  private setupAppOpenLifecycle(): void {
    document.addEventListener(
      'pause',
      () => {
        this.zone.run(() => {
          if (this.isAdSuppressed || this.isShowingFullscreenAd) {
            return;
          }

          if (this.isSdkInitialized) {
            this.loadAppOpenAd();
          } else {
            // Queue load if SDK is still initializing
            this.pendingLoadOnPause = true;
          }
        });
      },
      false,
    );

    document.addEventListener(
      'resume',
      () => {
        this.zone.run(() => {
          const admob = this.resolveAdMob();
          if (!admob || this.isAdSuppressed || this.isShowingFullscreenAd) {
            return;
          }

          if (Date.now() - this.lastFullscreenDismissedTime < this.FULLSCREEN_RESUME_DELAY) {
            return;
          }

          if (Date.now() - this.lastAppOpenShownTime < this.APP_OPEN_COOLDOWN) {
            return;
          }

          if (this.appOpenAd !== true) {
            return;
          }

          this.showAppOpen();
        });
      },
      false,
    );
  }

  private loadAppOpenAd(): void {
    const admob = this.resolveAdMob();

    if (!admob || !this.isSdkInitialized || this.appOpenAd) {
      return;
    }

    this.appOpenAd = 'loading';

    try {
      admob.loadAppOpenAd({
        adUnitId: environment.androidAppOpenId,
        isAutoShow: false,
        retryInterval: 5000,
      });
    } catch (error) {
      this.appOpenAd = false;
      console.error('Error loading App Open ad:', error);
    }
  }

  private showAppOpen(): void {
    const admob = this.resolveAdMob();
    if (!admob) return;

    this.appOpenAd = false;
    this.isShowingFullscreenAd = true;

    try {
      admob.showAppOpenAd();
    } catch (error) {
      console.error('Error showing App Open ad:', error);
      this.isShowingFullscreenAd = false;
      this.lastFullscreenDismissedTime = Date.now();
    }
  }

  // ==================================================
  // AD EVENTS
  // ==================================================

  private setupAdEvents(): void {

    // ---- rewarded ----

    document.addEventListener('on.rewarded.loaded', () => {
      this.zone.run(() => {
        this.rewardedAd = true;

        if (this.rewardPendingShow) {
          this.rewardPendingShow = false;
          this.rewardedAd = false;
          this.showRewardedNow();
        }
      });
    });

    document.addEventListener('on.rewarded.earned', () => {
      this.zone.run(() => {
        this.hasUserGotReward = true;
        this.rewardEarned$.next();
        this.resolveReward(true);
      });
    });

    document.addEventListener('on.rewarded.shown', () => {
      this.zone.run(() => {
        this.isShowingFullscreenAd = true;
      });
    });

    const rewardedClosed = () => {
      this.zone.run(() => {
        this.rewardedAd = false;
        this.rewardPendingShow = false;
        this.isShowingFullscreenAd = false;
        this.lastFullscreenDismissedTime = Date.now();
        this.resolveReward(false);
      });
    };

    document.addEventListener('on.rewarded.dismissed', rewardedClosed);
    document.addEventListener('on.rewarded.canceled', rewardedClosed);

    document.addEventListener('on.rewarded.failed.show', (event: any) => {
      console.error('Rewarded failed to show:', event);
      rewardedClosed();
    });

    document.addEventListener('on.rewarded.failed.load', (event: any) => {
      console.error('Rewarded failed to load:', event);
      this.zone.run(() => {
        this.rewardedAd = false;
        this.rewardPendingShow = false;
        this.resolveReward(false);
      });
    });

    // ---- interstitial ----

    document.addEventListener('on.interstitial.loaded', () => {
      this.zone.run(() => {
        console.log('inter-ad-loaded')
      });
    });

    document.addEventListener('on.interstitial.failed.load', (event: any) => {
      console.error('Interstitial failed to load:', event);
      this.zone.run(() => {
      });
    });

    const interstitialClosed = () => {
      this.zone.run(() => {
        this.isShowingFullscreenAd = false;
        this.lastFullscreenDismissedTime = Date.now();
      });
    };

    document.addEventListener('on.interstitial.dismissed', interstitialClosed);

    document.addEventListener('on.interstitial.failed.show', (event: any) => {
      console.error('Interstitial failed to show:', event);
      interstitialClosed();
    });

    // ---- app open ----

    document.addEventListener('on.appopen.loaded', () => {
      this.zone.run(() => {
        this.appOpenAd = true;
      });
    });

    document.addEventListener('on.appopen.failed.load', (event: any) => {
      console.error('App Open failed to load:', event);
      this.zone.run(() => {
        this.appOpenAd = false;
      });
    });

    document.addEventListener('on.appopen.shown', () => {
      this.zone.run(() => {
        this.appOpenAd = false;
        this.isShowingFullscreenAd = true;
        this.lastAppOpenShownTime = Date.now();
      });
    });

    const appOpenClosed = () => {
      this.zone.run(() => {
        this.appOpenAd = false;
        this.isShowingFullscreenAd = false;
        this.lastFullscreenDismissedTime = Date.now();
        this.appOpenDismissed$.next();
      });
    };

    document.addEventListener('on.appopen.dismissed', appOpenClosed);

    document.addEventListener('on.appopen.failed.show', (event: any) => {
      console.error('App Open failed to show:', event);
      appOpenClosed();
    });
  }
}

Describe the solution you'd like

loading and showing an ad, should be fast

Describe alternatives you've considered

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions