واجهة JavaScript bridge API
الإعلانات
عرض إعلان بيني أو إعلان بمكافأة عند إشارتك أنت، وإخبار الغلاف عند بدء التنقل واستقراره حتى لا يقاطع أحدهما.
AppMintAds.appOpen دالة مساعدة (helper)#
window.AppMintAds.appOpen.setEnabled(on)
مثال
يوقف إعلان فتح التطبيق أو يستأنفه، وهو الإعلان بملء الشاشة الذي يظهر عند الإطلاق وعندما يعود المستخدم من تطبيق آخر.
يعيد: لا شيء. يتطلب: التحكم في الإعلانات ← يتحكم به المطوّر ومعرّف وحدة إعلان فتح التطبيق.
أوقفه مؤقتًا بينما يغادر المستخدم التطبيق عمدًا لوقت قصير (تطبيق دفع، الكاميرا، قائمة المشاركة)، حتى لا يظهر إعلان عند عودته:
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 دالة مساعدة (helper)#
window.AppMintAds.banner.attach(target, opts) / .detach(slotOrElement)
مثال
يضع إعلان بانر أو مستطيل متوسط 300×250 في أي مكان من صفحتك، فوق عنصر تختاره.
يعيد: attach يعيد Promise لـ {ok:true, slot, width, height} (بكسل CSS) بعد تحميل الإعلان، أو {ok:false, slot?, code, message?}. detach لا يعيد شيئًا. يتطلب: التحكم في الإعلانات ← يتحكم به المطوّر ومعرّف وحدة إعلان بانر (أو مستطيل متوسط).
العنصر يحجز المساحة فقط. يُرسم الإعلان فوقه ويتبعه عند تمرير الصفحة أو تغيير حجمها:
<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 إلى العنصر أو معرّف المكان من attach، وليس محددًا. إزالة العنصر من DOM تفصله أيضًا. الرموز: 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()
مثال
يخبر الصفحة بوضع التحكم في الإعلانات الذي يستخدمه البناء وصيغ الإعلانات التي يمكنه تقديمها.
يعيد: كائنًا، بشكل متزامن: {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 عندما تكون الإعلانات مفعّلة ويملك البناء معرّف وحدة إعلان لها. في الوضع التلقائي (control: 'automatic') كل استدعاء لـ load / show / banner.attach يجيب بـ code: 'automatic_mode'؛ استخدم WebToApk.showRewardedAd() / showInterstitialAd() هناك. اختر التحكم في الإعلانات ← يتحكم به المطوّر في معالج البناء لتشغيل الإعلانات من الصفحة.
AppMintAds.isReady دالة مساعدة (helper)#
window.AppMintAds.isReady(type)
مثال
يخبرك إن كان إعلان بملء الشاشة من هذا النوع محمّلًا ويمكن عرضه الآن.
يعيد: true / false، بشكل متزامن. type: 'interstitial'، 'rewarded'، 'rewarded_interstitial' أو 'app_open'. يتطلب: التحكم في الإعلانات ← يتحكم به المطوّر ومعرّف وحدة إعلان للنوع.
أبقِ زر "شاهد إعلانًا" متزامنًا مع الإعلان باستخدام حدث الحالة 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 (فهما يُرفقان ولا يُعرضان). الإعلان البيني ضمن فترة التهدئة البالغة 60 ثانية يجيب بـ false؛ وإعلان فتح التطبيق الأقدم من 4 ساعات يجيب بـ false. في الوضع التلقائي يكون هذا دائمًا false.
AppMintAds.load دالة مساعدة (helper)#
window.AppMintAds.load(type)
مثال
يحمّل إعلانًا بملء الشاشة بحيث يمكن لـ show(type) لاحق تشغيله فورًا.
يعيد: Promise يُنجز (ولا يُرفض أبدًا) بـ {ok:true}، أو {ok:true, cached:true} عندما يكون واحد بالفعل في الانتظار، أو {ok:false, code, reason, message?, adCode?}. يتطلب: التحكم في الإعلانات ← يتحكم به المطوّر ومعرّف وحدة إعلان للنوع (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); };حمّل الإعلان البيني عند بدء المرحلة، ليكون جاهزًا عند نهايتها، وتوقف عن الطلب بمجرد أن يزيل المستخدم الإعلانات:
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). يحمّل التطبيق مسبقًا كل نوع بملء الشاشة له معرّف وحدة ويحمّل التالي بعد كل عرض، لذا load مفيدة غالبًا لمعرفة متى يمكن تفعيل الزر.
AppMintAds.show دالة مساعدة (helper)#
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?} عندما لم يُعرض شيء. يتطلب: التحكم في الإعلانات ← يتحكم به المطوّر ومعرّف وحدة إعلان للنوع.
إعلان بمكافأة: استدعه داخل نقرة المستخدم نفسه. تلك النقرة هي موافقة المستخدم، لذا يُعرض الإعلان فورًا. امنح المكافأة فقط عندما تكون earned صحيحة:
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.');
});إعلان بيني: عند توقف طبيعي. تابع مهما كانت الإجابة:
async function levelFinished() {
if (window.AppMintAds && window.AppMintAds.isReady('interstitial')) {
await window.AppMintAds.show('interstitial'); // resolves when the ad closes
}
showNextLevel();
}إعلان بيني بمكافأة خلف شاشة تمهيدية خاصة بك مع "لا، شكرًا" واضحة. النقرة على "شاهد" هي الموافقة:
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();
});ملاحظات: إعلان بمكافأة أو إعلان بيني بمكافأة show() لا يأتي من نقرة المستخدم (مؤقّت، تحميل صفحة، تغيير مسار) يحصل أولًا على شاشة "هل تريد مشاهدة إعلان؟ / لا، شكرًا"، وتجيب "لا، شكرًا" بـ declined. لا تشغّل صيغ المكافآت بهذه الطريقة أبدًا. رموز أخرى: automatic_mode، unknown_type، ad_free، disabled، consent، not_full_screen، showing، cooldown (60 ثانية بين الإعلانات البينية)، not_loaded (يبدأ تحميل جديد للمرة القادمة)، show_failed، internal. في الوضع التلقائي استخدم WebToApk.showRewardedAd().
adsAppOpenEnable الجسر (bridge)#
window.WebToApk.adsAppOpenEnable(enabled: Boolean)
يتيح للصفحة إيقاف إعلان فتح التطبيق أو استئنافه عند العودة من تطبيق آخر (مفعّل افتراضيًا عند ضبط وحدة).
مثال
النصف الأصلي من AppMintAds.appOpen.setEnabled(on): يوقف إعلان فتح التطبيق أو يستأنفه. تستخدم الصفحات AppMintAds.appOpen.setEnabled.
يعيد: لا شيء. يتطلب: التحكم في الإعلانات ← يتحكم به المطوّر ومعرّف وحدة إعلان فتح التطبيق.
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 الجسر (bridge)#
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 عندما تكون الإعلانات مفعّلة ويملك البناء معرّف وحدة إعلان لها. يتطلب: لا شيء.
الواجهة العامة أولًا:
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 الجسر (bridge)#
window.WebToApk.adsIsReady(type: String): Boolean
صحيح عندما يكون [type] بملء الشاشة محمّلًا ويمكن عرضه الآن.
مثال
يخبرك إن كان إعلان بملء الشاشة من نوع واحد محمّلًا ويمكن عرضه الآن (إعلانات يتحكم بها المطوّر). تستدعي الصفحات عادةً AppMintAds.isReady(type).
يعيد: true / false، بشكل متزامن. type هو 'interstitial'، 'rewarded'، 'rewarded_interstitial' أو 'app_open'؛ و'banner' / 'mrec' يجيبان دائمًا بـ false. يتطلب: التحكم في الإعلانات ← يتحكم به المطوّر ومعرّف وحدة إعلان لذلك النوع.
الواجهة العامة أولًا:
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'));اعرض إعلانًا بينيًا في نهاية المرحلة فقط عندما يكون واحد جاهزًا، ولا تُعطّل اللاعب أبدًا عندما لا يكون:
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
}
}ملاحظات: الإعلان البيني ضمن فترة التهدئة البالغة 60 ثانية يجيب بـ false. إعلان فتح التطبيق الأقدم من 4 ساعات يجيب بـ false (تقول Google ألا يُعرض). في الوضع التلقائي يكون هذا دائمًا false؛ استخدم WebToApk.isRewardedAdReady() هناك.
adsLoad الجسر (bridge)#
window.WebToApk.adsLoad(type: String, callbackId: String)
يحمّل [type] بملء الشاشة؛ ويُنجز الوعد الخاص بـ [callbackId] بالنتيجة.
مثال
النصف الأصلي من AppMintAds.load(type): يبدأ تحميل إعلان بملء الشاشة ويجيب على callback الطبقة الوسيطة. تستخدم الصفحات AppMintAds.load(type) الذي يعيد Promise؛ لا تستدعِ هذا مباشرة.
يعيد: (عبر AppMintAds.load) Promise لـ {ok:true}، أو {ok:true, cached:true} عندما يكون واحد محمّلًا بالفعل، أو {ok:false, code, reason, message?, adCode?}. يتطلب: التحكم في الإعلانات ← يتحكم به المطوّر ومعرّف وحدة إعلان للنوع.
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). يحمّل التطبيق مسبقًا كل نوع بملء الشاشة له معرّف وحدة، ويعيد التحميل بعد كل عرض. التوقيع الخام هو adsLoad(type, callbackId)؛ وتذهب إجابته إلى محلّل داخلي، لذا الاستدعاء المباشر لا يعطيك نتيجة.
adsShow الجسر (bridge)#
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?}. يتطلب: التحكم في الإعلانات ← يتحكم به المطوّر ومعرّف وحدة إعلان للنوع.
استدعه من نقرة المستخدم. تمرر الطبقة الوسيطة 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.');
});
});اعرض إعلانًا بينيًا بمكافأة من نقرة المستخدم نفسه "ضاعف مكافأتي"، وتابع مهما كانت الإجابة:
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 (إعلان بيني، 60 ثانية)، not_loaded (يبدأ تحميل للمرة القادمة)، show_failed, internal.
adsSlotAttach الجسر (bridge)#
window.WebToApk.adsSlotAttach(slotId: String, type: String, widthCss: Int, callbackId: String)
ينشئ طبقة بانر/مستطيل متوسط لمكان [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?}. يتطلب: التحكم في الإعلانات ← يتحكم به المطوّر ومعرّف وحدة إعلان بانر (أو مستطيل متوسط).
<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، باستخدام معرّف المكان الذي أعاده 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 الجسر (bridge)#
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 الجسر (bridge)#
window.WebToApk.adsSlotRect(slotId: String, x: Float, y: Float, w: Float, h: Float, visible: Boolean)
داخلي: مستطيل إطار العرض الحالي لعنصر المكان (بكسل CSS) - ينقل الطبقة.
مثال
داخلي: ينقل طبقة بانر إلى الموضع الحالي لعنصرها. تستدعيه أداة 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>بانر داخل قائمة قابلة للتمرير، وليس الصفحة: تستمع الأداة المساعدة للتمرير في مرحلة الالتقاط (capture)، لذلك يتبع الإعلان الحاوية الداخلية أيضًا:
<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 الجسر (bridge)#
window.WebToApk.isInterstitialAdReady(): Boolean
صحيح عندما يكون إعلان بيني محمّلًا وتجاوز فترة تهدئته (يطابق تمامًا ما سيقبله showInterstitialAd() - فلا "جاهز" يرفض بعده العرض).
مثال
يخبرك إن كان إعلان بيني محمّلًا وتجاوز فترة التهدئة البالغة 60 ثانية، بحيث يعرضه showInterstitialAd() الآن (التحكم التلقائي في الإعلانات).
يعيد: true / false، بشكل متزامن. يتطلب: تشغيل الإعلانات وإعلان بملء الشاشة ← إعلان بيني.
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 الجسر (bridge)#
window.WebToApk.isRewardedAdReady(): Boolean
صحيح عندما يكون إعلان بمكافأة محمّلًا ويمكن عرضه الآن. دع الصفحة تفعّل/تعطّل زر "شاهد إعلانًا" بناءً على هذا (استعلم أو استدعِ قبل العرض).
مثال
يخبرك إن كان إعلان بمكافأة محمّلًا ويمكن عرضه الآن (التحكم التلقائي في الإعلانات).
يعيد: 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 الجسر (bridge)#
window.WebToApk.notifyUserAction()
داخلي (يستدعيه عدّاد النقرات المحقون، وليس كود المطوّر): حدث تفاعل مهم واحد من المستخدم في الصفحة. يُحتسب ضمن وتيرة "إعلان بيني كل N إجراء" فقط ما دام لم يُلاحَظ أي تنقل قائم على العنوان - فالتطبيقات ذات HTML واحد التي تبدّل الشاشات بإظهار/إخفاء DOM لا يتغير عنوانها أبدًا، وبدون هذا ظل عدّاد التنقل عندها صفرًا إلى الأبد ولم تظهر الإعلانات المضبوطة أبدًا (فئة شكوى TicTrek، 2026-07-26). لا تتأثر تطبيقات العنوان/SPA: أول تنقل حقيقي لها يعيد العدّ نهائيًا إلى إشارات العنوان.
مثال
يحتسب إجراءً مهمًا واحدًا من المستخدم ضمن إعداد "إعلان بملء الشاشة كل N إجراء". يستدعيه التطبيق بنفسه من عدّاد نقراته؛ ولا تستدعيه الصفحات عادةً.
يعيد: لا شيء. يتطلب: تشغيل الإعلانات، وإعلان بملء الشاشة مع وضع التشغيل ← بعد التنقلات، والتحكم التلقائي في الإعلانات.
كيف يعمل: الصفحة التي تبدّل الشاشات بإخفاء عناصر DOM وإظهارها لا يتغير عنوانها أبدًا، لذلك لا يستطيع التطبيق رؤية "تنقل". لذلك يحقن التطبيق عدّاد نقرات (عدّة واحدة كحد أقصى كل ثانيتين) يستدعي هذه الدالة. بمجرد أن يرى التطبيق تغييرًا حقيقيًا واحدًا في العنوان (تحميل صفحة، pushState أو #hash)، يعدّ تغييرات العنوان بدلًا من ذلك وتتوقف هذه الدالة عن العدّ.
فقط إذا كانت تغييرات شاشتك لا تأتي من نقرة (مثل حركة بلوحة المفاتيح أو يد التحكم)، أبلغ عنها بنفسك:
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 الجسر (bridge)#
window.WebToApk.showInterstitialAd()
اعرض إعلانًا بينيًا الآن (مثلًا بين المراحل / عند إجراء مقصود). إذا تعذر العرض الآن → يُتخطى + 'appmint:ad-unavailable' مع السبب.
مثال
يعرض إعلانًا بينيًا بملء الشاشة الآن، مثلًا بين مرحلتين من اللعبة (التحكم التلقائي في الإعلانات).
يعيد: لا شيء. عند إغلاق الإعلان يُطلق appmint:ad-closed مع {adType:'interstitial', earned:false}. وعندما يتعذر عرضه يُطلق appmint:ad-unavailable مع {adType:'interstitial', reason}. يتطلب: تشغيل الإعلانات وإعلان بملء الشاشة ← إعلان بيني. اختر وضع التشغيل ← عند الطلب إذا كان يجب أن تقرر صفحتك وحدها متى.
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 ثانية على الأقل بين إعلانين بينيين؛ والاستدعاء ضمن هذه الفجوة يجيب بـ cooldown. isInterstitialAdReady() تتضمن فترة التهدئة بالفعل، لذا فحصها أولًا يتجنب الحدث. اعرض الإعلانات البينية عند توقفات طبيعية، وليس عند كل نقرة. في بناءات يتحكم به المطوّر استخدم AppMintAds.show('interstitial').
showRewardedAd الجسر (bridge)#
window.WebToApk.showRewardedAd()
اعرض إعلانًا بمكافأة الآن (بمبادرة المستخدم - الطريقة الوحيدة المتوافقة مع السياسة لعرض الإعلانات بمكافأة). اقرنه بوضع التشغيل "عند الطلب" في المعالج للحصول على إعلانات بمكافأة دون أي إعلانات فتح تطبيق/تنقل تلقائية. تُسلَّم المكافأة إلى الصفحة عبر deliverRewardToPage(): window.addEventListener('appmint:reward', e => { /* e.detail = {type,amount} */ }) عند إغلاق الإعلان يُطلق 'appmint:ad-closed' مع {adType:'rewarded', earned} - تكون earned خاطئة إذا انسحب المستخدم مبكرًا، فلا تمنح شيئًا في تلك الحالة. إذا تعذر العرض الآن → يُتخطى + يُطلق '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 واحد، ليُقرأ كل زر "شاهد إعلانًا" كاستدعاء async عادي:
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.