Advertising - VirtueSky/sunflower_2 GitHub Wiki
The ads module currently supports 3 mediations:
AdMediation.AppLovinAdMediation.AdmobAdMediation.LevelPlay
The runtime API lives in VirtueSky.Ads.Advertising.
Open AdSetting: Open tab Advertising in Magic Panel
AdSettings supports 2 mediation load modes:
-
MediationLoadMode.Single: initializes only the mediation selected inCurrentMediation -
MediationLoadMode.Multiple: initializes all mediations that are enabled viaUseAppLovin,UseAdmob,UseLevelPlay
Main fields in AdSettings:
-
RuntimeInitType: controls whenAdvertisingis 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: enablesAppTracking.Init(...) -
EnableGDPR: enables GDPR flow for Admob only (requiresVIRTUESKY_ADMOBdefine) -
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_impressionis 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 viaGameData, can be changed at runtime)
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:
InterstitialRewardedRewardedInterstitialAppOpen
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.
The GDPR flow in the current code:
- Only runs when
EnableGDPR = trueand theVIRTUESKY_ADMOBdefine is present - If
EnableGDPR = truebutVIRTUESKY_ADMOBis 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
- if ATT status is
- 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)| 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(...)returnsnullforAppLovinandLevelPlay -
Advertising.AppOpenAd(...)returnsnullforLevelPlay -
Advertising.NativeOverlayAd(...)is only meaningful forAdmob
Advertising.CurrentAdClient();
Advertising.BannerAd();
Advertising.InterstitialAd();
Advertising.RewardAd();
Advertising.RewardedInterstitialAd();
Advertising.AppOpenAd();
Advertising.NativeOverlayAd();
Advertising.ShowAdMediationDebugger();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);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 modifyingAdSettings -
Destroy(): destroy the ad unit
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()).
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).
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");
}
}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)
-
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 everyShow() -
AdStatic.IsRemoveAdis persisted viaGameDatawith key{Application.identifier}_removeads -
AdStatic.IsShowingAdis set automatically viaOnChangePreventDisplayAppOpenEvent; when set tofalse,AdStatic.AdClosingTimeis recorded -
AdStatic.waitAppOpenDisplayedActionandwaitAppOpenClosedActionare internal hooks used to hide/restore the banner when an App Open ad is displayed/closed — not public API -
CurrentAdClient()resolves usingAdSettings.CurrentMediation— best used withMediationLoadMode.Single - With
MediationLoadMode.Multiple, always pass the explicit mediation to avoid resolving to the wrong client
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)