JavaScript bridge API
Реклама
Показ interstitial или вознаграждаемой рекламы по вашему сигналу и уведомление оболочки о начале и завершении навигации, чтобы она не прерывала показ.
AppMintAds.appOpen помощник#
window.AppMintAds.appOpen.setEnabled(on)
Пример
Приостанавливает или возобновляет рекламу при открытии приложения — полноэкранную рекламу, показываемую при запуске и когда пользователь возвращается из другого приложения.
Возвращает: ничего. Требуется: Управление рекламой → Под контролем разработчика и ID рекламного блока при открытии приложения.
Приостановите её, пока пользователь намеренно ненадолго выходит из приложения (платёжное приложение, камера, меню «Поделиться»), чтобы при возвращении не показывалась реклама:
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);
}
}Проверьте, есть ли в сборке блок рекламы при открытии приложения вообще:
var hasAppOpen = !!(window.AppMintAds && window.AppMintAds.config().formats.app_open);Приостановите её, пока пользователь выбирает фото, поскольку системный выбор фото ненадолго уводит его из приложения:
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);
});Примечания: По умолчанию включено. При холодном запуске реклама показывается, когда страница готова или когда загрузка завершилась в течение 15 секунд; более поздняя загрузка сохраняется на следующий раз. Реклама при открытии приложения старше 4 часов никогда не показывается. Вы также можете показать её сами с помощью AppMintAds.show('app_open').
AppMintAds.banner помощник#
window.AppMintAds.banner.attach(target, opts) / .detach(slotOrElement)
Пример
Размещает баннер или рекламу «средний прямоугольник» 300×250 в любом месте вашей страницы, поверх выбранного вами элемента.
Возвращает: attach возвращает Promise с {ok:true, slot, width, height} (CSS px) после загрузки рекламы или {ok:false, slot?, code, message?}. detach ничего не возвращает. Требуется: Управление рекламой → Под контролем разработчика и ID баннерного (или среднего прямоугольника) блока.
Элемент лишь резервирует место. Реклама рисуется поверх него и следует за ним при прокрутке или изменении размера страницы:
<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>Средний прямоугольник (по одному за раз) и повторное удаление баннера:
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;
}Попробуйте блок снова позже, если реклама была недоступна, предварительно освободив неудавшийся блок, чтобы он не занимал одно из двух мест:
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);Примечания: target — это элемент или CSS-селектор; size равен 'banner' (по умолчанию, адаптивная ширина, не выше 90 dp), 'medium_rectangle' или 'mrec'. Не более двух блоков одновременно, а блок, реклама которого не загрузилась, всё равно считается, пока вы его не отсоедините. detach нужен элемент или ID блока из attach, а не селектор. Удаление элемента из DOM тоже отсоединяет его. Коды: no_element, duplicate_slot, too_many_slots, detached, no_fill, network, invalid_unit, ad_free, disabled, consent, automatic_mode, internal.
AppMintAds.config помощник#
window.AppMintAds.config()
Пример
Сообщает странице, какой режим управления рекламой использует сборка и какие форматы рекламы она может показывать.
Возвращает: объект, синхронно: {control: 'automatic' | 'developer', formats: {banner, mrec, interstitial, rewarded, rewarded_interstitial, app_open}} (каждый формат true / false). При внутренней ошибке возвращает {control:'automatic', formats:{}}. Требуется: ничего; window.AppMintAds существует только внутри установленного приложения.
Показывайте только тот рекламный интерфейс, который эта сборка действительно может обслужить:
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);Выберите вознаграждаемый формат, который есть в сборке, для кнопки «бонус» и скройте кнопку, если нет ни одного:
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);
});Выберите размер рекламы для конца статьи: средний прямоугольник, если он есть в сборке, иначе баннер:
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; }
});Примечания: Формат равен true, когда реклама включена и в сборке есть ID блока для него. В автоматическом режиме (control: 'automatic') каждый вызов load / show / banner.attach возвращает code: 'automatic_mode'; используйте там WebToApk.showRewardedAd() / showInterstitialAd(). Выберите Управление рекламой → Под контролем разработчика в мастере сборки, чтобы управлять рекламой со страницы.
AppMintAds.isReady помощник#
window.AppMintAds.isReady(type)
Пример
Сообщает, загружена ли полноэкранная реклама этого типа и можно ли показать её прямо сейчас.
Возвращает: true / false, синхронно. type: 'interstitial', 'rewarded', 'rewarded_interstitial' или 'app_open'. Требуется: Управление рекламой → Под контролем разработчика и ID блока для этого типа.
Синхронизируйте кнопку «Смотреть рекламу» с рекламой через событие статуса 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
}Предлагайте «удвоить монеты» на экране результатов, только если вознаграждаемая реклама уже ждёт:
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
};
}В кнопке подсказки проигрывайте тот вознаграждаемый формат, который сейчас загружен:
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();
});Примечания: banner и mrec всегда возвращают false (они подключаются, а не показываются). Interstitial в 60-секундной паузе возвращает false; реклама при открытии приложения старше 4 часов возвращает false. В автоматическом режиме это всегда false.
AppMintAds.load помощник#
window.AppMintAds.load(type)
Пример
Загружает полноэкранную рекламу, чтобы последующий show(type) мог показать её сразу.
Возвращает: Promise, который выполняется (никогда не отклоняется) с {ok:true}, {ok:true, cached:true}, если реклама уже ждёт, или {ok:false, code, reason, message?, adCode?}. Требуется: Управление рекламой → Под контролем разработчика и ID блока для этого типа (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();Вся жизнь каждого запроса также передаётся событием 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); };Загружайте interstitial при начале уровня, чтобы он был готов к его концу, и перестаньте запрашивать, когда пользователь убрал рекламу:
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();
}Примечания: Коды: no_fill, network, invalid_unit, internal (от AdMob), automatic_mode, unknown_type, ad_free, disabled, consent и use_slot для banner / mrec (используйте AppMintAds.banner.attach). Приложение уже заранее загружает каждый полноэкранный тип с ID блока и загружает следующий после каждого показа, поэтому load в основном нужен, чтобы знать, когда можно включить кнопку.
AppMintAds.show помощник#
window.AppMintAds.show(type)
Пример
Показывает загруженную полноэкранную рекламу: interstitial, rewarded, rewarded_interstitial или app_open.
Возвращает: Promise, который выполняется (никогда не отклоняется), когда реклама закрылась: {ok:true, shown:true, earned, reward?} (reward = {type, amount} для вознаграждаемых форматов) или {ok:false, shown:false, code, reason, message?}, если ничего не было показано. Требуется: Управление рекламой → Под контролем разработчика и ID блока для этого типа.
Вознаграждаемая: вызывайте внутри нажатия самого пользователя. Это нажатие — согласие пользователя, поэтому реклама играет сразу. Начисляйте награду, только когда earned равно true:
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: в естественной паузе. Продолжайте при любом ответе:
async function levelFinished() {
if (window.AppMintAds && window.AppMintAds.isReady('interstitial')) {
await window.AppMintAds.show('interstitial'); // resolves when the ad closes
}
showNextLevel();
}Вознаграждаемый interstitial за вашим собственным вводным экраном с понятной кнопкой «Нет, спасибо». Нажатие «Смотреть» — это согласие:
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();
});Примечания: Вознаграждаемый или вознаграждаемый interstitial show(), который НЕ вызван нажатием пользователя (таймер, загрузка страницы, смена маршрута), сначала показывает экран «Посмотреть рекламу? / Нет, спасибо», а «Нет, спасибо» даёт declined. Никогда не запускайте вознаграждаемые форматы так. Другие коды: automatic_mode, unknown_type, ad_free, disabled, consent, not_full_screen, showing, cooldown (60 с между interstitial), not_loaded (новая загрузка начинается на следующий раз), show_failed, internal. В автоматическом режиме используйте WebToApk.showRewardedAd().
adsAppOpenEnable мост#
window.WebToApk.adsAppOpenEnable(enabled: Boolean)
Позволяет странице приостанавливать/возобновлять рекламу при открытии приложения при возврате из другого приложения (по умолчанию включено, если задан блок).
Пример
Нативная часть AppMintAds.appOpen.setEnabled(on): она приостанавливает или возобновляет рекламу при открытии приложения. Страницы используют AppMintAds.appOpen.setEnabled.
Возвращает: ничего. Требуется: Управление рекламой → Под контролем разработчика и ID рекламного блока при открытии приложения.
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); }Выбор фото уводит из приложения в системный выбор, и возвращение считалось бы возвратом. Приостановите рекламу при открытии приложения на это время:
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);Участники вашего собственного платного тарифа никогда её не видят. Переключатель не сохраняется, поэтому задавайте его рано при каждом запуске:
// 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);
}Примечания: Исходная сигнатура adsAppOpenEnable(enabled). По умолчанию включено, когда задан блок рекламы при открытии приложения. Эта реклама показывается при холодном запуске (если загрузилась за 15 секунд) и когда пользователь возвращается из другого приложения; реклама старше 4 часов никогда не показывается.
adsConfig мост#
window.WebToApk.adsConfig(): String
`{control, formats:{banner, mrec, interstitial, rewarded, rewarded_interstitial, app_open}}` — форматы рекламы, которые может показывать эта сборка.
Пример
Считывает, какие форматы рекламы может показывать эта сборка и какой режим управления рекламой она использует. Страницы обычно вызывают AppMintAds.config(), который разбирает это за вас.
Возвращает: строку JSON: {"control":"automatic"|"developer","formats":{"banner":bool,"mrec":bool,"interstitial":bool,"rewarded":bool,"rewarded_interstitial":bool,"app_open":bool}}. Формат равен true, когда реклама включена и в сборке есть ID блока для него. Требуется: ничего.
Сначала публичный API:
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;
}
}Прямой вызов, если вы не используете 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); }
}Резервируйте место только для форматов, которые действительно есть в этой сборке, а пустой блок возвращайте странице:
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
}Примечания: В автоматическом режиме formats по-прежнему сообщает, какие блоки есть, но AppMintAds.load/show возвращают code: 'automatic_mode'; используйте там WebToApk.showRewardedAd() / showInterstitialAd().
adsIsReady мост#
window.WebToApk.adsIsReady(type: String): Boolean
True, когда полноэкранная реклама [type] загружена и может быть показана прямо сейчас.
Пример
Сообщает, загружена ли полноэкранная реклама одного типа и можно ли показать её сейчас (реклама под контролем разработчика). Страницы обычно вызывают AppMintAds.isReady(type).
Возвращает: true / false, синхронно. type равен 'interstitial', 'rewarded', 'rewarded_interstitial' или 'app_open'; 'banner' / 'mrec' всегда возвращают false. Требуется: Управление рекламой → Под контролем разработчика и ID блока для этого типа.
Сначала публичный API:
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Прямой вызов:
var b = window.WebToApk;
var ready = !!(b && typeof b.adsIsReady === 'function' && b.adsIsReady('interstitial'));Показывайте interstitial в конце уровня, только когда он ждёт, и никогда не задерживайте игрока, когда его нет:
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
}
}Примечания: Interstitial в пределах 60-секундной паузы возвращает false. Реклама при открытии приложения старше 4 часов возвращает false (Google просит не показывать её). В автоматическом режиме это всегда false; используйте там WebToApk.isRewardedAdReady().
adsLoad мост#
window.WebToApk.adsLoad(type: String, callbackId: String)
Загружает полноэкранную рекламу [type]; promise для [callbackId] выполняется с результатом.
Пример
Нативная часть AppMintAds.load(type): она начинает загрузку полноэкранной рекламы и отвечает на колбэк оболочки. Страницы используют AppMintAds.load(type), который возвращает Promise; не вызывайте это напрямую.
Возвращает: (через AppMintAds.load) Promise с {ok:true}, {ok:true, cached:true}, если реклама уже загружена, или {ok:false, code, reason, message?, adCode?}. Требуется: Управление рекламой → Под контролем разработчика и ID блока для этого типа.
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
}Повторите загрузку, которая не удалась по временной причине, и остановитесь при причинах, которые повтор не исправит:
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;
});
}Прогрейте два формата перед началом игровой сессии и скройте все рекламные кнопки, если у пользователя вообще нет рекламы:
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);
});
});
}Примечания: Коды ошибок: no_fill, network, invalid_unit, internal (от AdMob, с adCode) и automatic_mode, unknown_type, ad_free, disabled, consent, и use_slot для banner / mrec (они загружаются через AppMintAds.banner.attach). Приложение уже заранее загружает каждый полноэкранный тип с ID блока и перезагружает после каждого показа. Исходная сигнатура: adsLoad(type, callbackId); её ответ идёт во внутренний обработчик, поэтому прямой вызов не даст вам результата.
adsShow мост#
window.WebToApk.adsShow(type: String, callbackId: String, userGesture: Boolean)
Показывает загруженную полноэкранную рекламу [type]; завершается при закрытии, с earned/reward для вознаграждаемых форматов. [userGesture] — показание `navigator.userActivation` оболочки: вознаграждаемый формат, запрошенный без жеста, сначала получает вводный экран AdMob (см. DeveloperAds.offerRewarded).
Пример
Нативная часть AppMintAds.show(type): она показывает загруженную полноэкранную рекламу и отвечает, когда та закрывается. Страницы используют AppMintAds.show(type); не вызывайте это напрямую.
Возвращает: (через AppMintAds.show) Promise с {ok:true, shown:true, earned, reward?} после закрытия рекламы (reward = {type, amount} для вознаграждаемых форматов) или {ok:false, shown:false, code, reason, message?}. Требуется: Управление рекламой → Под контролем разработчика и ID блока для этого типа.
Вызывайте из нажатия пользователя. Оболочка передаёт navigator.userActivation.isActive третьим аргументом (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.');
});
});Предложите вознаграждаемый interstitial по собственному нажатию пользователя «Удвоить мой бонус» и идите дальше при любом ответе:
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
});
});Ставьте музыку игры на паузу, пока на экране любая полноэкранная реклама, используя поток 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
}Примечания: Исходная сигнатура adsShow(type, callbackId, userGesture). Когда userGesture равно false для rewarded или rewarded_interstitial, приложение сначала спрашивает «Посмотреть рекламу? / Нет, спасибо», и ответ «нет» даёт declined. Другие коды: automatic_mode, unknown_type, ad_free, disabled, consent, not_full_screen, showing, cooldown (interstitial, 60 с), not_loaded (загрузка начинается на следующий раз), show_failed, internal.
adsSlotAttach мост#
window.WebToApk.adsSlotAttach(slotId: String, type: String, widthCss: Int, callbackId: String)
Создаёт баннерную/mrec-накладку для блока страницы [slotId] шириной [widthCss]; после загрузки возвращает размер рекламы.
Пример
Нативная часть AppMintAds.banner.attach(element, {size}): она создаёт баннерную рекламу или рекламу «средний прямоугольник» поверх элемента страницы. Страницы используют AppMintAds.banner.attach; не вызывайте это напрямую.
Возвращает: (через AppMintAds.banner.attach) Promise с {ok:true, slot, width, height} в CSS-пикселях после загрузки рекламы или {ok:false, slot, code, message?}. Требуется: Управление рекламой → Под контролем разработчика и ID баннерного (или среднего прямоугольника) блока.
<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>Средний прямоугольник на экране результатов, который освобождает место, если реклама не пришла:
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;
}Считайте показы и клики по каждому блоку из потока appmint:ad по ID блока, который вернул 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);
}
});Примечания: Исходная сигнатура adsSlotAttach(slotId, type, widthCss, callbackId); type равен 'banner' или 'mrec'. WebView не может держать нативный вид внутри страницы, поэтому реклама рисуется поверх вашего элемента и следует за ним при прокрутке и изменении размера (см. adsSlotRect). Не более двух блоков одновременно и только один средний прямоугольник. Дополнительные коды: duplicate_slot, too_many_slots, detached, internal, плюс коды загрузки (no_fill, network, invalid_unit, ad_free, disabled, consent, automatic_mode).
adsSlotDetach мост#
window.WebToApk.adsSlotDetach(slotId: String)
Удаляет баннерную накладку.
Пример
Нативная часть AppMintAds.banner.detach(slotOrElement): она удаляет баннерную накладку и освобождает её блок. Страницы используют AppMintAds.banner.detach.
Возвращает: ничего. Требуется: Управление рекламой → Под контролем разработчика.
Уберите баннер перед экраном, где реклама неуместна (видеоплеер, оформление заказа):
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' });
}В одностраничном приложении освобождайте баннер, когда маршрут, который его содержит, исчезает. attach сразу помечает элемент, поэтому отсоединение по элементу работает, даже пока реклама ещё загружается:
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' });
}
}После покупки «Убрать рекламу» накладки исчезают; отсоедините и блоки и верните страницу место, которое они занимали:
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();
});
});Примечания: Исходная сигнатура adsSlotDetach(slotId). detach принимает элемент или строку slot, которую вернул attach, а не CSS-селектор. Promise от attach, всё ещё ждущий рекламу, получает {ok:false, code:'detached'}. Удаление элемента из DOM тоже отсоединяет блок.
adsSlotRect мост#
window.WebToApk.adsSlotRect(slotId: String, x: Float, y: Float, w: Float, h: Float, visible: Boolean)
Внутренний метод: текущий прямоугольник элемента блока в области просмотра (CSS px) — перемещает накладку.
Пример
Внутренний метод: перемещает баннерную накладку в текущую позицию её элемента. Помощник AppMintAds.banner вызывает его за вас при прокрутке, изменении размера, смене видимости и каждые 500 мс; страницы используют AppMintAds.banner.attach и никогда не вызывают это.
Возвращает: ничего. Требуется: Управление рекламой → Под контролем разработчика и блок, созданный AppMintAds.banner.attach.
Странице нужно лишь дать элементу блока место в вёрстке. Помощник измеряет его и держит рекламу поверх него:
<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>Баннер внутри прокручиваемого списка, а не страницы: помощник слушает прокрутку на фазе захвата, поэтому реклама следует и за внутренним контейнером:
<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>Реклама рисуется поверх страницы, поэтому ваш диалог оказался бы под ней. Скройте блок, пока диалог открыт:
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
});Примечания: Исходная сигнатура adsSlotRect(slotId, x, y, w, h, visible), в CSS-пикселях относительно области просмотра. Накладка скрыта, пока элемент вне экрана, имеет нулевой размер, имеет visibility: hidden или страница в фоне. Если элемент покидает DOM, помощник сам отсоединяет блок.
isInterstitialAdReady мост#
window.WebToApk.isInterstitialAdReady(): Boolean
True, когда interstitial загружен И прошла его пауза (в точности совпадает с тем, что примет showInterstitialAd() — никакого «готово», которое потом отказывается показываться).
Пример
Сообщает, загружен ли interstitial И прошла ли его 60-секундная пауза, то есть showInterstitialAd() показал бы его сейчас (автоматическое управление рекламой).
Возвращает: true / false, синхронно. Требуется: реклама включена и Полноэкранная реклама → 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();
});Показывайте рекламу после каждой третьей завершённой викторины и только когда она действительно покажется:
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
}Показывайте короткое уведомление «Реклама через 3…» только когда реклама готова, затем продолжайте, когда она закроется или не сможет показаться:
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);Примечания: true здесь означает, что показ не будет отклонён из-за not_loaded или cooldown. Согласие или покупка «Убрать рекламу» всё равно могут его остановить (appmint:ad-unavailable). В сборках Под контролем разработчика используйте AppMintAds.isReady('interstitial').
isRewardedAdReady мост#
window.WebToApk.isRewardedAdReady(): Boolean
True, когда вознаграждаемая реклама загружена и может быть показана прямо сейчас. Пусть страница включает/отключает свою кнопку «Смотреть рекламу» по этому значению (опрашивайте или вызывайте перед показом).
Пример
Сообщает, загружена ли вознаграждаемая реклама и можно ли показать её прямо сейчас (автоматическое управление рекламой).
Возвращает: true / false, синхронно. Требуется: реклама включена и Полноэкранная реклама → Вознаграждаемая реклама.
Включайте кнопку «Смотреть рекламу» только когда реклама ждёт:
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);При завершении игры предлагайте «Продолжить» только когда реклама ждёт, чтобы кнопка никогда не вела в никуда:
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(); });Проверьте в момент нажатия и скажите пользователю, что происходит, вместо того чтобы запускать показ, который будет отклонён:
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(); });Примечания: Возвращает false в браузере, когда реклама убрана покупкой и до загрузки первой рекламы. После показа следующая загружается сама. В сборках Под контролем разработчика используйте AppMintAds.isReady('rewarded').
notifyUserAction мост#
window.WebToApk.notifyUserAction()
Внутренний метод (вызывается внедрённым счётчиком нажатий, а не кодом автора): на странице произошло одно значимое действие пользователя. Засчитывается в частоту «interstitial каждые N действий» ТОЛЬКО пока не было замечено ни одной навигации по URL — одностраничные HTML-приложения, переключающие экраны показом/скрытием DOM, никогда не меняют URL, поэтому без этого их счётчик навигации вечно оставался на 0 и настроенная реклама не показывалась (жалоба класса TicTrek, 26.07.2026). URL/SPA-приложения не затронуты: их первая настоящая навигация навсегда возвращает подсчёт к сигналам URL.
Пример
Засчитывает одно значимое действие пользователя в настройку «полноэкранная реклама каждые N действий». Приложение вызывает это само из своего счётчика нажатий; страницы обычно никогда его не вызывают.
Возвращает: ничего. Требуется: реклама включена, Полноэкранная реклама с Режим запуска → После переходов и автоматическое управление рекламой.
Как это работает: страница, переключающая экраны скрытием и показом элементов DOM, никогда не меняет свой URL, поэтому приложение не видит «навигацию». Поэтому приложение внедряет счётчик нажатий (не чаще одного раза в 2 секунды), который вызывает этот метод. Как только приложение видит одно настоящее изменение URL (загрузка страницы, pushState или #hash), оно считает изменения URL, а этот метод перестаёт считать.
Только если смены экрана происходят не от нажатия (например, от клавиатуры или геймпада), сообщайте о них сами:
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');
});Приложение с карточками, где пользователь листает к следующему экрану (свайп — это не нажатие кнопки, поэтому счётчик нажатий его не видит):
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();
});HTML5-игра с геймпадом, засчитывающая одно действие за каждый уровень, который игрок начинает кнопкой 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 });Примечания: Ничего не делает, если реклама выключена, убрана покупкой или сборка использует Управление рекламой → Под контролем разработчика (там вы вызываете AppMintAds.show() сами). Вознаграждаемая реклама, показанная таким способом, всегда предлагается вопросом «Посмотреть рекламу? / Нет, спасибо» и никогда не навязывается. Не вызывайте её при каждом нажатии: реклама будет показываться чаще, чем вы настроили.
showInterstitialAd мост#
window.WebToApk.showInterstitialAd()
Показать interstitial СЕЙЧАС (например, между уровнями / при осознанном действии). Если сейчас показать нельзя — пропуск + 'appmint:ad-unavailable' с причиной.
Пример
Показывает полноэкранный interstitial прямо сейчас, например между двумя уровнями игры (автоматическое управление рекламой).
Возвращает: ничего. Когда реклама закрывается, срабатывает appmint:ad-closed с {adType:'interstitial', earned:false}. Когда её нельзя показать, срабатывает appmint:ad-unavailable с {adType:'interstitial', reason}. Требуется: реклама включена и Полноэкранная реклама → Interstitial. Выберите Режим запуска → По запросу, если только ваша страница должна решать когда.
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(); }
});Поставьте игру и её звук на паузу перед рекламой и возобновите при любом ответе:
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);Откройте статью после рекламы одним Promise, который выполняется с true, если реклама была показана, и с false, если пропущена:
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); });Примечания: Приложение выдерживает не менее 60 секунд между двумя interstitial; вызов в этом промежутке возвращает cooldown. isInterstitialAdReady() уже учитывает паузу, поэтому проверка сначала позволяет избежать события. Показывайте interstitial в естественных паузах, а не при каждом нажатии. В сборках Под контролем разработчика используйте AppMintAds.show('interstitial').
showRewardedAd мост#
window.WebToApk.showRewardedAd()
Показать вознаграждаемую рекламу СЕЙЧАС (по инициативе пользователя — единственный способ показа вознаграждаемой рекламы, соответствующий политике). Сочетайте с режимом запуска «По запросу» в мастере, чтобы получить вознаграждаемую рекламу БЕЗ какой-либо автоматической рекламы при открытии приложения/навигации. Награда доставляется странице через deliverRewardToPage(): window.addEventListener('appmint:reward', e => { /* e.detail = {type,amount} */ }) Когда реклама закрывается, срабатывает 'appmint:ad-closed' с {adType:'rewarded', earned} — earned равно false, если пользователь вышел раньше, поэтому в этом случае ничего не начисляйте. Если сейчас показать нельзя — пропуск + срабатывает 'appmint:ad-unavailable' с причиной.
Пример
Показывает вознаграждаемую рекламу прямо сейчас по собственному нажатию пользователя «Смотреть рекламу» (автоматическое управление рекламой).
Возвращает: ничего. Результат приходит позже в виде событий: appmint:reward {type, amount}, когда рекламу досмотрели до конца, appmint:ad-closed {adType:'rewarded', earned}, когда она закрывается, или appmint:ad-unavailable {adType:'rewarded', reason}, когда показать ничего не удалось. Требуется: реклама включена, Полноэкранная реклама → Вознаграждаемая реклама и Режим запуска → По запросу, чтобы ничего не показывалось само.
Начисляйте награду только в обработчике награды, а не при нажатии:
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();
});Те же три момента вызывают и хуки страницы, если вы предпочитаете по функции на каждый (каждый получает тот же объект, что и 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); };Оберните вызов и его события в один Promise, чтобы каждая кнопка «Смотреть рекламу» читалась как обычный асинхронный вызов:
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.');
});
});Примечания: Вызывайте только из обработчика клика. Никогда не вызывайте из таймера, загрузки страницы или смены маршрута и никогда не прячьте за этим основную функцию. not_loaded тоже начинает новую загрузку, поэтому следующее нажатие обычно срабатывает. В сборках Управление рекламой → Под контролем разработчика используйте вместо этого AppMintAds.show('rewarded'), который отвечает Promise.