واجهة JavaScript bridge API
النافذة
ملء الشاشة، وصورة داخل صورة، وألوان أشرطة النظام، ومنع لقطات الشاشة، وهل حماية النسخ مفعّلة في البناء (AppMint.copyProtection)، وشاشة البداية، وإغلاق نافذة.
AppMint.copyProtection دالة مساعدة (helper)#
AppMint.copyProtection
مثال
true عندما بُني التطبيق مع تفعيل حماية النسخ؛ وغائبة (undefined) خلاف ذلك. للقراءة فقط - لا تستطيع الصفحة تشغيل الحماية أو إيقافها، بل فقط السؤال هل هي مفعّلة.
تُرجع: true، أو undefined عندما تكون الحماية متوقفة (وفي المتصفح). المتطلبات: تفعيل حماية النسخ في الخطوة 3 (التكامل)، تحت خيارات العرض، عند الإنشاء. الافتراضي متوقف.
مع تفعيل الحماية، لا يمكن تحديد نص التطبيق أو نسخه أو قصّه؛ ويُلغى النسخ / القص وحدث contextmenu وCtrl/Cmd + C وX وA خارج الحقول القابلة للتحرير؛ ولا تظهر قائمة الضغط المطوّل. تبقى حقول الإدخال ومناطق النص والقوائم ومناطق contenteditable قابلة للتحرير بالكامل، فتواصل النماذج عملها.
أخفِ أزرار "نسخ" الخاصة بك عندما تكون الحماية مفعّلة - فهي لن تنسخ شيئًا وتبدو معطّلة:
const protectedApp = !!(window.AppMint && window.AppMint.copyProtection === true);
document.querySelectorAll('[data-copy-button]').forEach((btn) => {
btn.hidden = protectedApp;
});أو اختر صياغة تلميح مرة واحدة عند بدء التشغيل:
const hint = document.getElementById('share-hint');
hint.textContent = (window.AppMint && window.AppMint.copyProtection === true)
? 'Tap Share to send this lesson to a friend.'
: 'Select any text to copy it, or tap Share.';اجمعه مع قفل لقطات الشاشة لصفحة يجب ألا تغادر التطبيق:
if (window.AppMint && AppMint.copyProtection === true && window.WebToApk && WebToApk.setSecureScreen) {
WebToApk.setSecureScreen(true); // also blocks screenshots and recents thumbnails
document.body.classList.add('protected');
}ملاحظات: قائمة الضغط المطوّل على الروابط والصور (فتح أو نسخ أو مشاركة أو تنزيل) مفتاح بناء منفصل، قائمة الضغط المطوّل على الروابط والصور، في المكان نفسه. هي متوقفة افتراضيًا، فالضغط المطوّل على رابط لا يفعل شيئًا ما لم تفعّلها؛ وحماية النسخ تُبقيها متوقفة دائمًا. يمكن للصفحة مع ذلك رفض القائمة على عنصر واحد بإلغاء contextmenu (el.addEventListener('contextmenu', (e) => e.preventDefault())). الحماية توقف النسخ داخل التطبيق؛ ولا توقف لقطة الشاشة - لذلك راجع WebToApk.setSecureScreen(true).
screen.orientation معيار الويب#
screen.orientation.lock(type) / unlock()
مثال
قفل اتجاه الشاشة القياسي، الذي ترفضه WebView العادية: يقلب التطبيق إلى الوضع الأفقي لفيديو أو لعبة ثم يعيده.
تُرجع: lock(type) → Promise يُحلّ بعد طلب الاتجاه؛ ويُرفض بـ TypeError لنوع غير معروف وبـ NotSupportedError على Android TV. unlock() يعيد الاتجاه الذي بُني به التطبيق. المتطلبات: لا شيء.
const player = document.getElementById('player');
document.getElementById('fullscreen').addEventListener('click', async () => {
try {
await screen.orientation.lock('landscape'); // either landscape, follows the sensor
} catch (e) {
console.log('Could not rotate:', e.name);
}
player.classList.add('wide');
});
document.getElementById('done').addEventListener('click', () => {
screen.orientation.unlock();
player.classList.remove('wide');
});
screen.orientation.addEventListener('change', () => console.log(screen.orientation.type));اقلب اللعبة إلى الوضع الأفقي عند بدئها؛ وفي Android TV الشاشة أفقية أصلًا، فتابع:
async function startGame() {
try {
await screen.orientation.lock('landscape');
} catch (e) {
if (e.name !== 'NotSupportedError') console.log('Could not rotate:', e.name);
}
runGame();
}
function quitGame() {
screen.orientation.unlock(); // back to the orientation the app was built with
showMenu();
}اتبع شكل الفيديو الجاري تشغيله، وارجع عند انتهائه:
const video = document.getElementById('clip');
video.addEventListener('play', () => {
const wide = video.videoWidth >= video.videoHeight;
screen.orientation.lock(wide ? 'landscape' : 'portrait').catch((e) => console.log(e.name));
});
video.addEventListener('ended', () => screen.orientation.unlock());ملاحظات: الأنواع: any، natural، portrait، portrait-primary، portrait-secondary، landscape، landscape-primary، landscape-secondary. بخلاف Chrome، لا يلزم أن تكون الصفحة في ملء الشاشة أولًا. التطبيقات المبنية بالذكاء الاصطناعي تستخدم lockOrientation() من @/lib/appmintNative.
window.close معيار الويب#
window.close()
مثال
يغلق الشاشة الرئيسية للتطبيق. يستبدل الغلاف window.close() فيعمل زر "إغلاق" أو "خروج" في صفحتك داخل التطبيق.
يعيد: لا شيء. يتطلب: لا شيء.
document.getElementById('exit-btn').onclick = function () {
saveDraft(); // anything unsaved — the screen closes at once
window.close(); // in the app: WebToApk.closeWindow(); in a browser: normal behaviour
};أخفِ الزر في المتصفح، حيث لا يفعل window.close() عادةً شيئًا في تبويب فتحه المستخدم:
if (!window.WebToApk) document.getElementById('exit-btn').hidden = true;اسأل أولًا، لأن التطبيق يُغلق لحظة تشغيل window.close():
document.getElementById('quit').addEventListener('click', function () {
if (hasUnsavedChanges() && !confirm('You have unsaved changes. Close the app anyway?')) {
return;
}
window.close();
});ملاحظات: يُثبَّت الاستبدال بعد انتهاء تحميل كل صفحة، لذا الاستدعاء أثناء أول تشغيل لسكربت الصفحة يستخدم window.close() الخاص بـ WebView (الذي لا يفعل شيئًا). لا يوجد تأكيد خروج في هذا المسار. نافذة تسجيل الدخول المنبثقة التي تستدعي window.close() تُعالَج بشكل منفصل: فهي تغلق النافذة المنبثقة لا التطبيق.
__lockOrientation الجسر (bridge)#
window.WebToApk.__lockOrientation(type: String): String
screen.orientation.lock(type): "ok"، أو "type" لسلسلة ليست OrientationLockType، أو "unsupported" (Android TV أفقي دائمًا).
مثال
ناقل داخلي يقف خلف screen.orientation.lock(type). تستخدم الصفحات الواجهة القياسية؛ لا تستدعِ هذا مباشرةً أبدًا - فقد تتغير دوال __ دون إشعار.
تُرجع: 'ok'، أو 'type' لسلسلة ليست نوع قفل اتجاه، أو 'unsupported' (Android TV). المتطلبات: لا شيء لتفعيله.
استخدم الواجهة العامة:
document.getElementById('play').addEventListener('click', async () => {
try { await screen.orientation.lock('landscape'); } catch (e) { /* NotSupportedError on TV */ }
});
document.getElementById('exit').addEventListener('click', () => screen.orientation.unlock());ميّز نوع قفل خاطئ عن جهاز لا يستطيع التدوير:
async function lockTo(type) {
if (!screen.orientation || typeof screen.orientation.lock !== 'function') return 'unsupported';
try {
await screen.orientation.lock(type);
return 'ok';
} catch (e) {
if (e instanceof TypeError) return 'bad-type'; // not an OrientationLockType string
return 'unsupported'; // NotSupportedError (Android TV)
}
}
lockTo('portrait-primary').then((r) => console.log('orientation lock:', r));ثبّت الشاشة بالطريقة التي يمسك بها المستخدم هاتفه أثناء توقيعه، ثم أعد التدوير:
async function startSigning() {
const current = screen.orientation.type; // e.g. 'landscape-primary'
try { await screen.orientation.lock(current); } catch (e) { /* keep going unlocked */ }
showSignaturePad();
}
function finishSigning() {
hideSignaturePad();
screen.orientation.unlock();
}ملاحظات: منفَّذ في غلاف التطبيق (WebApiPolyfills.kt). يعمل كود الصفحة نفسه دون تغيير في Chrome.
__unlockOrientation الجسر (bridge)#
window.WebToApk.__unlockOrientation()
screen.orientation.unlock(): العودة إلى الاتجاه الذي بنى به المنشئ.
مثال
ناقل داخلي يقف خلف screen.orientation.unlock(). تستخدم الصفحات الواجهة القياسية؛ لا تستدعِ هذا مباشرةً أبدًا - فقد تتغير دوال __ دون إشعار.
تُرجع: لا شيء؛ يعود التطبيق إلى الاتجاه المختار عند البناء. المتطلبات: لا شيء لتفعيله.
استخدم الواجهة العامة:
document.getElementById('play').addEventListener('click', async () => {
try { await screen.orientation.lock('landscape'); } catch (e) { /* NotSupportedError on TV */ }
});
document.getElementById('exit').addEventListener('click', () => screen.orientation.unlock());فقط مسار اللعبة أفقي؛ وكل مسار آخر يعود إلى اتجاه التطبيق الأصلي:
function onRouteChange(path) {
if (path.startsWith('/play')) {
screen.orientation.lock('landscape').catch(() => {});
} else if (screen.orientation && typeof screen.orientation.unlock === 'function') {
screen.orientation.unlock(); // menus, settings and the store
}
}
window.addEventListener('popstate', () => onRouteChange(location.pathname));
onRouteChange(location.pathname);أبقِ شرائح التعريف قائمة، ثم افتح القفل عند الانتهاء:
async function showOnboarding() {
try { await screen.orientation.lock('portrait'); } catch (e) { /* TV: no lock */ }
await runOnboardingSlides(); // your own flow
screen.orientation.unlock(); // back to the orientation the app was built with
}ملاحظات: منفَّذ في غلاف التطبيق (WebApiPolyfills.kt). يعمل كود الصفحة نفسه دون تغيير في Chrome.
__wakeLock الجسر (bridge)#
window.WebToApk.__wakeLock(docId: String, held: Boolean): Boolean
قفل إبقاء الشاشة مضاءة: [held] true يُبقي الشاشة مضاءة طالما يحمل المستند [docId] حارسًا. يُرجع false عندما تعذّر أخذ القفل.
مثال
ناقل داخلي خلف navigator.wakeLock.request('screen') وWakeLockSentinel.release(). تستخدم الصفحات الواجهة القياسية؛ لا تستدعِ هذا مباشرة - دوال __ قد تتغير دون إشعار.
تُرجع: true عندما طُبّقت علامة إبقاء الشاشة مضاءة لذلك المستند. المتطلبات: لا شيء لتفعيله.
استخدم الواجهة العامة:
let lock = null;
async function keepScreenOn() {
if (!('wakeLock' in navigator)) return;
lock = await navigator.wakeLock.request('screen');
lock.addEventListener('release', () => { lock = null; });
}خذ القفل من جديد عندما يعود المستخدم إلى التطبيق، لأن كل قفل يُسقَط في الخلفية:
let lock = null;
let wantLock = false;
async function acquire() {
if (!('wakeLock' in navigator)) return;
try {
lock = await navigator.wakeLock.request('screen');
lock.addEventListener('release', () => { lock = null; });
} catch (e) {
lock = null; // NotAllowedError: the page was not visible
}
}
function startRecipeMode() { wantLock = true; acquire(); }
function stopRecipeMode() { wantLock = false; if (lock) lock.release(); }
document.addEventListener('visibilitychange', () => {
if (wantLock && !lock && document.visibilityState === 'visible') acquire();
});أبقِ الشاشة مضاءة فقط أثناء عمل مؤقّت التمرين، ودعها تنام من جديد عند انتهائه:
async function runTimer(seconds) {
const lock = ('wakeLock' in navigator)
? await navigator.wakeLock.request('screen').catch(() => null)
: null;
try {
for (let left = seconds; left > 0; left--) {
showRemaining(left);
await new Promise((r) => setTimeout(r, 1000));
}
} finally {
if (lock && !lock.released) await lock.release();
}
}ملاحظات: يُسقط التطبيق كل الأقفال عند ذهابه إلى الخلفية ويطلق appmint:wakelock-lost، الذي يحرر الحراس (يُطلق حدث release الخاص بهم).
closeWindow الجسر (bridge)#
window.WebToApk.closeWindow()
استخدم غلاف الوعد: const r = await AppMint.requestReview(); // {result, openedStore} const r = await AppMint.requestReview({ openStore: true }); // صفحة المتجر إن لم تظهر الورقة r.result: 'shown' | 'not_from_play' | 'quota' | 'error'. راجع RatePrompt.
موصوفة في مجموعتها، ورقة التقييم داخل التطبيق من Google Play، لا بمفردها.
مثال
يغلق الشاشة الرئيسية للتطبيق (مثل الضغط على رجوع في الصفحة الأخيرة). تستدعي الصفحات عادةً window.close() القياسي، الذي يوجّهه الغلاف إلى هنا.
يعيد: لا شيء. يتطلب: لا شيء.
document.getElementById('quit').onclick = function () {
if (confirm('Close the app?')) window.close(); // in the app: the screen closes
};الاستدعاء الخام يفعل الشيء نفسه:
if (window.WebToApk && typeof window.WebToApk.closeWindow === 'function') {
window.WebToApk.closeWindow();
}زر "خروج" يحفظ أولًا، ويُخفى في المتصفح حيث لا توجد شاشة تطبيق لإغلاقها:
var exitBtn = document.getElementById('exit-btn');
if (!(window.WebToApk && typeof window.WebToApk.closeWindow === 'function')) {
exitBtn.hidden = true;
} else {
exitBtn.onclick = async function () {
exitBtn.disabled = true;
await saveDraft(); // your own save; closing does not wait for anything
window.WebToApk.closeWindow();
};
}ملاحظات: يُنهي شاشة التطبيق فورًا - بلا تأكيد خروج، حتى لو كان في البناء. احفظ أي شيء غير محفوظ أولًا. في المتصفح window.close() يغلق فقط تبويبًا فتحه السكربت نفسه.
enterPip الجسر (bridge)#
window.WebToApk.enterPip(): Boolean
يُصغّر التطبيق كله إلى نافذة صورة داخل صورة عائمة الآن - فيديو أو مكالمة يريد المستخدم مواصلة مشاهدتها أثناء مغادرته. Android 8+ وفقط عندما فعّل البناء PiP (علامة manifest التي يحتاجها)؛ ويُرجع هل فُتحت النافذة. مغادرة التطبيق مع تفعيل PiP تفعل ذلك تلقائيًا؛ وهذا هو زر "التصغير" الصريح.
مثال
يُصغّر التطبيق كله إلى نافذة صورة داخل صورة عائمة صغيرة الآن - زر "تصغير" لفيديو أو مكالمة.
تُرجع: true إذا فُتحت النافذة العائمة، false خلاف ذلك (بشكل متزامن). المتطلبات: تفعيل صورة داخل صورة (PiP) في الخطوة 3 (التكامل)، تحت خيارات العرض، عند الإنشاء. Android 8+.
var pipBtn = document.getElementById('pip-btn');
pipBtn.onclick = function () {
if (!(window.WebToApk && typeof window.WebToApk.enterPip === 'function')) return;
var ok = window.WebToApk.enterPip();
if (!ok) pipBtn.hidden = true; // PiP not enabled in this build, or Android 7 and older
};اجعل الصفحة تناسب النافذة الصغيرة: تصبح النافذة ضيقة جدًا، لذا يمكن لمستمع resize إخفاء كل شيء عدا الفيديو.
window.addEventListener('resize', function () {
var small = window.innerWidth < 300;
document.querySelector('nav').style.display = small ? 'none' : '';
});تابع فتح النافذة العائمة وإغلاقها بالحدث appmint:pip (detail.inPip)، مثلًا لإخفاء أزرار مكالمة:
window.addEventListener('appmint:pip', function (e) {
var inPip = !!(e.detail && e.detail.inPip);
document.body.classList.toggle('pip', inPip); // CSS: .pip .call-controls { display: none; }
if (!inPip) {
document.getElementById('chat-panel').hidden = false; // back to the full-size screen
}
});
document.getElementById('minimise').onclick = function () {
if (window.WebToApk && typeof window.WebToApk.enterPip === 'function') {
document.getElementById('chat-panel').hidden = true;
window.WebToApk.enterPip();
}
};ملاحظات: مع تفعيل PiP، الضغط على الرئيسية يدخل النافذة العائمة من تلقاء نفسه بالفعل؛ وهذه الطريقة لزر صريح فقط. تُرجع false في بناء بلا مفتاح PiP، لأن علامة manifest التي تحتاجها مفقودة. حجم نافذة PiP يحدده Android. يمكن للتطبيقات المبنية بالذكاء الاصطناعي استخدام pip من @/lib/appmintNative.
isFullscreen الجسر (bridge)#
window.WebToApk.isFullscreen(): Boolean
يتيح للصفحة إخفاء شريط الحالة (الساعة/البطارية) وشريط التنقل بنفسها - مثلًا لعبة تدخل شاشة اللعب: WebToApk.setFullscreen(true) // إخفاء أشرطة النظام WebToApk.setFullscreen(false) // إعادتها WebToApk.toggleFullscreen() WebToApk.isFullscreen() يُحفظ الاختيار عبر مرات التشغيل. لا يفعل شيئًا في التطبيقات التي قفلها المنشئ بالفعل على ملء الشاشة/الكشك - لا يوجد ما يُعاد إليه هناك. عنصر القائمة الجانبية "ملء الشاشة" هو المعادل للمستخدمين النهائيين ويتحكم فيه خيار المنشئ enableFullscreenToggle؛ وهذا الجسر متاح دائمًا لصفحة التطبيق نفسه.
موصوفة في مجموعتها، جسر ملء الشاشة، لا بمفردها.
مثال
يخبرك هل شريطا الحالة والتنقل في Android مخفيان الآن.
تُرجع: true / false، بشكل متزامن. المتطلبات: لا شيء.
function barsHidden() {
if (window.WebToApk && typeof window.WebToApk.isFullscreen === 'function') {
return window.WebToApk.isFullscreen();
}
return false; // in a browser
}
if (barsHidden()) {
document.getElementById('fs-btn').textContent = 'Exit fullscreen';
}صمّم الصفحة للاختيار المحفوظ عند البدء، لأنه يبقى بعد إعادة التشغيل:
document.addEventListener('DOMContentLoaded', function () {
var hidden = !!(window.WebToApk && typeof window.WebToApk.isFullscreen === 'function' &&
window.WebToApk.isFullscreen());
document.documentElement.classList.toggle('bars-hidden', hidden);
// CSS: .bars-hidden header { padding-top: env(safe-area-inset-top); }
});أضف زر "إظهار الأشرطة" عندما بُني التطبيق بملء الشاشة ولا يمكن للأشرطة العودة:
function showBars() {
var W = window.WebToApk;
if (!(W && typeof W.isFullscreen === 'function')) return;
W.setFullscreen(false);
setTimeout(function () { // the change is applied on the UI thread
if (W.isFullscreen()) {
document.getElementById('bars-btn').hidden = true;
}
}, 100);
}ملاحظات: يُرجع true عندما بنى المنشئ التطبيق مع ملء الشاشة أو وضع الكشك الغامر، أو عندما استدعت الصفحة setFullscreen(true) / toggleFullscreen(). في الحالة الأولى لا يستطيع setFullscreen(false) إعادة الأشرطة.
isSecureScreen الجسر (bridge)#
window.WebToApk.isSecureScreen(): Boolean
WebToApk.setSecureScreen(true) // منع لقطات الشاشة في هذه الصفحة WebToApk.setSecureScreen(false) // إلغاء المنع مبكرًا WebToApk.isSecureScreen() // -> boolean الحماية تخص الصفحة التي طلبتها. وتُلغى لحظة ينتقل التطبيق إلى أي مكان آخر - مستند جديد أو مسار pushState أو مسار #hash - فلا تترك شاشة محمية بقية التطبيق مقفلة، والصفحة التي تريد الحماية بعد إعادة التحميل تطلبها من جديد. ما تفعله: تتوقف لقطات الشاشة وتسجيل الشاشة والبث والصورة المصغرة في شاشة التطبيقات الأخيرة طوال تفعيلها. ما لا تستطيعه: منع كاميرا موجّهة إلى الشاشة. لا شيء في Android يستطيع، ولن يدّعي أي جسر هنا غير ذلك.
موصوفة في مجموعتها، حماية التقاط الشاشة، لا بمفردها.
مثال
يخبرك هل حماية لقطات الشاشة (setSecureScreen) مفعّلة الآن.
تُرجع: قيمة منطقية فورًا. المتطلبات: لا شيء.
function updateLockIcon() {
var on = !!window.WebToApk &&
typeof window.WebToApk.isSecureScreen === 'function' &&
window.WebToApk.isSecureScreen();
document.getElementById('shield').hidden = !on;
}تحقق قبل عرض رقم بطاقة، وفعّل الحماية أولًا إن لم تطلبها هذه الصفحة بعد:
function revealCardNumber(full) {
var W = window.WebToApk;
if (W && typeof W.isSecureScreen === 'function' && !W.isSecureScreen()) {
W.setSecureScreen(true); // the new state is committed when this returns
}
document.getElementById('card-number').textContent = full;
}مفتاح "إخفاء من لقطات الشاشة" يبدأ من الحالة الفعلية ويقلبها:
var toggle = document.getElementById('privacy-toggle');
var W = window.WebToApk;
if (!W || typeof W.isSecureScreen !== 'function') {
toggle.hidden = true;
} else {
toggle.checked = W.isSecureScreen();
toggle.addEventListener('change', function () {
toggle.checked = W.setSecureScreen(!W.isSecureScreen());
});
}ملاحظات: يعود إلى false من تلقاء نفسه عندما ينتقل التطبيق إلى صفحة أو مسار آخر، لأن الحماية تخص الصفحة التي طلبتها.
setFullscreen الجسر (bridge)#
window.WebToApk.setFullscreen(enabled: Boolean)
يتيح للصفحة إخفاء شريط الحالة (الساعة/البطارية) وشريط التنقل بنفسها - مثلًا لعبة تدخل شاشة اللعب: WebToApk.setFullscreen(true) // إخفاء أشرطة النظام WebToApk.setFullscreen(false) // إعادتها WebToApk.toggleFullscreen() WebToApk.isFullscreen() يُحفظ الاختيار عبر مرات التشغيل. لا يفعل شيئًا في التطبيقات التي قفلها المنشئ بالفعل على ملء الشاشة/الكشك - لا يوجد ما يُعاد إليه هناك. عنصر القائمة الجانبية "ملء الشاشة" هو المعادل للمستخدمين النهائيين ويتحكم فيه خيار المنشئ enableFullscreenToggle؛ وهذا الجسر متاح دائمًا لصفحة التطبيق نفسه.
موصوفة في مجموعتها، جسر ملء الشاشة، لا بمفردها.
مثال
يُخفي (true) أو يُظهر (false) شريط حالة Android وشريط التنقل، مثلًا عندما تدخل لعبة شاشة اللعب.
تُرجع: لا شيء. المتطلبات: لا شيء - متاحة دائمًا لصفحتك. يُحفظ الاختيار عبر مرات التشغيل.
function enterPlayScreen() {
if (window.WebToApk && typeof window.WebToApk.setFullscreen === 'function') {
window.WebToApk.setFullscreen(true); // hide clock/battery and the nav bar
}
}
function leavePlayScreen() {
if (window.WebToApk && window.WebToApk.setFullscreen) {
window.WebToApk.setFullscreen(false); // bring the bars back
}
}أبقِ محتواك بعيدًا عن أسفل ثقب الكاميرا عندما تكون الأشرطة مخفية:
document.body.style.paddingTop = 'env(safe-area-inset-top)';
document.body.style.paddingBottom = 'env(safe-area-inset-bottom)';أخفِ الأشرطة أثناء تشغيل الفيديو وأعدها عند إيقافه مؤقتًا أو انتهائه:
var video = document.getElementById('movie');
function hideBars(hidden) {
if (window.WebToApk && typeof window.WebToApk.setFullscreen === 'function') {
window.WebToApk.setFullscreen(hidden);
}
}
video.addEventListener('play', function () { hideBars(true); });
video.addEventListener('pause', function () { hideBars(false); });
video.addEventListener('ended', function () { hideBars(false); });ملاحظات: لا يفعل شيئًا في تطبيق بُني مع تفعيل ملء الشاشة (أو وضع الكشك الغامر) في الخطوة 3 (التكامل) - فالمنشئ قفل ذلك الاختيار. يُخفي فقط أشرطة Android؛ أما الشريط العلوي للتطبيق نفسه (الذي فيه زر القائمة الجانبية) فهو مفتاح إظهار الشريط العلوي. عند تفعيله، يضيف الغلاف viewport-fit=cover إلى وسم viewport لديك لتتمدد الصفحة على كامل الشاشة. راجع toggleFullscreen وisFullscreen. يمكن للتطبيقات المبنية بالذكاء الاصطناعي استخدام fullscreen من @/lib/appmintNative.
setSecureScreen الجسر (bridge)#
window.WebToApk.setSecureScreen(enabled: Boolean): Boolean
يضبط الحماية للصفحة الحالية ويُرجع الحالة السارية الآن. تُطبَّق علامة النافذة نفسها على خيط الواجهة، لكن الحالة المُرجَعة تكون قد ثُبّتت بالفعل، فيمكن للصفحة استدعاء هذا وكشف محتواها الحساس فورًا دون انتظار ردّ.
مثال
يمنع لقطات الشاشة وتسجيل الشاشة والبث ومعاينة شاشة التطبيقات الأخيرة بينما تعرض الصفحة الحالية شيئًا خاصًا.
تُرجع: قيمة منطقية فورًا - الحالة السارية الآن (القيمة التي مرّرتها). يمكنك كشف المحتوى الخاص مباشرة بعد الاستدعاء. المتطلبات: لا شيء.
function showStatement() {
if (window.WebToApk && typeof window.WebToApk.setSecureScreen === 'function') {
window.WebToApk.setSecureScreen(true);
}
render(statementView);
}حرّرها بنفسك فقط عندما تخفي المحتوى الخاص دون انتقال (تُغلق نافذة، أو يتبدل تبويب داخل صفحة واحدة):
function closeCardDetails() {
hide(cardDetailsModal);
if (window.WebToApk && typeof window.WebToApk.setSecureScreen === 'function') {
window.WebToApk.setSecureScreen(false);
}
}اعرض رمز استرداد لمرة واحدة فقط بعد حظر الالتقاط، لأن الاستدعاء يرد بالحالة السارية:
function revealRecoveryCode(code) {
var W = window.WebToApk;
if (!(W && typeof W.setSecureScreen === 'function')) {
alert('Open the app to see your recovery code.');
return;
}
if (W.setSecureScreen(true)) {
document.getElementById('recovery-code').textContent = code;
}
}ملاحظات: الحماية تخص الصفحة التي طلبتها. وتُلغى بمجرد انتقال التطبيق إلى أي مكان آخر - صفحة جديدة أو مسار pushState أو مسار #hash - فلا شيء يلزم تنظيفه عند الخروج، وبعد إعادة التحميل يجب أن تطلبها الصفحة من جديد. لا تعيد تطبيقها بمؤقّت: يجب أن تكون العلامة مفعّلة أصلًا حين يضغط المستخدم أزرار لقطة الشاشة. لا شيء يستطيع منع كاميرا موجّهة إلى الشاشة.
setStatusBarColor الجسر (bridge)#
window.WebToApk.setStatusBarColor(color: String, style: String): Boolean
يطلي شريطي الحالة والتنقل بـ [color] ويختار لون الأيقونات: [style] 'light' تعني أيقونات فاتحة على شريط داكن، و'dark' العكس، و'' يترك السطوع يقرر. [color] هو `#RGB` أو `#RGBA` أو `#RRGGBB` أو `#AARRGGBB` (الشفافية أولًا - وترتيب CSS `#RRGGBBAA` يُقرأ أيضًا بالشفافية أولًا) أو اسم لون أساسي ('black'، 'navy'…)؛ ولا تُقرأ `rgb()`/`hsl()`. يُرجع false عندما لا يُحلَّل اللون.
مثال
يطلي شريط حالة Android بلون ويختار أيقونات فاتحة أو داكنة عليه.
تُرجع: true، أو false عندما يتعذّر تحليل اللون (بشكل متزامن). المتطلبات: لا شيء.
style هو 'light' (أيقونات فاتحة، لشريط داكن) أو 'dark' (أيقونات داكنة، لشريط فاتح) أو '' (يختار الغلاف حسب سطوع اللون):
function paintBar(color, style) {
if (window.WebToApk && typeof window.WebToApk.setStatusBarColor === 'function') {
return window.WebToApk.setStatusBarColor(color, style);
}
return false; // in a browser
}
paintBar('#0B0F1A', 'light'); // dark bar, light icons
paintBar('#FFFFFF', 'dark'); // white bar, dark icons
paintBar('#0E7C86', ''); // icons chosen automaticallyطابق الشريط مع كل شاشة:
function showScreen(name) {
var colors = { home: '#0B0F1A', settings: '#FFFFFF' };
paintBar(colors[name] || '#0B0F1A', name === 'settings' ? 'dark' : 'light');
}اتبع السمة الفاتحة أو الداكنة للهاتف، بما في ذلك تبديلها أثناء فتح التطبيق:
var darkTheme = window.matchMedia('(prefers-color-scheme: dark)');
function matchTheme() {
if (!(window.WebToApk && typeof window.WebToApk.setStatusBarColor === 'function')) return;
if (darkTheme.matches) {
window.WebToApk.setStatusBarColor('#121212', 'light');
} else {
window.WebToApk.setStatusBarColor('#F5F5F5', 'dark');
}
}
matchTheme();
darkTheme.addEventListener('change', matchTheme);ملاحظات: الألوان سلاسل ألوان Android: #RRGGBB أو #AARRGGBB (وأسماء مثل red). صيغ CSS مثل rgb(...) أو #RGB تُرجع false. يعمل أيضًا على Android 15+، حيث لا تستطيع إضافة StatusBar من Capacitor طلاء الشريط. بينما تكون الأشرطة مخفية (ملء الشاشة) يُحتفظ باللون لعودتها. يمكن للتطبيقات المبنية بالذكاء الاصطناعي استخدام setStatusBar من @/lib/appmintNative.
splashHold الجسر (bridge)#
window.WebToApk.splashHold()
يُبقي شاشة بداية التطبيق المميّزة ظاهرة حتى يُستدعى [splashReady]. افتراضيًا تختفي شاشة البداية بمجرد أن يكون لجسم الصفحة عناصر مرسومة، وهذا يعني لتطبيق يرسم هيكلًا ثم يجلب شاشته الأولى "شاشة البداية ثم هيكل". التطبيق الذي يفضّل كشف شاشة أولى مكتملة يستدعي هذا عند الاستيراد و[splashReady] عندما تظهر تلك الشاشة. محدود بالاحتياط نفسه البالغ 6 ثوانٍ لفحص الرسم، لذا الصفحة التي لا تُبلغ عن الجاهزية أبدًا تفتح مع ذلك.
مثال
يُبقي شاشة بداية التطبيق ظاهرة حتى تستدعي splashReady() - فيرى المستخدم شاشتك الأولى المكتملة، لا "شاشة البداية ثم هيكل تحميل".
يعيد: لا شيء. يتطلب: لا شيء.
استدعِه في أبكر وقت ممكن (أعلى أول سكربت لديك)، ثم استدعِ splashReady() بعد رسم الشاشة الأولى:
if (window.WebToApk && typeof window.WebToApk.splashHold === 'function') {
window.WebToApk.splashHold();
}
loadFirstScreen() // your own async start-up (fetch data, render)
.catch(function (err) { showError(err); })
.then(function () {
if (window.WebToApk && window.WebToApk.splashReady) window.WebToApk.splashReady();
});أبقِ شاشة البداية حتى تُحمَّل الصورة الرئيسية للشاشة الأولى، ليفتح التطبيق على صورة مكتملة:
if (window.WebToApk && typeof window.WebToApk.splashHold === 'function') {
window.WebToApk.splashHold();
}
function releaseSplash() {
if (window.WebToApk && window.WebToApk.splashReady) window.WebToApk.splashReady();
}
var hero = document.getElementById('hero');
if (hero.complete) {
releaseSplash();
} else {
hero.addEventListener('load', releaseSplash);
hero.addEventListener('error', releaseSplash); // a broken image must not keep the splash up
}أبقِ الشاشة فقط عندما تحتاج الشاشة الأولى إلى بيانات، ودع الشاشة التي تُرسم فورًا تفتح بشكل عادي:
var signedIn = !!localStorage.getItem('session');
if (signedIn && window.WebToApk && typeof window.WebToApk.splashHold === 'function') {
window.WebToApk.splashHold(); // the dashboard needs its data before it looks right
}
if (signedIn) {
loadDashboard().finally(function () {
if (window.WebToApk && window.WebToApk.splashReady) window.WebToApk.splashReady();
});
} else {
showLoginScreen(); // paints at once; the splash hides by itself
}ملاحظات: بدون splashHold() تختفي شاشة البداية بمجرد أن يكون لجسم الصفحة عناصر مرئية. شاشة البداية المحتجزة تختفي بنفسها أيضًا بعد بضع ثوانٍ (الاحتياط نفسه لفحص الرسم العادي)، لذا الصفحة التي لا تستدعي splashReady() أبدًا تفتح مع ذلك. استدعِ splashReady() في مسار الخطأ أيضًا. يظل الحد الأدنى لمدة شاشة البداية الذي حدده المنشئ ساريًا. يمكن للتطبيقات المبنية بالذكاء الاصطناعي استخدام splash من @/lib/appmintNative.
splashReady الجسر (bridge)#
window.WebToApk.splashReady()
الشاشة الأولى ظاهرة - أخفِ شاشة البداية الآن (مع مراعاة الحد الأدنى لمدة شاشة البداية الذي حدده المنشئ). آمنة للتكرار؛ وغير ضارة عندما لم يكن هناك شيء محتجز.
مثال
يُخبر الغلاف بأن شاشتك الأولى جاهزة، فتختفي شاشة البداية الآن.
تُرجع: لا شيء. المتطلبات: لا شيء. آمنة للاستدعاء أكثر من مرة، وغير ضارة عندما لم يكن هناك شيء ممسوك.
يقترن مع splashHold():
if (window.WebToApk && window.WebToApk.splashHold) window.WebToApk.splashHold();
async function start() {
try {
var res = await fetch('/api/today');
renderToday(await res.json());
} catch (e) {
renderOfflineMessage();
} finally {
if (window.WebToApk && typeof window.WebToApk.splashReady === 'function') {
window.WebToApk.splashReady(); // hide the splash in every case
}
}
}
start();اكشف الشاشة فقط بعد أن يرسم المتصفح ما عرضته للتو (إطاران من الرسوم المتحركة):
renderApp(document.getElementById('root'));
requestAnimationFrame(function () {
requestAnimationFrame(function () {
if (window.WebToApk && typeof window.WebToApk.splashReady === 'function') {
window.WebToApk.splashReady();
}
});
});انتظر عدة مهام بدء تشغيل، وأخفِ شاشة البداية حتى لو فشلت إحداها:
if (window.WebToApk && window.WebToApk.splashHold) window.WebToApk.splashHold();
Promise.allSettled([
loadProfile(), // your own start-up requests
loadFeed(),
document.fonts.ready // no flash of the wrong font
]).then(function (results) {
results.forEach(function (r) { if (r.status === 'rejected') console.warn(r.reason); });
if (window.WebToApk && typeof window.WebToApk.splashReady === 'function') {
window.WebToApk.splashReady();
}
});ملاحظات: يظل الحد الأدنى لمدة شاشة البداية الذي حدده المنشئ محترمًا. إذا لم تستدعِ splashHold() قط، تختفي شاشة البداية من تلقاء نفسها عند رسم الصفحة، ولا يفعل splashReady() شيئًا إضافيًا.
toggleFullscreen الجسر (bridge)#
window.WebToApk.toggleFullscreen()
يتيح للصفحة إخفاء شريط الحالة (الساعة/البطارية) وشريط التنقل بنفسها - مثلًا لعبة تدخل شاشة اللعب: WebToApk.setFullscreen(true) // إخفاء أشرطة النظام WebToApk.setFullscreen(false) // إعادتها WebToApk.toggleFullscreen() WebToApk.isFullscreen() يُحفظ الاختيار عبر مرات التشغيل. لا يفعل شيئًا في التطبيقات التي قفلها المنشئ بالفعل على ملء الشاشة/الكشك - لا يوجد ما يُعاد إليه هناك. عنصر القائمة الجانبية "ملء الشاشة" هو المعادل للمستخدمين النهائيين ويتحكم فيه خيار المنشئ enableFullscreenToggle؛ وهذا الجسر متاح دائمًا لصفحة التطبيق نفسه.
موصوفة في مجموعتها، جسر ملء الشاشة، لا بمفردها.
مثال
يبدّل شريطي الحالة والتنقل في Android بين الإخفاء والإظهار.
تُرجع: لا شيء. المتطلبات: لا شيء. تُحفظ الحالة الجديدة عبر مرات التشغيل.
زر "ملء الشاشة" يحدّث تسميته أيضًا:
var btn = document.getElementById('fs-btn');
if (window.WebToApk && typeof window.WebToApk.toggleFullscreen === 'function') {
btn.onclick = function () {
window.WebToApk.toggleFullscreen();
// The change is applied on the UI thread; read the state a moment later.
setTimeout(function () {
btn.textContent = window.WebToApk.isFullscreen() ? 'Exit fullscreen' : 'Fullscreen';
}, 100);
};
} else {
btn.hidden = true; // in a browser
}انقر نقرًا مزدوجًا على صورة أو عرض قراءة لإخفاء الأشرطة أو إظهارها:
var viewer = document.getElementById('photo-viewer');
viewer.addEventListener('dblclick', function () {
if (window.WebToApk && typeof window.WebToApk.toggleFullscreen === 'function') {
window.WebToApk.toggleFullscreen();
}
});بدّل بمفتاح F على لوحة مفاتيح فعلية، ولكن ليس بينما يكتب المستخدم في حقل:
document.addEventListener('keydown', function (e) {
if (e.key !== 'f' || e.target.closest('input, textarea, [contenteditable]')) return;
if (window.WebToApk && typeof window.WebToApk.toggleFullscreen === 'function') {
e.preventDefault();
window.WebToApk.toggleFullscreen();
}
});ملاحظات: لا يفعل شيئًا في تطبيق بُني مع تفعيل ملء الشاشة أو وضع الكشك الغامر (تبقى الأشرطة مخفية). عنصر القائمة الجانبية "ملء الشاشة" للمستخدمين النهائيين مفتاح بناء منفصل (زر ملء الشاشة في الخطوة 3، تحت خيارات العرض)؛ وهذه الطريقة في الجسر تعمل بدونه.