Criar APK grátis

API da ponte JavaScript

Anúncios

Exibir um anúncio intersticial ou com recompensa no momento que você escolher e avisar ao shell quando uma navegação começa e termina para que ele não interrompa uma.

AppMintAds.appOpen helper#

window.AppMintAds.appOpen.setEnabled(on)

Exemplo

Pausa ou retoma o anúncio de abertura do app, o anúncio em tela cheia exibido ao iniciar e quando o usuário volta de outro app.

Retorna: nada. Requer: Controle de anúncios → Controlado pelo desenvolvedor e um ID de unidade de anúncio de abertura do app.

Pause-o enquanto o usuário sai do app de propósito por um instante (um app de pagamento, a câmera, uma folha de compartilhamento), para que ao voltar não apareça um anúncio:

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);
  }
}

Verifique se o build tem uma unidade de abertura do app:

var hasAppOpen = !!(window.AppMintAds && window.AppMintAds.config().formats.app_open);

Pause-o enquanto o usuário escolhe uma foto, já que o seletor de fotos do sistema o tira do app por um instante:

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);
});

Observações: Vem ativado por padrão. Na inicialização a frio o anúncio aparece quando a página está pronta, ou quando termina de carregar em até 15 segundos; um carregamento posterior é guardado para a próxima vez. Um anúncio de abertura do app com mais de 4 horas nunca é exibido. Você também pode exibir um você mesmo com AppMintAds.show('app_open').

AppMintAds.banner helper#

window.AppMintAds.banner.attach(target, opts) / .detach(slotOrElement)

Exemplo

Coloca um banner ou um anúncio de retângulo médio de 300×250 em qualquer lugar da sua página, sobre um elemento que você escolher.

Retorna: attach retorna uma Promise de {ok:true, slot, width, height} (px CSS) quando o anúncio carregou, ou {ok:false, slot?, code, message?}. detach não retorna nada. Requer: Controle de anúncios → Controlado pelo desenvolvedor e um ID de unidade de anúncio de banner (ou retângulo médio).

O elemento apenas reserva o espaço. O anúncio é desenhado sobre ele e o acompanha quando a página rola ou é redimensionada:

<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>

Retângulo médio (um por vez) e a remoção de um banner novamente:

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;
}

Tente um espaço de novo mais tarde quando nenhum anúncio estava disponível, liberando antes o espaço que falhou para que ele não consuma um dos dois:

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);

Observações: target é um elemento ou um seletor CSS; size é 'banner' (padrão, largura adaptativa, no máximo 90 dp de altura), 'medium_rectangle' ou 'mrec'. No máximo dois espaços ao mesmo tempo, e um espaço cujo anúncio falhou ao carregar ainda conta até você desanexá-lo. detach precisa do elemento ou do ID do espaço retornado por attach, não de um seletor. Remover o elemento do DOM também o desanexa. Códigos: 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()

Exemplo

Informa à página qual modo de controle de anúncios o build usa e quais formatos de anúncio ele pode servir.

Retorna: um objeto, de forma síncrona: {control: 'automatic' | 'developer', formats: {banner, mrec, interstitial, rewarded, rewarded_interstitial, app_open}} (cada formato true / false). Em caso de erro interno retorna {control:'automatic', formats:{}}. Requer: nada; window.AppMintAds existe apenas dentro do app instalado.

Mostre apenas a interface de anúncios que este build realmente pode servir:

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);

Escolha o formato com recompensa que o build tem para um botão de "bônus" e oculte o botão quando não houver nenhum dos dois:

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);
});

Escolha o tamanho do anúncio para o final de um artigo: um retângulo médio quando o build tiver um, caso contrário um 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; }
});

Observações: Um formato é true quando os anúncios estão ativados e o build tem um ID de unidade de anúncio para ele. No modo Automático (control: 'automatic') toda chamada de load / show / banner.attach responde code: 'automatic_mode'; use WebToApk.showRewardedAd() / showInterstitialAd() lá. Escolha Controle de anúncios → Controlado pelo desenvolvedor no assistente de build para conduzir os anúncios a partir da página.

AppMintAds.isReady helper#

window.AppMintAds.isReady(type)

Exemplo

Informa se um anúncio em tela cheia deste tipo está carregado e pode ser exibido agora.

Retorna: true / false, de forma síncrona. type: 'interstitial', 'rewarded', 'rewarded_interstitial' ou 'app_open'. Requer: Controle de anúncios → Controlado pelo desenvolvedor e um ID de unidade de anúncio para o tipo.

Mantenha um botão "Assistir anúncio" sincronizado com o anúncio, usando o evento de status 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
}

Ofereça "dobrar suas moedas" na tela de resultados apenas quando um anúncio com recompensa já estiver esperando:

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
  };
}

Em um botão de dica, reproduza qualquer formato com recompensa que esteja carregado agora:

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();
});

Observações: banner e mrec sempre respondem false (eles são anexados, não exibidos). Um intersticial dentro do intervalo de 60 segundos responde false; um anúncio de abertura do app com mais de 4 horas responde false. No modo Automático isto é sempre false.

AppMintAds.load helper#

window.AppMintAds.load(type)

Exemplo

Carrega um anúncio em tela cheia para que um show(type) posterior possa exibi-lo imediatamente.

Retorna: uma Promise que resolve (nunca rejeita) com {ok:true}, {ok:true, cached:true} quando um já está esperando, ou {ok:false, code, reason, message?, adCode?}. Requer: Controle de anúncios → Controlado pelo desenvolvedor e um ID de unidade de anúncio para o 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();

A vida inteira de cada requisição também é transmitida no 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); };

Carregue o intersticial quando uma fase começar, para que esteja lá quando ela terminar, e pare de pedir quando o usuário tiver removido os anúncios:

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();
}

Observações: Códigos: no_fill, network, invalid_unit, internal (do AdMob), automatic_mode, unknown_type, ad_free, disabled, consent e use_slot para banner / mrec (use AppMintAds.banner.attach). O app já pré-carrega cada tipo de tela cheia que tenha um ID de unidade e carrega o próximo após cada exibição, então load serve principalmente para saber quando o botão pode ser habilitado.

AppMintAds.show helper#

window.AppMintAds.show(type)

Exemplo

Exibe um anúncio em tela cheia carregado: interstitial, rewarded, rewarded_interstitial ou app_open.

Retorna: uma Promise que resolve (nunca rejeita) quando o anúncio fechou: {ok:true, shown:true, earned, reward?} (reward = {type, amount} para os formatos com recompensa), ou {ok:false, shown:false, code, reason, message?} quando nada foi exibido. Requer: Controle de anúncios → Controlado pelo desenvolvedor e um ID de unidade de anúncio para o tipo.

Com recompensa: chame dentro do toque do próprio usuário. Esse toque é a adesão do usuário, então o anúncio toca de imediato. Conceda apenas quando earned for verdadeiro:

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.');
});

Intersticial: em uma pausa natural. Continue seja qual for a resposta:

async function levelFinished() {
  if (window.AppMintAds && window.AppMintAds.isReady('interstitial')) {
    await window.AppMintAds.show('interstitial');    // resolves when the ad closes
  }
  showNextLevel();
}

Intersticial com recompensa atrás da sua própria tela de introdução com um "Não, obrigado" claro. O toque em "Assistir" é a adesão:

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();
});

Observações: Um show() com recompensa ou intersticial com recompensa que NÃO vem de um toque do usuário (um timer, carregamento de página, mudança de rota) primeiro mostra uma tela "Assistir a um anúncio? / Não, obrigado", e "Não, obrigado" responde declined. Nunca dispare formatos com recompensa dessa forma. Outros códigos: automatic_mode, unknown_type, ad_free, disabled, consent, not_full_screen, showing, cooldown (60 s entre intersticiais), not_loaded (um novo carregamento começa para a próxima vez), show_failed, internal. No modo Automático use WebToApk.showRewardedAd().

adsAppOpenEnable ponte#

window.WebToApk.adsAppOpenEnable(enabled: Boolean)

Permite que a página pause/retome o anúncio de abertura do app ao voltar de outro app (ativado por padrão quando há uma unidade definida).

Exemplo

A metade nativa de AppMintAds.appOpen.setEnabled(on): ela pausa ou retoma o anúncio de abertura do app. As páginas usam AppMintAds.appOpen.setEnabled.

Retorna: nada. Requer: Controle de anúncios → Controlado pelo desenvolvedor e um ID de unidade de anúncio de abertura do 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); }

Escolher uma foto sai do app para o seletor do sistema, e a volta contaria como um retorno. Pause o anúncio de abertura do app durante esse processo:

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);

Membros do seu próprio plano pago nunca o veem. A opção não é salva, então defina-a cedo a cada inicialização:

// 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);
}

Observações: Assinatura bruta adsAppOpenEnable(enabled). Ativado por padrão quando uma unidade de abertura do app está definida. O anúncio de abertura do app aparece na inicialização a frio (se carregar em até 15 segundos) e quando o usuário volta de outro app; um anúncio com mais de 4 horas nunca é exibido.

adsConfig ponte#

window.WebToApk.adsConfig(): String

`{control, formats:{banner, mrec, interstitial, rewarded, rewarded_interstitial, app_open}}` - os formatos de anúncio que este build pode servir.

Exemplo

Lê quais formatos de anúncio este build pode servir e qual modo de controle de anúncios ele usa. As páginas normalmente chamam AppMintAds.config(), que interpreta isso para você.

Retorna: uma string JSON: {"control":"automatic"|"developer","formats":{"banner":bool,"mrec":bool,"interstitial":bool,"rewarded":bool,"rewarded_interstitial":bool,"app_open":bool}}. Um formato é true quando os anúncios estão ativados e o build tem um ID de unidade de anúncio para ele. Requer: nada.

Primeiro, a API pública:

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;
  }
}

A chamada bruta, se você não usa 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); }
}

Reserve espaço apenas para os formatos que este build realmente tem e, caso contrário, devolva a caixa vazia para a página:

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
}

Observações: No modo Automático formats ainda informa quais unidades existem, mas AppMintAds.load/show respondem code: 'automatic_mode'; use WebToApk.showRewardedAd() / showInterstitialAd() lá.

adsIsReady ponte#

window.WebToApk.adsIsReady(type: String): Boolean

Verdadeiro quando um [type] em tela cheia está carregado e pode ser exibido agora.

Exemplo

Informa se um anúncio em tela cheia de um tipo está carregado e pode ser exibido agora (anúncios controlados pelo desenvolvedor). As páginas normalmente chamam AppMintAds.isReady(type).

Retorna: true / false, de forma síncrona. type é 'interstitial', 'rewarded', 'rewarded_interstitial' ou 'app_open'; 'banner' / 'mrec' sempre respondem false. Requer: Controle de anúncios → Controlado pelo desenvolvedor e um ID de unidade de anúncio para esse tipo.

Primeiro, a API pública:

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 readiness

A chamada bruta:

var b = window.WebToApk;
var ready = !!(b && typeof b.adsIsReady === 'function' && b.adsIsReady('interstitial'));

Mostre um intersticial no fim de uma fase apenas quando houver um esperando, e nunca segure o jogador quando não houver:

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
  }
}

Observações: Um intersticial dentro do seu intervalo de 60 segundos responde false. Um anúncio de abertura do app com mais de 4 horas responde false (o Google diz para não o exibir). No modo Automático isto é sempre false; use WebToApk.isRewardedAdReady() lá.

adsLoad ponte#

window.WebToApk.adsLoad(type: String, callbackId: String)

Carrega um [type] em tela cheia; a promise de [callbackId] resolve com o resultado.

Exemplo

A metade nativa de AppMintAds.load(type): ela começa a carregar um anúncio em tela cheia e responde ao callback do shim. As páginas usam AppMintAds.load(type), que retorna uma Promise; não chame isto diretamente.

Retorna: (por meio de AppMintAds.load) uma Promise de {ok:true}, {ok:true, cached:true} quando um já está carregado, ou {ok:false, code, reason, message?, adCode?}. Requer: Controle de anúncios → Controlado pelo desenvolvedor e um ID de unidade de anúncio para o 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
}

Tente de novo um carregamento que falhou por um motivo passageiro e pare nos motivos que uma nova tentativa não resolve:

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;
  });
}

Aqueça dois formatos antes de uma sessão de jogo começar e oculte todos os botões de anúncio quando o usuário não tiver anúncios:

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);
    });
  });
}

Observações: Códigos de falha: no_fill, network, invalid_unit, internal (do AdMob, com adCode), e automatic_mode, unknown_type, ad_free, disabled, consent e use_slot para banner / mrec (esses carregam com AppMintAds.banner.attach). O app já pré-carrega todo tipo de tela cheia que tenha um ID de unidade e recarrega após cada exibição. A assinatura bruta é adsLoad(type, callbackId); a resposta vai para um resolvedor interno, então uma chamada direta não lhe dá resultado.

adsShow ponte#

window.WebToApk.adsShow(type: String, callbackId: String, userGesture: Boolean)

Exibe um [type] em tela cheia carregado; resolve quando ele fecha, com earned/reward para formatos com recompensa. [userGesture] é a leitura de `navigator.userActivation` do shim - um formato com recompensa pedido sem ela recebe antes a tela de introdução do AdMob (veja DeveloperAds.offerRewarded).

Exemplo

A metade nativa de AppMintAds.show(type): ela exibe um anúncio em tela cheia carregado e responde quando ele fecha. As páginas usam AppMintAds.show(type); não chame isto diretamente.

Retorna: (por meio de AppMintAds.show) uma Promise de {ok:true, shown:true, earned, reward?} depois que o anúncio fecha (reward = {type, amount} para formatos com recompensa), ou {ok:false, shown:false, code, reason, message?}. Requer: Controle de anúncios → Controlado pelo desenvolvedor e um ID de unidade de anúncio para o tipo.

Chame-o a partir do toque do usuário. O shim passa navigator.userActivation.isActive como terceiro argumento (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.');
  });
});

Ofereça um intersticial com recompensa a partir do toque do próprio usuário em "Dobrar meu bônus" e siga em frente seja qual for a resposta:

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
  });
});

Pause a música do seu jogo enquanto qualquer anúncio em tela cheia estiver na tela, usando o fluxo 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
}

Observações: Assinatura bruta adsShow(type, callbackId, userGesture). Quando userGesture é false para rewarded ou rewarded_interstitial, o app primeiro pergunta "Assistir a um anúncio? / Não, obrigado" e um "não" responde declined. Outros códigos: automatic_mode, unknown_type, ad_free, disabled, consent, not_full_screen, showing, cooldown (intersticial, 60 s), not_loaded (um carregamento começa para a próxima vez), show_failed, internal.

adsSlotAttach ponte#

window.WebToApk.adsSlotAttach(slotId: String, type: String, widthCss: Int, callbackId: String)

Cria uma sobreposição de banner/mrec para o espaço [slotId] da página, dimensionada em [widthCss]; resolve com o tamanho do anúncio depois de carregado.

Exemplo

A metade nativa de AppMintAds.banner.attach(element, {size}): ela cria um anúncio de banner ou retângulo médio sobre um elemento da página. As páginas usam AppMintAds.banner.attach; não chame isto diretamente.

Retorna: (por meio de AppMintAds.banner.attach) uma Promise de {ok:true, slot, width, height} em pixels CSS quando o anúncio carregou, ou {ok:false, slot, code, message?}. Requer: Controle de anúncios → Controlado pelo desenvolvedor e um ID de unidade de anúncio de banner (ou retângulo médio).

<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>

Um retângulo médio em uma tela de resultados que devolve o espaço quando nenhum anúncio chega:

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;
}

Conte impressões e cliques por espaço a partir do fluxo appmint:ad, usando como chave o ID do espaço que attach retornou:

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);
  }
});

Observações: Assinatura bruta adsSlotAttach(slotId, type, widthCss, callbackId); type é 'banner' ou 'mrec'. Um WebView não pode conter uma view nativa dentro da página, então o anúncio é desenhado sobre o seu elemento e o acompanha na rolagem e no redimensionamento (veja adsSlotRect). No máximo dois espaços ao mesmo tempo, e apenas um retângulo médio. Códigos extras: duplicate_slot, too_many_slots, detached, internal, mais os códigos de carregamento (no_fill, network, invalid_unit, ad_free, disabled, consent, automatic_mode).

adsSlotDetach ponte#

window.WebToApk.adsSlotDetach(slotId: String)

Remove uma sobreposição de banner.

Exemplo

A metade nativa de AppMintAds.banner.detach(slotOrElement): ela remove uma sobreposição de banner e libera seu espaço. As páginas usam AppMintAds.banner.detach.

Retorna: nada. Requer: Controle de anúncios → Controlado pelo desenvolvedor.

Remova o banner antes de uma tela onde um anúncio não cabe (um player de vídeo, um 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' });
}

Em um app de página única, libere o banner quando a rota que o contém desaparecer. attach marca o elemento imediatamente, então desanexar pelo elemento funciona mesmo enquanto o anúncio ainda está carregando:

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' });
  }
}

Depois de uma compra de "Remover anúncios" as sobreposições somem; desanexe também os espaços e elimine o espaço que eles reservavam:

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();
  });
});

Observações: Assinatura bruta adsSlotDetach(slotId). detach recebe o elemento ou a string slot que attach retornou, não um seletor CSS. Uma Promise de attach ainda esperando seu anúncio responde {ok:false, code:'detached'}. Remover o elemento do DOM também desanexa o espaço.

adsSlotRect ponte#

window.WebToApk.adsSlotRect(slotId: String, x: Float, y: Float, w: Float, h: Float, visible: Boolean)

Interno: o retângulo atual do elemento do espaço na viewport (px CSS) - move a sobreposição.

Exemplo

Interno: move uma sobreposição de banner para a posição atual do seu elemento. O helper AppMintAds.banner chama isso por você na rolagem, no redimensionamento, na mudança de visibilidade e a cada 500 ms; as páginas usam AppMintAds.banner.attach e nunca chamam isto.

Retorna: nada. Requer: Controle de anúncios → Controlado pelo desenvolvedor e um espaço criado por AppMintAds.banner.attach.

Tudo o que uma página faz é dar ao elemento do espaço um lugar no layout. O helper o mede e mantém o anúncio sobre ele:

<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>

Um banner dentro de uma lista com rolagem, não da página: o helper escuta o scroll na fase de captura, então o anúncio acompanha também o contêiner 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>

O anúncio é desenhado acima da página, então seu próprio diálogo ficaria por baixo dele. Oculte o espaço do anúncio enquanto o diálogo estiver aberto:

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
});

Observações: Assinatura bruta adsSlotRect(slotId, x, y, w, h, visible), em pixels CSS relativos à viewport. A sobreposição fica oculta enquanto o elemento está fora da tela, tem tamanho zero, tem visibility: hidden, ou a página está em segundo plano. Se o elemento sair do DOM, o helper desanexa o espaço sozinho.

isInterstitialAdReady ponte#

window.WebToApk.isInterstitialAdReady(): Boolean

Verdadeiro quando um intersticial está carregado E já passou do intervalo (corresponde exatamente ao que showInterstitialAd() vai aceitar - sem um "pronto" que depois se recusa a exibir).

Exemplo

Informa se um anúncio intersticial está carregado E já passou do intervalo de 60 segundos, de modo que showInterstitialAd() o exibiria agora (controle automático de anúncios).

Retorna: true / false, de forma síncrona. Requer: Anúncios ativados e Anúncio em tela cheia → Anúncio intersticial.

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();
});

Mostre um anúncio após cada terceiro quiz concluído, e apenas quando um realmente seria exibido:

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
}

Mostre um breve aviso "Anúncio em 3…" apenas quando um anúncio estiver pronto e depois continue quando ele fechar ou não puder ser exibido:

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);

Observações: true aqui significa que a exibição não será recusada por not_loaded nem cooldown. O consentimento ou uma compra de "Remover anúncios" ainda podem impedi-la (appmint:ad-unavailable). Em builds Controlados pelo desenvolvedor use AppMintAds.isReady('interstitial').

isRewardedAdReady ponte#

window.WebToApk.isRewardedAdReady(): Boolean

Verdadeiro quando um anúncio com recompensa está carregado e pode ser exibido agora. Deixe a página habilitar/desabilitar seu botão "Assistir anúncio" com base nisto (consulte ou chame antes de exibir).

Exemplo

Informa se um anúncio com recompensa está carregado e pode ser exibido agora (controle automático de anúncios).

Retorna: true / false, de forma síncrona. Requer: Anúncios ativados e Anúncio em tela cheia → Anúncio com recompensa.

Habilite o botão "Assistir a um anúncio" apenas quando houver um anúncio esperando:

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);

No fim de jogo, ofereça "Continuar" apenas quando um anúncio estiver esperando, para que o botão nunca leve a lugar nenhum:

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(); });

Verifique no momento do toque e diga ao usuário o que está acontecendo, em vez de disparar uma exibição que será recusada:

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(); });

Observações: Retorna false em um navegador, quando os anúncios foram removidos por compra e antes de o primeiro anúncio carregar. Depois que um anúncio é exibido, o próximo carrega sozinho. Em builds Controlados pelo desenvolvedor use AppMintAds.isReady('rewarded').

notifyUserAction ponte#

window.WebToApk.notifyUserAction()

Interno (chamado pelo contador de toques injetado, não pelo código do criador): ocorreu uma interação significativa do usuário na página. Conta para a cadência "intersticial a cada N ações" APENAS enquanto nenhuma navegação baseada em URL tiver sido observada - apps de HTML único que trocam de tela via mostrar/ocultar DOM nunca mudam a URL, então sem isto o contador de navegação deles ficava em 0 para sempre e os anúncios configurados nunca apareciam (classe de reclamação TicTrek, 26/07/2026). Apps de URL/SPA não são afetados: a primeira navegação real deles volta a contagem permanentemente para os sinais de URL.

Exemplo

Conta uma ação significativa do usuário para a configuração "anúncio em tela cheia a cada N ações". O app chama isso sozinho a partir do próprio contador de toques; as páginas normalmente nunca o chamam.

Retorna: nada. Requer: Anúncios ativados, um Anúncio em tela cheia com Modo de disparo → Após navegações e controle automático de anúncios.

Como funciona: uma página que troca de tela ocultando e mostrando elementos do DOM nunca muda de URL, então o app não consegue ver uma "navegação". Por isso o app injeta um contador de toques (no máximo uma contagem a cada 2 segundos) que chama este método. Assim que o app vê uma mudança real de URL (um carregamento de página, pushState ou um #hash), ele passa a contar mudanças de URL e este método para de contar.

Somente se as mudanças de tela não vierem de um toque (por exemplo um movimento de teclado ou controle), reporte-as você mesmo:

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');
});

Um app em estilo de cartões em que o usuário desliza para a próxima tela (deslizar não é um toque em um botão, então o contador de toques nunca percebe):

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();
});

Um jogo HTML5 jogado com um gamepad, contando uma ação por fase que o jogador inicia com o botão 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 });

Observações: Não faz nada quando os anúncios estão desativados, removidos por compra, ou quando o build usa Controle de anúncios → Controlado pelo desenvolvedor (nesse caso você mesmo chama AppMintAds.show()). Um anúncio com recompensa acionado assim é sempre oferecido com a pergunta "Assistir a um anúncio? / Não, obrigado", nunca forçado. Não o chame a cada toque; isso mostraria anúncios com mais frequência do que você configurou.

showInterstitialAd ponte#

window.WebToApk.showInterstitialAd()

Exibe um intersticial AGORA (por exemplo entre fases / em uma ação deliberada). Não pode ser exibido agora → ignorado + 'appmint:ad-unavailable' com o motivo.

Exemplo

Exibe um anúncio intersticial em tela cheia agora, por exemplo entre duas fases de um jogo (controle automático de anúncios).

Retorna: nada. Quando o anúncio fecha, appmint:ad-closed é disparado com {adType:'interstitial', earned:false}. Quando ele não pode ser exibido, appmint:ad-unavailable é disparado com {adType:'interstitial', reason}. Requer: Anúncios ativados e Anúncio em tela cheia → Anúncio intersticial. Escolha Modo de disparo → Sob demanda se apenas a sua página deve decidir 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(); }
});

Pause o jogo e o som antes do anúncio e retome em qualquer uma das respostas:

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);

Abra um artigo depois de um anúncio, como uma única Promise que resolve true quando o anúncio foi exibido e false quando foi pulado:

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); });

Observações: O app mantém pelo menos 60 segundos entre dois intersticiais; uma chamada dentro desse intervalo responde cooldown. isInterstitialAdReady() já inclui o intervalo, então verificá-lo antes evita o evento. Exiba intersticiais em pausas naturais, nunca a cada toque. Em builds Controlados pelo desenvolvedor use AppMintAds.show('interstitial').

showRewardedAd ponte#

window.WebToApk.showRewardedAd()

Exibe um anúncio com recompensa AGORA (iniciado pelo usuário - a única forma em conformidade com a política de exibir anúncios com recompensa). Combine com o modo de disparo "Sob demanda" no assistente para ter anúncios com recompensa SEM nenhum anúncio automático de abertura do app/navegação. A recompensa é entregue de volta à página via deliverRewardToPage(): window.addEventListener('appmint:reward', e => { /* e.detail = {type,amount} */ }) Quando o anúncio fecha, 'appmint:ad-closed' é disparado com {adType:'rewarded', earned} - earned é false se o usuário saiu antes, então não conceda nada nesse caso. Não pode ser exibido agora → ignorado + 'appmint:ad-unavailable' disparado com o motivo.

Exemplo

Exibe um anúncio com recompensa agora, a partir do toque do próprio usuário em "Assistir a um anúncio" (controle automático de anúncios).

Retorna: nada. O resultado chega depois como eventos: appmint:reward {type, amount} quando o anúncio foi assistido até o fim, appmint:ad-closed {adType:'rewarded', earned} quando ele fecha, ou appmint:ad-unavailable {adType:'rewarded', reason} quando nada pôde ser exibido. Requer: Anúncios ativados, Anúncio em tela cheia → Anúncio com recompensa e Modo de disparo → Sob demanda para que nada apareça sozinho.

Conceda a recompensa apenas no handler de recompensa, nunca no toque:

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();
});

Os mesmos três momentos também chamam hooks da página, se você preferir uma função para cada um (cada uma recebe o mesmo objeto que 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); };

Envolva a chamada e seus eventos em uma única Promise, para que cada botão "Assistir a um anúncio" se leia como uma chamada assíncrona normal:

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.');
  });
});

Observações: Chame apenas a partir de um handler de clique. Nunca o chame a partir de um timer, carregamento de página ou mudança de rota, e nunca coloque um recurso principal atrás dele. not_loaded também inicia um novo carregamento, então o próximo toque costuma funcionar. Em builds Controle de anúncios → Controlado pelo desenvolvedor use AppMintAds.show('rewarded') no lugar, que responde com uma Promise.

Gerado a partir do runtime do app e de seus arquivos de exemplo a cada build da documentação. Leia em Markdown · Todas as famílias.

Conferido com a ponte atual em 22/10/2026.