API del bridge JavaScript
Annunci
Mostrare un annuncio interstitial o con premio al momento che scegli tu, e dire alla shell quando una navigazione inizia e si conclude, così non ne interrompe una.
AppMintAds.appOpen helper#
window.AppMintAds.appOpen.setEnabled(on)
Esempio
Mette in pausa o riprende l'annuncio di apertura app, l'annuncio a schermo intero mostrato all'avvio e quando l'utente torna da un'altra app.
Restituisce: niente. Richiede: Controllo annunci → Controllato dallo sviluppatore e un ID unità annuncio di apertura app.
Mettilo in pausa mentre l'utente lascia l'app di proposito per un attimo (un'app di pagamento, la fotocamera, il menu di condivisione), così al ritorno non compare un annuncio:
var ads = window.AppMintAds;
async function payWithUpi(link) {
if (ads) ads.appOpen.setEnabled(false);
try {
await openPaymentApp(link); // your own code; the user switches apps and returns
} finally {
if (ads) ads.appOpen.setEnabled(true);
}
}Controlla se la build ha un'unità di apertura app:
var hasAppOpen = !!(window.AppMintAds && window.AppMintAds.config().formats.app_open);Mettilo in pausa mentre l'utente sceglie una foto, perché il selettore foto di sistema lo porta fuori dall'app per un momento:
var ads = window.AppMintAds;
var input = document.getElementById('photo-input'); // <input type="file" accept="image/*" hidden>
var pausedForPicker = false;
document.getElementById('pick-photo').addEventListener('click', function () {
if (ads) { ads.appOpen.setEnabled(false); pausedForPicker = true; }
input.click();
});
input.addEventListener('change', function () {
if (input.files[0]) uploadPhoto(input.files[0]); // your own code
});
// Back in the app (a photo was picked or the picker was cancelled): turn it on again.
document.addEventListener('visibilitychange', function () {
if (document.hidden || !pausedForPicker) return;
pausedForPicker = false;
setTimeout(function () { ads.appOpen.setEnabled(true); }, 1000);
});Note: è attivo per impostazione predefinita. All'avvio a freddo l'annuncio compare quando la pagina è pronta, o quando finisce di caricarsi entro 15 secondi; un caricamento successivo viene tenuto per la volta dopo. Un annuncio di apertura app più vecchio di 4 ore non viene mai mostrato. Puoi anche mostrarne uno tu con AppMintAds.show('app_open').
AppMintAds.banner helper#
window.AppMintAds.banner.attach(target, opts) / .detach(slotOrElement)
Esempio
Posiziona un banner o un annuncio rettangolo medio 300×250 ovunque nella tua pagina, sopra un elemento che scegli.
Restituisce: attach restituisce una Promise di {ok:true, slot, width, height} (px CSS) una volta caricato l'annuncio, oppure {ok:false, slot?, code, message?}. detach non restituisce nulla. Richiede: Controllo annunci → Controllato dallo sviluppatore e un ID unità per un annuncio banner (o rettangolo medio).
L'elemento riserva soltanto lo spazio. L'annuncio viene disegnato sopra di esso e lo segue quando la pagina scorre o cambia dimensione:
<div id="ad-slot"></div>
<script>
var ads = window.AppMintAds;
var slotEl = document.getElementById('ad-slot');
if (ads) {
ads.banner.attach(slotEl, { size: 'banner' }).then(function (res) {
// On success the helper sets slotEl.style.minHeight to res.height (pass keepHeight:true to stop that).
if (!res.ok) { // no_fill, network, too_many_slots, ...
if (res.slot) ads.banner.detach(res.slot); // a failed slot still counts toward the limit of two
slotEl.hidden = true;
}
});
} else {
slotEl.hidden = true; // browser: no ads here
}
</script>Rettangolo medio (uno alla volta) e rimozione di un banner:
var box = document.querySelector('.article-end-ad');
var mrecSlot = null;
if (window.AppMintAds) {
window.AppMintAds.banner.attach(box, { size: 'medium_rectangle' }).then(function (res) {
if (res.ok) mrecSlot = res.slot;
else { if (res.slot) window.AppMintAds.banner.detach(res.slot); box.hidden = true; }
});
}
function leaveArticle() {
if (window.AppMintAds && mrecSlot) window.AppMintAds.banner.detach(mrecSlot); // or detach(box)
mrecSlot = null;
}Riprova uno spazio più tardi quando non c'era nessun annuncio disponibile, liberando prima lo spazio fallito così non consuma uno dei due:
function fillSlot(el, triesLeft) {
var ads = window.AppMintAds;
if (!ads) { el.hidden = true; return; } // browser: no ads here
ads.banner.attach(el, { size: 'banner' }).then(function (res) {
if (res.ok) return;
if (res.slot) ads.banner.detach(res.slot);
if ((res.code === 'no_fill' || res.code === 'network') && triesLeft > 0) {
setTimeout(function () { fillSlot(el, triesLeft - 1); }, 60000);
} else {
el.hidden = true; // ad_free, disabled, consent, ...
}
});
}
fillSlot(document.getElementById('footer-ad'), 2);Note: target è un elemento o un selettore CSS; size è 'banner' (predefinito, larghezza adattiva, al massimo 90 dp di altezza), 'medium_rectangle' o 'mrec'. Al massimo due spazi alla volta, e uno spazio il cui annuncio non si è caricato conta comunque finché non lo stacchi. detach richiede l'elemento o l'ID dello spazio restituito da attach, non un selettore. Anche rimuovere l'elemento dal DOM lo stacca. Codici: no_element, duplicate_slot, too_many_slots, detached, no_fill, network, invalid_unit, ad_free, disabled, consent, automatic_mode, internal.
AppMintAds.config helper#
window.AppMintAds.config()
Esempio
Dice alla pagina quale modalità di controllo degli annunci usa la build e quali formati può servire.
Restituisce: un oggetto, in modo sincrono: {control: 'automatic' | 'developer', formats: {banner, mrec, interstitial, rewarded, rewarded_interstitial, app_open}} (ogni formato true / false). In caso di errore interno restituisce {control:'automatic', formats:{}}. Richiede: niente; window.AppMintAds esiste solo dentro l'app installata.
Mostra solo l'interfaccia degli annunci che questa build può davvero servire:
var ads = window.AppMintAds; // undefined in a browser
var cfg = ads ? ads.config() : null;
var developer = !!(cfg && cfg.control === 'developer');
document.getElementById('watch-ad').hidden = !(developer && cfg.formats.rewarded);
document.getElementById('ad-slot').hidden = !(developer && cfg.formats.banner);Scegli il formato con premio che la build ha per un pulsante «bonus» e nascondi il pulsante quando non ne ha nessuno dei due:
var ads = window.AppMintAds;
var cfg = ads ? ads.config() : null;
var bonusBtn = document.getElementById('bonus');
var bonusType = null;
if (cfg && cfg.control === 'developer') {
if (cfg.formats.rewarded) bonusType = 'rewarded';
else if (cfg.formats.rewarded_interstitial) bonusType = 'rewarded_interstitial';
}
bonusBtn.hidden = !bonusType;
bonusBtn.addEventListener('click', async function () {
var res = await ads.show(bonusType); // inside the tap: plays at once
if (res.earned) addCoins(res.reward.amount);
});Scegli la dimensione dell'annuncio per la fine di un articolo: un rettangolo medio se la build ce l'ha, altrimenti un banner:
var ads = window.AppMintAds;
var cfg = ads ? ads.config() : null;
var box = document.getElementById('article-end-ad');
var size = null;
if (cfg && cfg.control === 'developer') {
size = cfg.formats.mrec ? 'medium_rectangle' : (cfg.formats.banner ? 'banner' : null);
}
if (!size) box.hidden = true;
else ads.banner.attach(box, { size: size }).then(function (res) {
if (!res.ok) { if (res.slot) ads.banner.detach(res.slot); box.hidden = true; }
});Note: un formato è true quando gli annunci sono attivi e la build ha un ID unità annuncio per esso. In modalità automatica (control: 'automatic') ogni chiamata a load / show / banner.attach risponde code: 'automatic_mode'; lì usa WebToApk.showRewardedAd() / showInterstitialAd(). Scegli Controllo annunci → Controllato dallo sviluppatore nella procedura guidata della build per gestire gli annunci dalla pagina.
AppMintAds.isReady helper#
window.AppMintAds.isReady(type)
Esempio
Dice se un annuncio a schermo intero di questo tipo è caricato e può essere mostrato subito.
Restituisce: true / false, in modo sincrono. type: 'interstitial', 'rewarded', 'rewarded_interstitial' o 'app_open'. Richiede: Controllo annunci → Controllato dallo sviluppatore e un ID unità annuncio per il tipo.
Tieni un pulsante «Guarda annuncio» in linea con l'annuncio, usando l'evento di stato appmint:ad:
var ads = window.AppMintAds;
var btn = document.getElementById('watch-ad');
function refresh() { btn.disabled = !(ads && ads.isReady('rewarded')); }
if (ads) {
refresh();
window.addEventListener('appmint:ad', function (e) {
if (e.detail.type === 'rewarded') refresh(); // phases: loaded, failed, closed, ...
});
} else {
btn.hidden = true; // browser: no ads here
}Proponi «raddoppia le monete» nella schermata dei risultati solo quando un annuncio con premio è già in attesa:
function showResults(coins) {
var ads = window.AppMintAds;
var offer = document.getElementById('double-coins');
renderResults(coins); // your own screen
offer.hidden = !(ads && ads.isReady('rewarded'));
offer.onclick = async function () {
offer.hidden = true;
var res = await ads.show('rewarded'); // inside the tap: plays at once
addCoins(res.earned ? coins : 0); // the bonus: the same amount again
};
}In un pulsante di suggerimento, riproduci il formato con premio che è caricato in questo momento:
document.getElementById('hint').addEventListener('click', async function () {
var ads = window.AppMintAds;
if (!ads) return; // browser: no ads here
var type = ads.isReady('rewarded') ? 'rewarded'
: ads.isReady('rewarded_interstitial') ? 'rewarded_interstitial'
: null;
if (!type) { showMessage('No hint video right now. Try again in a minute.'); return; }
var res = await ads.show(type);
if (res.earned) revealHint();
});Note: banner e mrec rispondono sempre false (sono agganciati, non mostrati). Un interstitial entro i 60 secondi di attesa risponde false; un annuncio di apertura app più vecchio di 4 ore risponde false. In modalità automatica è sempre false.
AppMintAds.load helper#
window.AppMintAds.load(type)
Esempio
Carica un annuncio a schermo intero così che un successivo show(type) possa riprodurlo subito.
Restituisce: una Promise che si risolve (non viene mai rifiutata) con {ok:true}, {ok:true, cached:true} quando uno è già in attesa, oppure {ok:false, code, reason, message?, adCode?}. Richiede: Controllo annunci → Controllato dallo sviluppatore e un ID unità annuncio per il tipo (interstitial, rewarded, rewarded_interstitial, app_open).
var ads = window.AppMintAds;
var btn = document.getElementById('watch-ad');
btn.disabled = true;
async function prepareRewarded() {
if (!ads) { btn.hidden = true; return; } // browser: no ads
var res = await ads.load('rewarded');
if (res.ok) { btn.disabled = false; return; }
if (res.code === 'no_fill' || res.code === 'network') setTimeout(prepareRewarded, 30000);
else console.log('rewarded ad unavailable:', res.code, res.message);
}
prepareRewarded();L'intera vita di ogni richiesta viene anche trasmessa sull'evento appmint:ad:
window.addEventListener('appmint:ad', function (e) {
var a = e.detail; // {type, phase, slot?, code?, adCode?, message?, width?, height?, reward?, earned?}
// phase: loading, loaded, failed, opened, impression, clicked, closed, rewarded, show_failed, opt_in, declined
if (a.phase === 'failed') console.log(a.type, 'failed to load:', a.code, a.adCode, a.message);
});
// The same object also goes to window.onAppMintAd, if you define that function.
window.onAppMintAd = function (a) { console.log('ad', a.type, a.phase); };Carica l'interstitial quando inizia un livello, così è pronto quando il livello finisce, e smetti di chiederlo quando l'utente ha rimosso gli annunci:
var ads = window.AppMintAds;
var interstitialsOff = false;
async function startLevel(n) {
runLevel(n); // your own game
if (!ads || interstitialsOff) return;
var res = await ads.load('interstitial');
if (!res.ok && (res.code === 'ad_free' || res.code === 'disabled' || res.code === 'automatic_mode')) {
interstitialsOff = true; // no interstitials in this app session
}
}
async function levelEnded() {
if (ads && !interstitialsOff && ads.isReady('interstitial')) await ads.show('interstitial');
showLevelSummary();
}Note: codici: no_fill, network, invalid_unit, internal (da AdMob), automatic_mode, unknown_type, ad_free, disabled, consent, e use_slot per banner / mrec (usa AppMintAds.banner.attach). L'app precarica già ogni tipo a schermo intero che ha un ID unità e carica il successivo dopo ogni visualizzazione, quindi load serve soprattutto per sapere quando il pulsante può essere attivato.
AppMintAds.show helper#
window.AppMintAds.show(type)
Esempio
Mostra un annuncio a schermo intero caricato: interstitial, rewarded, rewarded_interstitial oppure app_open.
Restituisce: una Promise che si risolve (non viene mai rifiutata) quando l'annuncio si è chiuso: {ok:true, shown:true, earned, reward?} (reward = {type, amount} per i formati con premio), oppure {ok:false, shown:false, code, reason, message?} quando non è stato mostrato nulla. Richiede: Controllo annunci → Controllato dallo sviluppatore e un ID unità annuncio per il tipo.
Con premio: chiamalo dentro il tocco dell'utente. Quel tocco è l'adesione dell'utente, quindi l'annuncio parte subito. Assegna il premio solo quando earned è vero:
var ads = window.AppMintAds;
document.getElementById('watch-ad').addEventListener('click', async function () {
if (!ads) return; // browser: no ads here
var res = await ads.show('rewarded');
if (res.earned) addCoins(res.reward.amount);
else if (res.reason === 'ad_free') addCoins(50); // user paid to remove ads: reward anyway
else if (res.shown) showMessage('Watch to the end to get the reward.');
else if (res.reason !== 'declined') showMessage('No ad available right now.');
});Interstitial: in una pausa naturale. Continua qualunque sia la risposta:
async function levelFinished() {
if (window.AppMintAds && window.AppMintAds.isReady('interstitial')) {
await window.AppMintAds.show('interstitial'); // resolves when the ad closes
}
showNextLevel();
}Interstitial con premio dietro una tua schermata introduttiva con un chiaro «No, grazie». Il tocco su «Guarda» è l'adesione:
var ads = window.AppMintAds;
var intro = document.getElementById('free-life-intro'); // your own dialog: Watch / No thanks
function offerFreeLife() {
if (ads && ads.isReady('rewarded_interstitial')) intro.hidden = false;
else gameOver();
}
document.getElementById('free-life-watch').addEventListener('click', async function () {
intro.hidden = true;
var res = await ads.show('rewarded_interstitial');
if (res.earned) continueWithExtraLife();
else gameOver();
});
document.getElementById('free-life-skip').addEventListener('click', function () {
intro.hidden = true;
gameOver();
});Note: un show() con premio o interstitial con premio che NON nasce da un tocco dell'utente (un timer, il caricamento della pagina, un cambio di percorso) mostra prima una schermata «Guardare un annuncio? / No, grazie», e «No, grazie» risponde declined. Non attivare mai i formati con premio in quel modo. Altri codici: automatic_mode, unknown_type, ad_free, disabled, consent, not_full_screen, showing, cooldown (60 s tra un interstitial e l'altro), not_loaded (parte un nuovo caricamento per la prossima volta), show_failed, internal. In modalità automatica usa WebToApk.showRewardedAd().
adsAppOpenEnable bridge#
window.WebToApk.adsAppOpenEnable(enabled: Boolean)
Permette alla pagina di mettere in pausa/riprendere l'annuncio di apertura app al ritorno da un'altra app (attivo per impostazione predefinita quando è impostata un'unità).
Esempio
La metà nativa di AppMintAds.appOpen.setEnabled(on): mette in pausa o riprende l'annuncio di apertura app. Le pagine usano AppMintAds.appOpen.setEnabled.
Restituisce: niente. Richiede: Controllo annunci → Controllato dallo sviluppatore e un ID unità annuncio di apertura app.
function setAppOpenAds(on) {
if (window.AppMintAds) window.AppMintAds.appOpen.setEnabled(on);
}
// Pause while the user is in the middle of something, resume afterwards.
function startCheckout() { setAppOpenAds(false); showCheckout(); }
function checkoutDone() { setAppOpenAds(true); }Scegliere una foto porta fuori dall'app verso il selettore di sistema, e il ritorno verrebbe contato come un rientro. Metti in pausa l'annuncio di apertura app per tutto il tempo:
var input = document.getElementById('photo');
function appOpenAds(on) {
if (window.AppMintAds) window.AppMintAds.appOpen.setEnabled(on);
}
input.addEventListener('click', function () { appOpenAds(false); });
function pickerDone() { setTimeout(function () { appOpenAds(true); }, 1000); }
input.addEventListener('change', pickerDone);
input.addEventListener('cancel', pickerDone);I membri del tuo piano a pagamento non lo vedono mai. L'interruttore non viene salvato, quindi impostalo presto a ogni avvio:
// Runs from a <head> script: window.AppMintAds is already there at document start.
var plan = null;
try { plan = localStorage.getItem('plan'); } catch (e) {}
if (window.AppMintAds && plan === 'pro') {
window.AppMintAds.appOpen.setEnabled(false);
}Note: firma diretta adsAppOpenEnable(enabled). Attivo per impostazione predefinita quando è impostata un'unità di apertura app. L'annuncio di apertura app compare all'avvio a freddo (se si carica entro 15 secondi) e quando l'utente torna da un'altra app; un annuncio più vecchio di 4 ore non viene mai mostrato.
adsConfig bridge#
window.WebToApk.adsConfig(): String
`{control, formats:{banner, mrec, interstitial, rewarded, rewarded_interstitial, app_open}}` - i formati di annuncio che questa build può servire.
Esempio
Legge quali formati di annuncio può servire questa build e quale modalità di controllo degli annunci usa. Le pagine di solito chiamano AppMintAds.config(), che lo interpreta per te.
Restituisce: una stringa JSON: {"control":"automatic"|"developer","formats":{"banner":bool,"mrec":bool,"interstitial":bool,"rewarded":bool,"rewarded_interstitial":bool,"app_open":bool}}. Un formato è true quando gli annunci sono attivi e la build ha un ID unità annuncio per esso. Richiede: niente.
Prima l'API pubblica:
if (window.AppMintAds) {
var cfg = window.AppMintAds.config(); // already parsed; {control:'automatic', formats:{}} on error
if (cfg.control === 'developer' && cfg.formats.rewarded) {
document.getElementById('watch-ad').hidden = false;
}
}La chiamata diretta, se non usi AppMintAds:
var b = window.WebToApk;
if (b && typeof b.adsConfig === 'function') {
try {
var cfg = JSON.parse(b.adsConfig());
console.log(cfg.control, cfg.formats);
} catch (e) { console.log('could not read ad config', e); }
}Riserva spazio solo per i formati che questa build ha davvero e, altrimenti, restituisci alla pagina il riquadro vuoto:
var box = document.getElementById('sidebar-ad');
var cfg = window.AppMintAds ? window.AppMintAds.config() : { control: 'automatic', formats: {} };
if (cfg.control === 'developer' && cfg.formats.mrec) {
window.AppMintAds.banner.attach(box, { size: 'mrec' });
} else if (cfg.control === 'developer' && cfg.formats.banner) {
window.AppMintAds.banner.attach(box, { size: 'banner' });
} else {
box.remove(); // browser, Automatic mode, or no unit: no empty gap
}Note: in modalità automatica formats ti dice ancora quali unità esistono, ma AppMintAds.load/show rispondono code: 'automatic_mode'; lì usa WebToApk.showRewardedAd() / showInterstitialAd().
adsIsReady bridge#
window.WebToApk.adsIsReady(type: String): Boolean
Vero quando un [type] a schermo intero è caricato e può essere mostrato subito.
Esempio
Dice se un annuncio a schermo intero di un tipo è caricato e può essere mostrato ora (annunci controllati dallo sviluppatore). Le pagine di solito chiamano AppMintAds.isReady(type).
Restituisce: true / false, in modo sincrono. type è 'interstitial', 'rewarded', 'rewarded_interstitial' o 'app_open'; 'banner' / 'mrec' rispondono sempre false. Richiede: Controllo annunci → Controllato dallo sviluppatore e un ID unità annuncio per quel tipo.
Prima l'API pubblica:
var watchBtn = document.getElementById('watch-ad');
function refresh() {
watchBtn.disabled = !(window.AppMintAds && window.AppMintAds.isReady('rewarded'));
}
refresh();
window.addEventListener('appmint:ad', refresh); // loaded / closed / failed all change readinessLa chiamata grezza:
var b = window.WebToApk;
var ready = !!(b && typeof b.adsIsReady === 'function' && b.adsIsReady('interstitial'));Mostra un interstitial alla fine di un livello solo quando ce n'è uno in attesa, e non trattenere mai il giocatore quando non c'è:
function onLevelComplete() {
var ads = window.AppMintAds;
if (ads && ads.isReady('interstitial')) {
// resolves after the ad closes, or at once with {ok:false, code} if it could not show
ads.show('interstitial').then(startNextLevel);
} else {
startNextLevel(); // not loaded yet, or inside the 60-second cooldown
}
}Note: un interstitial entro i 60 secondi di attesa risponde false. Un annuncio di apertura app più vecchio di 4 ore risponde false (Google dice di non mostrarlo). In modalità automatica è sempre false; lì usa WebToApk.isRewardedAdReady().
adsLoad bridge#
window.WebToApk.adsLoad(type: String, callbackId: String)
Carica un [type] a schermo intero; la promise per [callbackId] si risolve con l'esito.
Esempio
La metà nativa di AppMintAds.load(type): avvia il caricamento di un annuncio a schermo intero e risponde alla callback dello shim. Le pagine usano AppMintAds.load(type), che restituisce una Promise; non chiamarlo direttamente.
Restituisce: (tramite AppMintAds.load) una Promise di {ok:true}, {ok:true, cached:true} quando uno è già caricato, oppure {ok:false, code, reason, message?, adCode?}. Richiede: Controllo annunci → Controllato dallo sviluppatore e un ID unità annuncio per il tipo.
var watchBtn = document.getElementById('watch-ad');
watchBtn.disabled = true;
if (window.AppMintAds) {
window.AppMintAds.load('rewarded').then(function (res) {
if (res.ok) watchBtn.disabled = false;
else console.log('rewarded ad not loaded:', res.code, res.message);
});
} else {
watchBtn.hidden = true; // browser: there are no ads here
}Riprova un caricamento fallito per un motivo passeggero e fermati per i motivi che un nuovo tentativo non può risolvere:
function loadWithRetry(type, attempt) {
attempt = attempt || 0;
return window.AppMintAds.load(type).then(function (res) {
if (res.ok) return res;
if ((res.code === 'no_fill' || res.code === 'network') && attempt < 3) {
return new Promise(function (wait) { setTimeout(wait, 5000 * (attempt + 1)); })
.then(function () { return loadWithRetry(type, attempt + 1); });
}
return res; // invalid_unit, consent, ad_free, disabled ...
});
}
if (window.AppMintAds) {
loadWithRetry('rewarded').then(function (res) {
document.getElementById('watch-ad').disabled = !res.ok;
});
}Prepara due formati prima dell'inizio di una partita e nascondi ogni pulsante annuncio quando l'utente non ha affatto annunci:
if (window.AppMintAds) {
Promise.all([
window.AppMintAds.load('interstitial'),
window.AppMintAds.load('rewarded_interstitial')
]).then(function (results) {
var noAds = results.some(function (r) { return r.code === 'ad_free' || r.code === 'disabled'; });
if (noAds) hideAllAdButtons(); // paid to remove ads, or ads are off in this build
results.forEach(function (r) {
if (!r.ok && r.adCode !== undefined) console.log('ad load failed', r.code, r.adCode, r.message);
});
});
}Note: codici di errore: no_fill, network, invalid_unit, internal (da AdMob, con adCode), e automatic_mode, unknown_type, ad_free, disabled, consent, e use_slot per banner / mrec (si caricano con AppMintAds.banner.attach). L'app precarica già ogni tipo a schermo intero che ha un ID unità e ricarica dopo ogni visualizzazione. La firma diretta è adsLoad(type, callbackId); la sua risposta va a un resolver interno, quindi una chiamata diretta non ti dà alcun risultato.
adsShow bridge#
window.WebToApk.adsShow(type: String, callbackId: String, userGesture: Boolean)
Mostra un [type] a schermo intero caricato; si risolve alla chiusura, con earned/reward per i formati con premio. [userGesture] è la lettura di `navigator.userActivation` dello shim - un formato con premio richiesto senza di essa mostra prima la schermata introduttiva di AdMob (vedi DeveloperAds.offerRewarded).
Esempio
La metà nativa di AppMintAds.show(type): mostra un annuncio a schermo intero caricato e risponde alla chiusura. Le pagine usano AppMintAds.show(type); non chiamarlo direttamente.
Restituisce: (tramite AppMintAds.show) una Promise di {ok:true, shown:true, earned, reward?} dopo la chiusura dell'annuncio (reward = {type, amount} per i formati con premio), oppure {ok:false, shown:false, code, reason, message?}. Richiede: Controllo annunci → Controllato dallo sviluppatore e un ID unità annuncio per il tipo.
Chiamalo dal tocco dell'utente. Lo shim passa navigator.userActivation.isActive come terzo argomento (userGesture):
document.getElementById('watch-ad').addEventListener('click', function () {
if (!window.AppMintAds) return;
window.AppMintAds.show('rewarded').then(function (res) {
if (res.earned) addCoins(res.reward.amount);
else if (res.reason === 'ad_free') addCoins(50); // paid to remove ads: reward anyway
else if (res.reason !== 'declined') showMessage('No ad available right now.');
});
});Proponi un interstitial con premio dal tocco dell'utente su «Raddoppia il mio bonus» e vai avanti qualunque sia la risposta:
document.getElementById('double-bonus').addEventListener('click', function () {
if (!window.AppMintAds) return goToNextLevel();
window.AppMintAds.show('rewarded_interstitial').then(function (res) {
if (res.earned) doubleLevelBonus();
else if (!res.shown && res.code !== 'declined') console.log('no ad:', res.code);
goToNextLevel(); // shown or not, the player keeps going
});
});Metti in pausa la musica del gioco mentre un annuncio a schermo intero è visibile, usando il flusso appmint:ad:
window.addEventListener('appmint:ad', function (e) {
var d = e.detail; // {type, phase, code?, adCode?, message?, earned?, reward?}
if (d.type === 'banner' || d.type === 'mrec') return;
if (d.phase === 'opened') music.pause();
if (d.phase === 'closed' || d.phase === 'show_failed') music.play();
});
function onChapterSaved() {
if (window.AppMintAds) window.AppMintAds.show('interstitial'); // a natural break
}Note: firma diretta adsShow(type, callbackId, userGesture). Quando userGesture è false per rewarded o rewarded_interstitial, l'app chiede prima «Guardare un annuncio? / No, grazie» e un «no» risponde declined. Altri codici: automatic_mode, unknown_type, ad_free, disabled, consent, not_full_screen, showing, cooldown (interstitial, 60 s), not_loaded (parte un caricamento per la prossima volta), show_failed, internal.
adsSlotAttach bridge#
window.WebToApk.adsSlotAttach(slotId: String, type: String, widthCss: Int, callbackId: String)
Crea un overlay banner/mrec per lo spazio [slotId] della pagina, con larghezza [widthCss]; si risolve con la dimensione dell'annuncio una volta caricato.
Esempio
La metà nativa di AppMintAds.banner.attach(element, {size}): crea un annuncio banner o rettangolo medio sopra un elemento della pagina. Le pagine usano AppMintAds.banner.attach; non chiamarlo direttamente.
Restituisce: (tramite AppMintAds.banner.attach) una Promise di {ok:true, slot, width, height} in pixel CSS una volta caricato l'annuncio, oppure {ok:false, slot, code, message?}. Richiede: Controllo annunci → Controllato dallo sviluppatore e un ID unità per un annuncio banner (o rettangolo medio).
<div id="ad-slot"></div>
<script>
if (window.AppMintAds) {
window.AppMintAds.banner.attach('#ad-slot', { size: 'banner' }).then(function (res) {
if (!res.ok) console.log('no banner:', res.code); // e.g. no_fill, network, too_many_slots
});
}
</script>Un rettangolo medio in una schermata dei risultati che restituisce il suo spazio quando non arriva nessun annuncio:
var box = document.getElementById('result-ad');
if (window.AppMintAds) {
window.AppMintAds.banner.attach(box, { size: 'mrec' }).then(function (res) {
if (res.ok) return; // the box now has min-height = res.height
window.AppMintAds.banner.detach(res.slot); // free the slot for another banner
box.hidden = true;
if (res.code === 'too_many_slots') console.log('detach a banner first:', res.message);
});
} else {
box.hidden = true;
}Conta impressioni e clic per spazio dal flusso appmint:ad, usando come chiave l'ID dello spazio restituito da attach:
var slotNames = {};
if (window.AppMintAds) {
window.AppMintAds.banner.attach('#footer-ad', { size: 'banner' }).then(function (res) {
if (res.ok) slotNames[res.slot] = 'footer';
});
}
window.addEventListener('appmint:ad', function (e) {
var d = e.detail; // banner events carry {type, phase, slot}
if (d.slot && (d.phase === 'impression' || d.phase === 'clicked')) {
track('ad_' + d.phase, slotNames[d.slot] || d.slot);
}
});Note: firma diretta adsSlotAttach(slotId, type, widthCss, callbackId); type è 'banner' o 'mrec'. Una WebView non può contenere una vista nativa dentro la pagina, quindi l'annuncio viene disegnato sopra il tuo elemento e lo segue durante lo scroll e il ridimensionamento (vedi adsSlotRect). Al massimo due spazi alla volta, e un solo rettangolo medio. Codici aggiuntivi: duplicate_slot, too_many_slots, detached, internal, più i codici di caricamento (no_fill, network, invalid_unit, ad_free, disabled, consent, automatic_mode).
adsSlotDetach bridge#
window.WebToApk.adsSlotDetach(slotId: String)
Rimuove un overlay banner.
Esempio
La metà nativa di AppMintAds.banner.detach(slotOrElement): rimuove un overlay banner e libera il suo spazio. Le pagine usano AppMintAds.banner.detach.
Restituisce: niente. Richiede: Controllo annunci → Controllato dallo sviluppatore.
Rimuovi il banner prima di una schermata dove un annuncio non va (un lettore video, un checkout):
var slotEl = document.getElementById('ad-slot');
function openPlayer() {
if (window.AppMintAds) window.AppMintAds.banner.detach(slotEl); // the element, or the slot id from attach()
showPlayer();
}
function closePlayer() {
hidePlayer();
if (window.AppMintAds) window.AppMintAds.banner.attach(slotEl, { size: 'banner' });
}In un'app a pagina singola, libera il banner quando il percorso che lo contiene scompare. attach segna subito l'elemento, quindi staccare per elemento funziona anche mentre l'annuncio si sta ancora caricando:
function onRouteChange(route) {
if (!window.AppMintAds) return renderRoute(route);
var old = document.getElementById('article-ad');
if (old) window.AppMintAds.banner.detach(old);
renderRoute(route);
if (route === '/articles') {
window.AppMintAds.banner.attach('#article-ad', { size: 'banner' });
}
}Dopo un acquisto «Rimuovi annunci» gli overlay sono spariti; stacca anche gli spazi e togli lo spazio che riservavano:
window.addEventListener('appmint:premium', function (e) {
if (!e.detail.premium || !window.AppMintAds) return;
document.querySelectorAll('[data-appmint-ad-slot]').forEach(function (el) {
window.AppMintAds.banner.detach(el);
el.remove();
});
});Note: firma diretta adsSlotDetach(slotId). detach accetta l'elemento o la stringa slot restituita da attach, non un selettore CSS. Una Promise di attach ancora in attesa del suo annuncio risponde {ok:false, code:'detached'}. Anche rimuovere l'elemento dal DOM stacca lo spazio.
adsSlotRect bridge#
window.WebToApk.adsSlotRect(slotId: String, x: Float, y: Float, w: Float, h: Float, visible: Boolean)
Interno: il rettangolo attuale dell'elemento dello spazio nel viewport (px CSS) - sposta l'overlay.
Esempio
Interno: sposta un overlay banner nella posizione attuale del suo elemento. L'helper AppMintAds.banner lo chiama per te durante lo scroll, il ridimensionamento, il cambio di visibilità e ogni 500 ms; le pagine usano AppMintAds.banner.attach e non lo chiamano mai.
Restituisce: niente. Richiede: Controllo annunci → Controllato dallo sviluppatore e uno spazio creato da AppMintAds.banner.attach.
Alla pagina basta dare all'elemento dello spazio un posto nel layout. L'helper lo misura e tiene l'annuncio sopra di esso:
<main>
<article id="story">…</article>
<div id="ad-slot" style="margin: 16px 0"></div> <!-- the ad follows this box while scrolling -->
</main>
<script>
if (window.AppMintAds) window.AppMintAds.banner.attach('#ad-slot', { size: 'banner' });
</script>Un banner dentro un elenco scorrevole, non nella pagina: l'helper ascolta lo scroll nella fase di cattura, così l'annuncio segue anche il contenitore interno:
<div id="feed" style="height: 100vh; overflow-y: auto">
<div class="card">…</div>
<div class="card">…</div>
<div id="feed-ad" style="margin: 12px 0"></div>
<div class="card">…</div>
</div>
<script>
if (window.AppMintAds) window.AppMintAds.banner.attach('#feed-ad', { size: 'banner' });
</script>L'annuncio viene disegnato sopra la pagina, quindi la tua finestra di dialogo resterebbe sotto. Nascondi lo spazio dell'annuncio mentre la finestra è aperta:
var slotEl = document.getElementById('ad-slot');
var dialog = document.getElementById('settings-dialog');
function openSettings() {
slotEl.style.visibility = 'hidden'; // the helper hides the overlay on its next tick
dialog.showModal();
}
dialog.addEventListener('close', function () {
slotEl.style.visibility = ''; // and puts it back over the box
});Note: firma diretta adsSlotRect(slotId, x, y, w, h, visible), in pixel CSS relativi al viewport. L'overlay è nascosto mentre l'elemento è fuori schermo, ha dimensione zero, ha visibility: hidden, o la pagina è in secondo piano. Se l'elemento esce dal DOM, l'helper stacca da solo lo spazio.
isInterstitialAdReady bridge#
window.WebToApk.isInterstitialAdReady(): Boolean
Vero quando un interstitial è caricato E fuori dal suo tempo di attesa (corrisponde esattamente a ciò che showInterstitialAd() accetterà - nessun «pronto» che poi rifiuta di mostrarsi).
Esempio
Dice se un annuncio interstitial è caricato E fuori dal suo tempo di attesa di 60 secondi, così showInterstitialAd() lo mostrerebbe ora (controllo automatico degli annunci).
Restituisce: true / false, in modo sincrono. Richiede: annunci attivi e Annuncio a schermo intero → Annuncio interstitial.
function onLevelDone() {
var b = window.WebToApk;
if (b && typeof b.isInterstitialAdReady === 'function' && b.isInterstitialAdReady()) {
b.showInterstitialAd(); // wait for 'appmint:ad-closed' before continuing
} else {
startNextLevel(); // nothing ready: never block the user
}
}
window.addEventListener('appmint:ad-closed', function (e) {
if (e.detail.adType === 'interstitial') startNextLevel();
});Mostra un annuncio dopo ogni terzo quiz completato, e solo quando verrebbe davvero mostrato:
var finished = 0;
function onQuizFinished() {
finished++;
var b = window.WebToApk;
var ready = !!(b && typeof b.isInterstitialAdReady === 'function' && b.isInterstitialAdReady());
if (finished % 3 === 0 && ready) b.showInterstitialAd();
showResults(); // the results are there when the ad closes
}Mostra un breve avviso «Annuncio tra 3…» solo quando un annuncio è pronto, poi continua quando si chiude o non può essere mostrato:
var afterAd = null;
function adBreakThen(next) {
var b = window.WebToApk;
if (!b || typeof b.isInterstitialAdReady !== 'function' || !b.isInterstitialAdReady()) return next();
var note = document.getElementById('ad-break'), n = 3;
note.hidden = false; note.textContent = 'Ad in 3…';
var t = setInterval(function () {
if (--n > 0) { note.textContent = 'Ad in ' + n + '…'; return; }
clearInterval(t); note.hidden = true;
afterAd = next;
b.showInterstitialAd();
}, 1000);
}
function runAfterAd(e) {
if (e.detail.adType !== 'interstitial' || !afterAd) return;
var next = afterAd; afterAd = null; next();
}
window.addEventListener('appmint:ad-closed', runAfterAd);
window.addEventListener('appmint:ad-unavailable', runAfterAd);Note: true qui significa che la visualizzazione non verrà rifiutata per not_loaded o cooldown. Il consenso o un acquisto «Rimuovi annunci» possono comunque fermarla (appmint:ad-unavailable). Nelle build controllate dallo sviluppatore usa AppMintAds.isReady('interstitial').
isRewardedAdReady bridge#
window.WebToApk.isRewardedAdReady(): Boolean
Vero quando un annuncio con premio è caricato e può essere mostrato subito. Lascia che la pagina attivi/disattivi il suo pulsante «Guarda annuncio» in base a questo (interroga o chiama prima di mostrare).
Esempio
Dice se un annuncio con premio è caricato e può essere mostrato subito (controllo automatico degli annunci).
Restituisce: true / false, in modo sincrono. Richiede: annunci attivi e Annuncio a schermo intero → Annuncio con premio.
Attiva il pulsante «Guarda un annuncio» solo quando un annuncio è in attesa:
var btn = document.getElementById('earn');
function refreshWatchButton() {
var b = window.WebToApk;
var ready = !!(b && typeof b.isRewardedAdReady === 'function' && b.isRewardedAdReady());
btn.disabled = !ready;
btn.textContent = ready ? 'Watch an ad for 10 coins' : 'Loading ad…';
}
refreshWatchButton();
setInterval(refreshWatchButton, 2000); // an ad can finish loading at any time
window.addEventListener('appmint:ad-closed', refreshWatchButton);Al game over, proponi «Continua» solo quando un annuncio è in attesa, così il pulsante non porta mai nel nulla:
var continueBtn = document.getElementById('continue-with-ad');
function onGameOver() {
var b = window.WebToApk;
continueBtn.hidden = !(b && typeof b.isRewardedAdReady === 'function' && b.isRewardedAdReady());
showGameOverPanel(); // "Restart" is always there
}
continueBtn.addEventListener('click', function () { // the user's own tap
continueBtn.hidden = true;
window.WebToApk.showRewardedAd();
});
window.addEventListener('appmint:reward', function () { revivePlayer(); });Controlla nel momento del tocco e di' all'utente cosa sta succedendo, invece di lanciare una visualizzazione che verrà rifiutata:
document.getElementById('hint').addEventListener('click', function () {
var b = window.WebToApk;
if (!b || typeof b.isRewardedAdReady !== 'function') return showMessage('Hints need the app.');
if (typeof b.isPremium === 'function' && b.isPremium()) return revealHint(); // paid to remove ads
if (b.isRewardedAdReady()) b.showRewardedAd();
else showMessage('The ad is still loading. Try again in a few seconds.');
});
window.addEventListener('appmint:reward', function () { revealHint(); });Note: restituisce false in un browser, quando gli annunci sono stati rimossi con un acquisto e prima che sia stato caricato il primo annuncio. Dopo che un annuncio è stato mostrato, il successivo si carica da solo. Nelle build controllate dallo sviluppatore usa AppMintAds.isReady('rewarded').
notifyUserAction bridge#
window.WebToApk.notifyUserAction()
Interno (chiamato dal contatore dei tocchi inserito, non dal codice del creatore): nella pagina è avvenuta un'interazione significativa dell'utente. Conta per la cadenza «interstitial ogni N azioni» SOLO finché non è mai stata osservata una navigazione basata sull'URL - le app HTML singole che cambiano schermata mostrando/nascondendo il DOM non cambiano mai l'URL, quindi senza questo il loro contatore di navigazione restava a 0 per sempre e gli annunci configurati non comparivano mai (classe di reclami TicTrek, 2026-07-26). Le app URL/SPA non sono toccate: la loro prima vera navigazione riporta per sempre il conteggio sui segnali dell'URL.
Esempio
Conta un'azione significativa dell'utente per l'impostazione «annuncio a schermo intero ogni N azioni». L'app la chiama da sola dal proprio contatore dei tocchi; le pagine di solito non la chiamano mai.
Restituisce: niente. Richiede: annunci attivi, un annuncio a schermo intero con Modalità di attivazione → Dopo le navigazioni e il controllo automatico degli annunci.
Come funziona: una pagina che cambia schermata nascondendo e mostrando elementi DOM non cambia mai il suo URL, quindi l'app non può vedere una «navigazione». Per questo l'app inserisce un contatore dei tocchi (al massimo un conteggio ogni 2 secondi) che chiama questo metodo. Appena l'app vede un vero cambio di URL (un caricamento di pagina, pushState o un #hash), conta i cambi di URL e questo metodo smette di contare.
Solo se i cambi di schermata non nascono da un tocco (per esempio un movimento di tastiera o gamepad), segnalali tu:
function goToScreen(name) {
showScreen(name); // your own DOM show/hide
var b = window.WebToApk;
if (b && typeof b.notifyUserAction === 'function') b.notifyUserAction();
}
document.addEventListener('keydown', function (e) {
if (e.key === 'Enter') goToScreen('next');
});Un'app a schede in cui l'utente scorre alla schermata successiva (uno scorrimento non è un tocco su un pulsante, quindi il contatore dei tocchi non lo vede):
var startX = null;
document.addEventListener('touchstart', function (e) { startX = e.touches[0].clientX; }, { passive: true });
document.addEventListener('touchend', function (e) {
if (startX === null) return;
var dx = e.changedTouches[0].clientX - startX;
startX = null;
if (Math.abs(dx) < 80) return; // not a swipe
showScreen(dx < 0 ? 'next' : 'previous'); // your own DOM show/hide
var b = window.WebToApk;
if (b && typeof b.notifyUserAction === 'function') b.notifyUserAction();
});Un gioco HTML5 giocato con un gamepad, che conta un'azione per ogni livello che il giocatore avvia con il pulsante A:
var aWasDown = false;
function pollPad() {
var pad = navigator.getGamepads ? navigator.getGamepads()[0] : null;
var aDown = !!(pad && pad.buttons[0] && pad.buttons[0].pressed);
if (aDown && !aWasDown && isOnLevelSelect()) { // your own game state
startSelectedLevel();
var b = window.WebToApk;
if (b && typeof b.notifyUserAction === 'function') b.notifyUserAction();
}
aWasDown = aDown;
requestAnimationFrame(pollPad);
}
window.addEventListener('gamepadconnected', function () { requestAnimationFrame(pollPad); }, { once: true });Note: non fa nulla quando gli annunci sono disattivati, rimossi con un acquisto, o quando la build usa Controllo annunci → Controllato dallo sviluppatore (in quel caso chiami tu AppMintAds.show()). Un annuncio con premio raggiunto in questo modo viene sempre proposto con la domanda «Guardare un annuncio? / No, grazie», mai imposto. Non chiamarlo a ogni tocco: mostrerebbe annunci più spesso di quanto hai configurato.
showInterstitialAd bridge#
window.WebToApk.showInterstitialAd()
Mostra ORA un interstitial (per esempio tra un livello e l'altro / dopo un'azione deliberata). Non mostrabile in questo momento → saltato + 'appmint:ad-unavailable' con il motivo.
Esempio
Mostra subito un annuncio interstitial a schermo intero, per esempio tra due livelli di un gioco (controllo automatico degli annunci).
Restituisce: niente. Quando l'annuncio si chiude, scatta appmint:ad-closed con {adType:'interstitial', earned:false}. Quando non può essere mostrato, scatta appmint:ad-unavailable con {adType:'interstitial', reason}. Richiede: annunci attivi e Annuncio a schermo intero → Annuncio interstitial. Scegli Modalità di attivazione → Su richiesta se solo la tua pagina deve decidere quando.
var bridge = window.WebToApk;
var waitingForAd = false;
function levelFinished() {
if (bridge && typeof bridge.isInterstitialAdReady === 'function' && bridge.isInterstitialAdReady()) {
waitingForAd = true;
bridge.showInterstitialAd(); // the next level starts when the ad closes
} else {
showNextLevel(); // no ad ready: just continue
}
}
window.addEventListener('appmint:ad-closed', function (e) {
if (e.detail.adType === 'interstitial' && waitingForAd) { waitingForAd = false; showNextLevel(); }
});
window.addEventListener('appmint:ad-unavailable', function (e) {
// reason: ad_free | disabled | consent | not_loaded | cooldown | show_failed
if (e.detail.adType === 'interstitial' && waitingForAd) { waitingForAd = false; showNextLevel(); }
});Metti in pausa il gioco e il suo audio prima dell'annuncio e riprendi con qualsiasi risposta:
var pausedForAd = false;
function adBetweenRounds() {
var b = window.WebToApk;
if (!b || typeof b.showInterstitialAd !== 'function') return;
pausedForAd = true;
pauseGame(); music.pause();
b.showInterstitialAd();
}
function resumeAfterAd(e) {
if (e.detail.adType !== 'interstitial' || !pausedForAd) return;
pausedForAd = false;
music.play(); resumeGame();
}
window.addEventListener('appmint:ad-closed', resumeAfterAd);
window.addEventListener('appmint:ad-unavailable', resumeAfterAd);Apri un articolo dopo un annuncio, come un'unica Promise che si risolve true quando l'annuncio è stato mostrato e false quando è stato saltato:
function interstitialThen() {
return new Promise(function (resolve) {
var b = window.WebToApk;
if (!b || typeof b.isInterstitialAdReady !== 'function' || !b.isInterstitialAdReady()) return resolve(false);
function done(e) {
if (e.detail.adType !== 'interstitial') return;
window.removeEventListener('appmint:ad-closed', done);
window.removeEventListener('appmint:ad-unavailable', done);
resolve(e.type === 'appmint:ad-closed');
}
window.addEventListener('appmint:ad-closed', done);
window.addEventListener('appmint:ad-unavailable', done);
b.showInterstitialAd();
});
}
interstitialThen().then(function () { openArticle(articleId); });Note: l'app mantiene almeno 60 secondi tra due interstitial; una chiamata in quell'intervallo risponde cooldown. isInterstitialAdReady() include già l'attesa, quindi controllarlo prima evita l'evento. Mostra gli interstitial nelle pause naturali, mai a ogni tocco. Nelle build controllate dallo sviluppatore usa AppMintAds.show('interstitial').
showRewardedAd bridge#
window.WebToApk.showRewardedAd()
Mostra ORA un annuncio con premio (avviato dall'utente - l'unico modo conforme alle regole per mostrare un annuncio con premio). Abbinalo alla modalità di attivazione «Su richiesta» nella procedura guidata per avere annunci con premio SENZA alcun annuncio automatico di apertura app/navigazione. Il premio viene consegnato alla pagina tramite deliverRewardToPage(): window.addEventListener('appmint:reward', e => { /* e.detail = {type,amount} */ }) Quando l'annuncio si chiude, scatta 'appmint:ad-closed' con {adType:'rewarded', earned} - earned è false se l'utente è uscito prima, quindi in quel caso non assegnare nulla. Non mostrabile in questo momento → saltato + 'appmint:ad-unavailable' scattato con il motivo.
Esempio
Mostra subito un annuncio con premio, dal tocco dell'utente su «Guarda un annuncio» (controllo automatico degli annunci).
Restituisce: niente. L'esito arriva più tardi come eventi: appmint:reward {type, amount} quando l'annuncio è stato guardato fino alla fine, appmint:ad-closed {adType:'rewarded', earned} quando si chiude, oppure appmint:ad-unavailable {adType:'rewarded', reason} quando non è stato possibile mostrare nulla. Richiede: annunci attivi, Annuncio a schermo intero → Annuncio con premio e Modalità di attivazione → Su richiesta, così non compare nulla da solo.
Assegna il premio solo nel gestore del premio, mai al tocco:
var btn = document.getElementById('earn');
var bridge = window.WebToApk;
function refresh() {
btn.disabled = !(bridge && typeof bridge.isRewardedAdReady === 'function' && bridge.isRewardedAdReady());
}
refresh();
setInterval(refresh, 2000);
btn.addEventListener('click', function () { // a real user tap: the only place to call it
if (!bridge || typeof bridge.showRewardedAd !== 'function') return;
btn.disabled = true;
bridge.showRewardedAd();
});
// GRANT HERE ONLY: the ad was watched to the end.
window.addEventListener('appmint:reward', function (e) {
addCoins(e.detail.amount); // e.detail = {type, amount}
});
// The ad closed. earned === false means the user left early: grant nothing.
window.addEventListener('appmint:ad-closed', function (e) {
if (e.detail.adType === 'rewarded' && !e.detail.earned) showMessage('No reward: the ad was closed early.');
refresh();
});
// Nothing could be shown.
window.addEventListener('appmint:ad-unavailable', function (e) {
// e.detail = {adType, reason}; reason: ad_free | disabled | consent | not_loaded | show_failed
if (e.detail.reason === 'ad_free') addCoins(1); // the user paid to remove ads: reward anyway
else showMessage('No ad right now. Try again in a moment.');
refresh();
});Gli stessi tre momenti chiamano anche degli hook della pagina, se preferisci una funzione per ciascuno (ognuna riceve lo stesso oggetto di e.detail):
window.onAppMintReward = function (reward) { addCoins(reward.amount); }; // {type, amount}
window.onAppMintAdClosed = function (info) { console.log(info.adType, info.earned); };
window.onAppMintAdUnavailable = function (info) { console.log(info.adType, info.reason); };Racchiudi la chiamata e i suoi eventi in un'unica Promise, così ogni pulsante «Guarda un annuncio» si legge come una normale chiamata asincrona:
function watchRewardedAd() { // call it inside the user's tap
return new Promise(function (resolve) {
var b = window.WebToApk;
if (!b || typeof b.showRewardedAd !== 'function') return resolve({ earned: false, reason: 'no_app' });
function done(e) {
if (e.detail.adType !== 'rewarded') return;
window.removeEventListener('appmint:ad-closed', done);
window.removeEventListener('appmint:ad-unavailable', done);
resolve(e.type === 'appmint:ad-closed' ? { earned: e.detail.earned } : { earned: false, reason: e.detail.reason });
}
window.addEventListener('appmint:ad-closed', done);
window.addEventListener('appmint:ad-unavailable', done);
b.showRewardedAd();
});
}
document.getElementById('revive').addEventListener('click', function () {
watchRewardedAd().then(function (r) {
if (r.earned || r.reason === 'ad_free') revivePlayer();
else if (r.reason) showMessage('No ad right now.');
});
});Note: chiamalo solo da un gestore di clic. Non chiamarlo mai da un timer, dal caricamento della pagina o da un cambio di percorso, e non mettere mai una funzione essenziale dietro di esso. not_loaded avvia anche un nuovo caricamento, quindi il tocco successivo di solito funziona. Nelle build con Controllo annunci → Controllato dallo sviluppatore usa invece AppMintAds.show('rewarded'), che risponde con una Promise.