ساخت APK رایگان

API پل جاوااسکریپت

پنجره

تمام‌صفحه، تصویر در تصویر، رنگ نوارهای سیستم، مسدودسازی اسکرین‌شات، اینکه ساخت محافظت کپی دارد یا نه (AppMint.copyProtection)، صفحه‌ی اسپلش و بستن یک پنجره.

AppMint.copyProtection کمک‌کننده#

AppMint.copyProtection

نمونه

true وقتی اپلیکیشن با محافظت کپی روشن ساخته شده؛ در غیر این صورت وجود ندارد (undefined). فقط‌خواندنی - صفحه نمی‌تواند محافظت را روشن یا خاموش کند، فقط می‌تواند بپرسد روشن است یا نه.

مقدار بازگشتی: true، یا undefined وقتی محافظت خاموش است (و در مرورگر). نیازمندی: محافظت کپی هنگام ساخت در مرحله 3 (یکپارچه‌سازی)، زیر گزینه‌های نمایش، روشن باشد. پیش‌فرض خاموش.

با روشن بودن محافظت، متن اپلیکیشن را نمی‌توان انتخاب، کپی یا برش داد؛ کپی / برش، رویداد contextmenu و Ctrl/Cmd + C، X و A بیرون از فیلدهای قابل‌ویرایش لغو می‌شوند؛ و منوی فشار طولانی ظاهر نمی‌شود. ورودی‌ها، textareaها، selectها و ناحیه‌های 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).

navigator.wakeLock استاندارد وب#

navigator.wakeLock.request('screen')

نمونه

API استاندارد Screen Wake Lock: صفحه را هنگام نمایش یک دستور غذا، نقشه، کارت پرواز یا تایمر ورزش از کم‌نور شدن نگه می‌دارد.

مقدار بازگشتی: یک Promise از یک WakeLockSentinel {type:'screen', released, release(), onrelease}. وقتی صفحه قابل‌مشاهده نیست با NotAllowedError رد می‌شود. نیازمندی: چیزی برای روشن کردن نیست، بدون مجوز.

let wakeLock = null;

async function startCooking() {
  try {
    wakeLock = await navigator.wakeLock.request('screen');
    wakeLock.addEventListener('release', () => { wakeLock = null; });
  } catch (e) {
    console.log('Screen may dim:', e.name);
  }
}

async function stopCooking() {
  if (wakeLock) await wakeLock.release();
}

// The lock is dropped when the app goes to the background — take it again on return.
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'visible' && cookingModeOn && !wakeLock) startCooking();
});

صفحه را فقط تا وقتی تایمر ورزش در حال اجراست روشن نگه دارید و وقتی تمام شد رها کنید:

let lock = null;

async function startTimer(seconds) {
  if ('wakeLock' in navigator) {
    try { lock = await navigator.wakeLock.request('screen'); } catch (e) { lock = null; }
  }
  runCountdown(seconds, async () => {        // your timer; the callback runs at 0
    if (lock && !lock.released) await lock.release();
    lock = null;
    showDone();
  });
}

یک کلید «روشن نگه داشتن صفحه» که وقتی قفل از دست می‌رود (مثلاً اپلیکیشن به پس‌زمینه رفت) خودش تیک را برمی‌دارد:

const box = document.getElementById('keep-on');
let sentinel = null;

box.hidden = !('wakeLock' in navigator);
box.addEventListener('change', async () => {
  if (box.checked) {
    try {
      sentinel = await navigator.wakeLock.request('screen');
      sentinel.onrelease = () => { box.checked = false; sentinel = null; };
    } catch (e) {
      box.checked = false;                     // NotAllowedError: page not visible
    }
  } else if (sentinel) {
    await sentinel.release();
  }
});

نکته‌ها: طبق مشخصات، هر قفل وقتی صفحه پنهان می‌شود (اپلیکیشن به پس‌زمینه می‌رود یا مسیر عوض می‌کند) رها می‌شود؛ رویداد release هر sentinel فعال می‌شود. ممکن است چند sentinel همزمان نگه داشته شود - صفحه تا رها شدن آخرین روشن می‌ماند. اپلیکیشن‌های ساخته‌شده با هوش مصنوعی از keepAwake(true/false) در @/lib/appmintNative استفاده می‌کنند. رویداد پشت آن: appmint:wakelock-lost.

screen.orientation استاندارد وب#

screen.orientation.lock(type) / unlock()

نمونه

قفل استاندارد جهت صفحه که WebView ساده آن را رد می‌کند: اپلیکیشن را برای ویدیو یا بازی افقی می‌کند و دوباره برمی‌گرداند.

مقدار بازگشتی: lock(type) → یک Promise که وقتی جهت درخواست شد حل می‌شود؛ برای نوع ناشناخته با TypeError و در Android TV با NotSupportedError رد می‌شود. 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 پل#

window.WebToApk.__lockOrientation(type: String): String

screen.orientation.lock(type): «ok»، «type» برای رشته‌ای که OrientationLockType نیست، یا «unsupported» (Android TV همیشه افقی است).

نمونه

انتقال داخلی پشت screen.orientation.lock(type). صفحه‌ها از API استاندارد استفاده می‌کنند؛ هرگز مستقیم آن را فراخوانی نکنید - متدهای __ ممکن است بدون اطلاع تغییر کنند.

مقدار بازگشتی: 'ok'، 'type' برای رشته‌ای که نوع قفل جهت نیست، یا 'unsupported' (Android TV). نیازمندی: چیزی برای روشن کردن نیست.

از API عمومی استفاده کنید:

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 پل#

window.WebToApk.__unlockOrientation()

screen.orientation.unlock(): بازگشت به جهتی که سازنده با آن ساخته است.

نمونه

انتقال داخلی پشت screen.orientation.unlock(). صفحه‌ها از API استاندارد استفاده می‌کنند؛ هرگز مستقیم آن را فراخوانی نکنید - متدهای __ ممکن است بدون اطلاع تغییر کنند.

مقدار بازگشتی: چیزی؛ اپلیکیشن به جهتی که هنگام ساخت انتخاب شده برمی‌گردد. نیازمندی: چیزی برای روشن کردن نیست.

از API عمومی استفاده کنید:

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 پل#

window.WebToApk.__wakeLock(docId: String, held: Boolean): Boolean

Screen Wake Lock: [held] برابر true صفحه را روشن نگه می‌دارد تا وقتی سند [docId] یک sentinel دارد. اگر قفل گرفته نشد false برمی‌گرداند.

نمونه

انتقال داخلی پشت navigator.wakeLock.request('screen') و WakeLockSentinel.release(). صفحه‌ها از API استاندارد استفاده می‌کنند؛ هرگز این را مستقیم صدا نزنید - متدهای __ ممکن است بدون اطلاع تغییر کنند.

مقدار بازگشتی: true وقتی پرچم روشن‌ماندن صفحه برای آن سند اعمال شد. نیازمندی: چیزی برای روشن کردن نیست.

از API عمومی استفاده کنید:

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 را فعال می‌کند که sentinelها را آزاد می‌کند (رویداد release آن‌ها فعال می‌شود).

closeWindow پل#

window.WebToApk.closeWindow()

از پوشاننده‌ی promise استفاده کنید: 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، توضیح داده می‌شود، نه جداگانه.

نمونه

صفحه‌ی اصلی اپلیکیشن را می‌بندد (مثل زدن Back در آخرین صفحه). صفحه‌ها معمولاً 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 پل#

window.WebToApk.enterPip(): Boolean

کل اپلیکیشن را همین حالا در یک پنجره‌ی شناور تصویر در تصویر جمع می‌کند - ویدیو یا تماسی که کاربر می‌خواهد هنگام رفتن به جای دیگر ببیند. Android 8+ و فقط وقتی ساخت PiP را فعال کرده باشد (پرچم مانیفستی که لازم دارد)؛ برمی‌گرداند که پنجره باز شد یا نه. با فعال بودن 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، زدن Home از قبل خودش وارد پنجره‌ی شناور می‌شود؛ این متد فقط برای دکمه‌ی صریح است. در ساختی که کلید PiP را ندارد false برمی‌گرداند، چون پرچم مانیفستی که لازم دارد وجود ندارد. اندازه‌ی پنجره‌ی PiP را Android انتخاب می‌کند. اپلیکیشن‌های ساخته‌شده با هوش مصنوعی از pip در @/lib/appmintNative.

isFullscreen پل#

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

نکته‌ها: وقتی سازنده اپلیکیشن را با تمام‌صفحه یا حالت کیوسک فراگیر ساخته باشد، یا وقتی صفحه setFullscreen(true) / toggleFullscreen() را صدا زده باشد true برمی‌گرداند. در حالت اول setFullscreen(false) نمی‌تواند نوارها را برگرداند.

isSecureScreen پل#

window.WebToApk.isSecureScreen(): Boolean

WebToApk.setSecureScreen(true) // جلوی اسکرین‌شات را در همین صفحه بگیرید WebToApk.setSecureScreen(false) // زودتر رهایش کنید WebToApk.isSecureScreen() // -> boolean محافظت متعلق به صفحه‌ای است که آن را خواسته. به‌محض اینکه اپلیکیشن به جای دیگری برود - سند جدید، مسیر pushState، مسیر #hash - رها می‌شود، پس صفحه‌ی محافظت‌شده نمی‌تواند بقیه‌ی اپلیکیشن را قفل‌شده بگذارد، و صفحه‌ای که بعد از بارگذاری مجدد محافظت را می‌خواهد دوباره درخواست می‌کند. کارش: تا وقتی روشن است اسکرین‌شات، ضبط صفحه، پخش به دستگاه دیگر و تصویر بندانگشتی صفحه‌ی اخیرها متوقف می‌شوند. کاری که نمی‌تواند: جلوی دوربینی که رو به صفحه گرفته شده را بگیرد. هیچ چیز در Android نمی‌تواند، و هیچ پلی اینجا وانمود نمی‌کند که می‌تواند.

با گروهش، محافظت در برابر ضبط صفحه، توضیح داده می‌شود، نه جداگانه.

نمونه

به شما می‌گوید محافظت از اسکرین‌شات (setSecureScreen) همین حالا روشن است یا نه.

مقدار بازگشتی: یک boolean، بلافاصله. نیازمندی: هیچ.

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 پل#

window.WebToApk.setFullscreen(enabled: Boolean)

به صفحه اجازه می‌دهد خودش نوار وضعیت (ساعت/باتری) و نوار ناوبری را پنهان کند - مثلاً بازی که وارد صفحه‌ی بازی می‌شود: WebToApk.setFullscreen(true) // نوارهای سیستم را پنهان کنید WebToApk.setFullscreen(false) // برشان گردانید WebToApk.toggleFullscreen() WebToApk.isFullscreen() انتخاب بین اجراها به خاطر سپرده می‌شود. در اپلیکیشن‌هایی که سازنده از قبل روی تمام‌صفحه/کیوسک قفل کرده بی‌اثر است - چیزی برای بازگرداندن نیست. گزینه‌ی «تمام‌صفحه» در منوی کناری معادل آن برای کاربران نهایی است و با گزینه‌ی enableFullscreenToggle سازنده کنترل می‌شود؛ این پل همیشه برای صفحه‌ی خود اپلیکیشن در دسترس است.

با گروهش، پل تمام‌صفحه، توضیح داده می‌شود، نه جداگانه.

نمونه

نوار وضعیت و نوار ناوبری Android را پنهان (true) یا نمایان (false) می‌کند، مثلاً وقتی بازی وارد صفحه‌ی بازی می‌شود.

مقدار بازگشتی: چیزی. نیازمندی: هیچ - همیشه برای صفحه‌ی شما در دسترس است. انتخاب بین اجراها به خاطر سپرده می‌شود.

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 پل#

window.WebToApk.setSecureScreen(enabled: Boolean): Boolean

محافظت را برای صفحه‌ی فعلی تنظیم می‌کند و وضعیتی را که اکنون برقرار است برمی‌گرداند. خود پرچم پنجره روی رشته‌ی رابط کاربری اعمال می‌شود، اما وضعیتی که برمی‌گرداند از قبل ثبت شده است، پس صفحه می‌تواند این را صدا بزند و بلافاصله بدون انتظار برای callback محتوای حساسش را نمایان کند.

نمونه

وقتی صفحه‌ی فعلی چیزی خصوصی نشان می‌دهد، جلوی اسکرین‌شات، ضبط صفحه، پخش به دستگاه دیگر و پیش‌نمایش صفحه‌ی اخیرها را می‌گیرد.

مقدار بازگشتی: یک 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 پل#

window.WebToApk.setStatusBarColor(color: String, style: String): Boolean

نوارهای وضعیت و ناوبری را با [color] رنگ می‌کند و رنگ آیکون را انتخاب می‌کند: [style] 'light' یعنی آیکون روشن روی نوار تیره، 'dark' برعکس، '' روشنایی تعیین می‌کند. [color] برابر `#RGB`، `#RGBA`، `#RRGGBB`، `#AARRGGBB` (آلفا اول - ترتیب `#RRGGBBAA` در CSS هم آلفا-اول خوانده می‌شود) یا نام رنگ ساده ('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 پل#

window.WebToApk.splashHold()

اسپلش برندشده‌ی راه‌اندازی را تا وقتی [splashReady] صدا زده شود نگه می‌دارد. به‌طور پیش‌فرض اسپلش به‌محض اینکه بدنه فرزندان چیده‌شده داشته باشد پنهان می‌شود، که برای اپلیکیشنی که اسکلت رسم می‌کند و بعد صفحه‌ی اولش را می‌گیرد یعنی «اسپلش، بعد یک اسکلت». اپلیکیشنی که ترجیح می‌دهد صفحه‌ی اول تمام‌شده را نشان دهد این را هنگام import و [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 پل#

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 پل#

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، زیر گزینه‌های نمایش)؛ این متد پل بدون آن هم کار می‌کند.