diff --git a/aiAssets/GUIDE.md b/aiAssets/GUIDE.md index 6cb5742..ba22dc4 100644 --- a/aiAssets/GUIDE.md +++ b/aiAssets/GUIDE.md @@ -73,18 +73,19 @@ const offY = (viewH - 1920 * s) / 2 ## CTA — SDK Priority (triggerCTA fallback chain) ``` 1. ExitApi.exit() → GoogleAds (gg) -2. FbPlayableAd.onCTAClick() → Facebook (fb) +2. FbPlayableAd.onCTAClick() → Facebook (fb) · Moloco (mo) 3. Luna.Unity.Playable → Unity (un) 4. playableSDK.openAppStore() → (runtime fallback if SDK present) 5. window.install() → Mintegral (mtg) 6. window.openAppStore() → (runtime fallback) -7. window.clickTag → Moloco (mo) +7. window.clickTag → Moloco (mo) fallback 8. window.__VUNGLE__ → Vungle (vu) via parent.postMessage 9. window.__TIKTOK__ → TikTok (tt) → openAppStore() or window.open fallback -10. mraid.open(url) → Applovin (al) / Ironsource (is) +10. mraid.open(url) → Applovin (al) / Ironsource (is) / Unity (un fallback after Luna) 11. window.open(storeUrl) → Fallback (all others) ``` `notifyGameClose()` fires before every CTA redirect (all networks, no-op when SDK absent). +MRAID CTA calls must be guarded: require `typeof mraid.open === 'function'`; treat missing `mraid.getState()` as `ready`; if state is still `loading`, fall through to `window.open(storeUrl)`. ## Analytics — SDK Priority ``` @@ -107,15 +108,63 @@ gameClose() → notifyGameClose() in cta.ts redirectToStore(), before triggerCT ### Pause / Resume / Mute (bindLifecycle in networks.ts) | Network | Mechanism | |---|---| -| Unity | `luna:mute` / `luna:unmute` / `luna:pause` / `luna:resume` events | +| Unity | `luna:mute` / `luna:unmute` / `luna:pause` / `luna:resume` events; also shared MRAID exposure/viewability when `mraid.js` is present | | Mintegral | `window.message` → `onPause` / `onResume` | | Vungle | `ad-event-pause` / `ad-event-resume` events | -| Applovin / Ironsource | MRAID viewable state (gated in initMraid) | +| Applovin / Ironsource / Unity | MRAID 3.0 `exposureChange`, MRAID 2.0 fallback `viewableChange` / `isViewable`, and `audioVolumeChange` (gated in `initMraid`) | | GoogleAds / Facebook / Moloco | No SDK pause — browser handles visibility | +### MRAID 3.0 Requirements & Best Practices +MRAID networks are **Applovin (`al`)**, **Ironsource (`is`)**, and **Unity (`un`)**. All three must request `` early in the generated HTML. Unity still uses Luna first for CTA/lifecycle where available, but MRAID must exist as the standards fallback. + +Creative requirements from the MRAID 3.0 spec and Best Practices Guide: +- Request `mraid.js` as early as possible, exactly once, either with `` or DOM insertion. Do not rely on the container to inject it automatically. +- Wait for both DOM readiness and MRAID readiness before starting rich media behavior. Use `document.readyState` / `DOMContentLoaded` or `load` for the DOM side. +- Use `mraid.getState()` together with `mraid.addEventListener('ready', ...)` so the creative still starts when the container fires `ready` before the listener attaches. +- Guard access to `mraid` and MRAID methods with `typeof` checks. Treat missing optional methods as unsupported and fall back gracefully. +- Use `mraid.open(url)` for MRAID clickthroughs. Avoid ``, `location.href` / `assign` / `replace`, and unguarded `window.open`. +- Include `` or an equivalent mobile viewport tag. +- Do not assume nested iframes can access native MRAID. If nested iframe access is required, the outer frame must provide its own bridge. +- Use `exposureChange` as the MRAID 3.0 viewability signal, then degrade to `viewableChange` / `isViewable()` for MRAID 2.0 compatibility. +- Listen for `audioVolumeChange`; `null` is valid and must be ignored. Only apply volume math when the value is numeric. +- Listen for `error`; if the ad cannot run or assets fail, gracefully degrade or call `mraid.unload()` instead of showing a broken/blank ad. +- Call `setResizeProperties()` before `resize()`. Do not use `resize()` for full-screen takeovers; use `expand()` for that case. +- Avoid resizing or expanding interstitials. Check placement with `getPlacementType()` when one creative can serve inline and interstitial placements. +- Avoid `useCustomClose()` and custom close indicators in MRAID 3.0. The host provides the close control. +- Avoid two-part expandable ads (`expand(url)`); use self-contained one-part expandables. +- Call `supports()` before optional/native features such as `storePicture`, `createCalendarEvent`, `getLocation`, VPAID, SMS/tel, or inline video behavior. +- Use `playVideo()` for native video playback cases instead of `mraid.open(videoUrl)`. Use HTML5 `