Advertising - VirtueSky/sunflower_2 GitHub Wiki

Advertising

Overview

The ads module currently supports 3 mediations:

  • AdMediation.AppLovin
  • AdMediation.Admob
  • AdMediation.LevelPlay

The runtime API lives in VirtueSky.Ads.Advertising.

Opening Settings

Open AdSetting: Open tab Advertising in Magic Panel

Unity_fulAWJZo5S

Configuration

AdSettings supports 2 mediation load modes:

  • MediationLoadMode.Single: initializes only the mediation selected in CurrentMediation
  • MediationLoadMode.Multiple: initializes all mediations that are enabled via UseAppLovin, UseAdmob, UseLevelPlay

Main fields in AdSettings:

  • RuntimeInitType: controls when Advertising is auto-created (BeforeSceneLoad / AfterSceneLoad) and when init runs (Awake / OnEnable / Start)
  • AdCheckingInterval: polling interval for auto-load
  • AdLoadingInterval: minimum time between two auto-load attempts for the same ad type
  • EnableTrackAdRevenue: enables AppTracking.Init(...)
  • EnableGDPR: enables GDPR flow for Admob only (requires VIRTUESKY_ADMOB define)
  • EnableGDPRTestMode: tests GDPR using UMP debug geography

Mediation-specific fields:

AppLovin:

  • SdkKey: AppLovin MAX SDK key

Admob:

  • AutoTrackingAdImpressionAdmob: if enabled and Admob is connected to Firebase, ad_impression is tracked automatically; if disabled, tracking is done manually
  • AdmobEnableTestMode: enables Admob test mode
  • AdmobDevicesTest: list of device IDs for test mode

LevelPlay:

  • AndroidAppKey / IosAppKey: app key per platform
  • UseTestAppKey: use LevelPlay test app key
  • EnableTestSuite: enables the LevelPlay test suite (persisted via GameData, can be changed at runtime)

Init Flow

AdStatic uses RuntimeInitializeOnLoadMethod to auto-create a Advertising GameObject based on RuntimeInitType. If auto-init is not used, create Advertising manually in the scene and call:

Advertising.Initialization();

Always check before calling AdUnit methods:

if (Advertising.IsInitAdClient)
{
    // ad client is ready
}

After the ad client is initialized, the system starts an auto-load coroutine (IeAutoLoadAll) for:

  • Interstitial
  • Rewarded
  • RewardedInterstitial
  • AppOpen

Banner and Native Overlay are triggered to load from each client once the SDK finishes initializing.

AdClient.SdkInitializationCompleted is a property to check the SDK init status of each individual client.

GDPR

The GDPR flow in the current code:

  • Only runs when EnableGDPR = true and the VIRTUESKY_ADMOB define is present
  • If EnableGDPR = true but VIRTUESKY_ADMOB is not defined, InitAdClient() will never be called — avoid this configuration
  • Android: runs UMP first, then calls InitAdClient()
  • iOS:
    • if ATT status is AUTHORIZED, runs UMP first
    • if ATT is not authorized, skips UMP and inits ads directly
  • Unity Editor: skips UMP and inits ads directly

Public API (only compiled when VIRTUESKY_ADMOB is defined):

Advertising.LoadAndShowGdpr();   // load and show consent form
Advertising.ShowAgainGdpr();     // show privacy options form (already loaded)

Support Matrix

Mediation Banner Interstitial Rewarded Rewarded Interstitial App Open Native Overlay
AppLovin Yes Yes Yes No Yes No
Admob Yes Yes Yes Yes Yes Yes
LevelPlay Yes Yes Yes No No No

Notes:

  • Advertising.RewardedInterstitialAd(...) returns null for AppLovin and LevelPlay
  • Advertising.AppOpenAd(...) returns null for LevelPlay
  • Advertising.NativeOverlayAd(...) is only meaningful for Admob

Public API

Current mediation

Advertising.CurrentAdClient();

Advertising.BannerAd();
Advertising.InterstitialAd();
Advertising.RewardAd();
Advertising.RewardedInterstitialAd();
Advertising.AppOpenAd();
Advertising.NativeOverlayAd();

Advertising.ShowAdMediationDebugger();

Specific mediation

Advertising.BannerAd(AdMediation.AppLovin);
Advertising.InterstitialAd(AdMediation.Admob);
Advertising.RewardAd(AdMediation.LevelPlay);
Advertising.RewardedInterstitialAd(AdMediation.Admob);
Advertising.AppOpenAd(AdMediation.AppLovin);
Advertising.NativeOverlayAd(AdMediation.Admob);

Advertising.ShowAdMediationDebugger(AdMediation.Admob);

AdUnit Properties & Methods

Each AdUnit exposes:

  • IsShowing: whether the ad is currently displayed
  • IsLoading: whether the ad is currently loading
  • Id: ad unit ID for the current platform (Android/iOS), or the runtime ID if one has been set

Methods:

  • Load(): manually trigger an ad load
  • IsReady(): check if the ad is ready to show
  • Show(string placement = ""): show the ad; resets chain callbacks before showing
  • HideBanner(): hide the banner (banner units only)
  • SetIdRuntime(string unitId): override the ad unit ID at runtime without modifying AdSettings
  • Destroy(): destroy the ad unit

Callback Chain

AdUnit supports callback chaining via extension methods in AdStatic. These callbacks are reset on every Show() call, so they must be chained after each Show() invocation.

.OnLoaded(Action<AdsInfo> callback)
.OnDisplayed(Action<AdsInfo> callback)
.OnClosed(Action<AdsInfo> callback)
.OnClicked(Action<AdsInfo> callback)
.OnFailedToLoad(Action<AdsError> callback)
.OnFailedToDisplay(Action<AdsError> callback)
.OnCompleted(Action callback)
.OnSkipped(Action callback)
.OnReceivedReward(Action callback)

OnCompleted, OnSkipped, and OnReceivedReward are only meaningful for specific ad types:

  • OnCompleted: interstitial / rewarded / rewarded interstitial
  • OnSkipped: rewarded / rewarded interstitial
  • OnReceivedReward: rewarded / rewarded interstitial

On non-mobile platforms, OnCompleted invokes the callback immediately (without going through Show()).

Persistent Events on AdUnit

In addition to the chain callbacks (reset on each Show()), each AdUnit has persistent events that are never reset:

adUnit.OnLoadAdEvent            += (AdsInfo info) => { };
adUnit.OnFailedToLoadAdEvent    += (AdsError err)  => { };
adUnit.OnDisplayedAdEvent       += (AdsInfo info) => { };
adUnit.OnFailedToDisplayAdEvent += (AdsError err)  => { };
adUnit.OnClosedAdEvent          += (AdsInfo info) => { };
adUnit.OnClickedAdEvent         += (AdsInfo info) => { };
adUnit.paidedCallback           += (double revenue, string adUnitId, string adFormat, string adNetwork, string adMediation) => { };

Use these events when you need to subscribe once and keep the subscription alive for the lifetime of the object (e.g., revenue tracking).

Usage Examples — Current Mediation

using VirtueSky.Ads;

public class AdsSample
{
    public void ShowBanner()
    {
        Advertising.BannerAd()?.Show("main_banner");
    }

    public void HideBanner()
    {
        Advertising.BannerAd()?.HideBanner();
    }

    public void ShowInterstitial()
    {
        Advertising.InterstitialAd()?
            .Show("level_complete")
            .OnCompleted(() =>
            {
                // interstitial closed
            })
            .OnFailedToDisplay(error =>
            {
                // handle show error
            });
    }

    public void ShowReward()
    {
        Advertising.RewardAd()?
            .Show("revive")
            .OnReceivedReward(() =>
            {
                // grant reward
            })
            .OnCompleted(() =>
            {
                // reward ad closed
            })
            .OnSkipped(() =>
            {
                // user skipped reward
            });
    }

    public void ShowRewardedInterstitial()
    {
        Advertising.RewardedInterstitialAd(AdMediation.Admob)?
            .Show("bonus")
            .OnReceivedReward(() =>
            {
                // grant reward
            });
    }

    public void ShowAppOpen()
    {
        Advertising.AppOpenAd()?.Show("resume");
    }
}

Usage Example — Admob Native Overlay

NativeOverlayAd() returns AdUnit. Cast to AdmobNativeOverlayAdUnit to access render-specific methods:

using VirtueSky.Ads;

public class NativeOverlaySample
{
    public void ShowNative()
    {
        var native = Advertising.NativeOverlayAd(AdMediation.Admob) as AdmobNativeOverlayAdUnit;
        if (native == null) return;

        native.Show("native_home");
        native.RenderAd();
    }

    public void HideNative()
    {
        var native = Advertising.NativeOverlayAd(AdMediation.Admob) as AdmobNativeOverlayAdUnit;
        native?.Hide();
    }
}

AdmobNativeOverlayAdUnit.RenderAd() overloads:

  • RenderAd()
  • RenderAd(RectTransform uiElement)
  • RenderAd(RectTransform uiElement, int width, int height)
  • RenderAd(RectTransform uiElement, Camera camera, bool useSizeUiElement = true)
  • RenderAd(RectTransform uiElement, Camera camera, int width, int height)

Important Notes

  • Show() is a no-op if:
    • not running on a mobile platform
    • ad unit ID is empty
    • AdStatic.IsRemoveAd == true
    • IsReady() returns false
  • Show() always resets chain callbacks at the start of the call; chain your callbacks after every Show()
  • AdStatic.IsRemoveAd is persisted via GameData with key {Application.identifier}_removeads
  • AdStatic.IsShowingAd is set automatically via OnChangePreventDisplayAppOpenEvent; when set to false, AdStatic.AdClosingTime is recorded
  • AdStatic.waitAppOpenDisplayedAction and waitAppOpenClosedAction are internal hooks used to hide/restore the banner when an App Open ad is displayed/closed — not public API
  • CurrentAdClient() resolves using AdSettings.CurrentMediation — best used with MediationLoadMode.Single
  • With MediationLoadMode.Multiple, always pass the explicit mediation to avoid resolving to the wrong client

Recommended Usage

If the game runs a single mediation at runtime:

  • Set MediationLoadMode = Single
  • Select CurrentMediation
  • Use the no-argument API: Advertising.InterstitialAd()

If you need to build or debug multiple mediations simultaneously:

  • Set MediationLoadMode = Multiple
  • Enable each required mediation
  • Always pass the mediation explicitly: Advertising.InterstitialAd(AdMediation.Admob)
⚠️ **GitHub.com Fallback** ⚠️