API پل جاوااسکریپت
افزونههای Capacitor
افزونههای Capacitor که اپلیکیشن میزبانی میکند. یک صفحهٔ دستنویس از طریق window.Capacitor.Plugins.<Name> به آنها میرسد؛ یک اپلیکیشن ساختهشده با هوش مصنوعی از بستهٔ کمکی @/lib/appmintNative که هر مثال نام میبرد استفاده میکند.
Capacitor.ActionSheet Capacitor#
Capacitor.Plugins.ActionSheet — showActions({ title, message, options })
نمونه
یک برگهٔ پایینی بومی با فهرستی از گزینهها نشان میدهد و میگوید کدام لمس شد (@capacitor/action-sheet 8.1.1).
خروجی: Promise { index, canceled } - index گزینهٔ لمسشده است؛ وقتی برگه رد میشود canceled برابر true است و index خارج از فهرست است (-1). نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی این افزونه را دارد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
هر گزینه { title, style? } است با style 'DEFAULT'، 'DESTRUCTIVE' یا 'CANCEL'.
var ActionSheet = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ActionSheet;
async function photoMenu() {
if (!ActionSheet) return;
var opts = [
{ title: 'Share', style: 'DEFAULT' },
{ title: 'Edit', style: 'DEFAULT' },
{ title: 'Delete', style: 'DESTRUCTIVE' }
];
var r = await ActionSheet.showActions({ title: 'Photo', message: 'Choose an action', options: opts });
if (r.canceled || r.index < 0 || r.index >= opts.length) return; // dismissed
if (opts[r.index].title === 'Delete') deletePhoto();
}در یک اپلیکیشن ساختهشده با هوش مصنوعی بستهٔ کمکی با شکل Capacitor هنگام رد کردن { index: -1 } برمیگرداند؛ شکل کوتاه actionSheet() برمیگرداند null:
import { ActionSheet, actionSheet } from '@/lib/appmintNative';
const { index } = await ActionSheet.showActions({
title: 'Photo',
options: [{ title: 'Share' }, { title: 'Delete', destructive: true }],
});
if (index === 1) deletePhoto();
const i = await actionSheet('Sort by', [{ title: 'Name' }, { title: 'Date' }]); // number | nullتأیید حذف که در مرورگر ساده هم کار میکند:
async function confirmDelete(name) {
const AS = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ActionSheet;
if (!AS) return window.confirm('Delete ' + name + '?');
const r = await AS.showActions({
title: 'Delete ' + name + '?',
options: [{ title: 'Delete', style: 'DESTRUCTIVE' }, { title: 'Keep it', style: 'CANCEL' }]
});
return !r.canceled && r.index === 0;
}نکتهها: همیشه حد اندیس را بررسی کنید - هرگز هیچ اندیسی را انتخاب واقعی فرض نکنید. شکل گزینهٔ بستهٔ کمکی { title, destructive? } است؛ destructive را به سبک 'DESTRUCTIVE' افزونه نگاشت میکند.
Capacitor.App Capacitor#
Capacitor.Plugins.App — getInfo(), getState(), exitApp(), minimizeApp(), addListener(...)
نمونه
هویت و چرخهٔ حیات اپلیکیشن: نام، شناسهٔ بسته، نسخه، اینکه اپلیکیشن جلوی صفحه است یا نه، و رویدادهای مکث/ازسرگیری (@capacitor/app 8.1.0).
مقدار بازگشتی: getInfo() ← { name, id, build, version }؛ getState() ← { isActive }؛ getLaunchUrl() ← { url } یا هیچ؛ getAppLanguage() ← { value }؛ exitApp() / minimizeApp() ← void. addListener() ← یک Promise از یک handle با remove()، مانند API خود Capacitor - await کنید یا .then() را زنجیر کنید؛ مقدار بازگشتی خودش هم remove() دارد. نیازها: چیزی برای روشن کردن نیست - هر اپلیکیشن افزونه را میزبانی میکند. window.Capacitor روی صفحههایی وجود دارد که خود اپلیکیشن سرو میکند (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و، در اپلیکیشن حالت وبسایت، روی سایت خودتان (دامنه و زیردامنههایش) - هرگز روی سایتهای دیگری که اپلیکیشن باز میکند. پشتیبانی را تشخیص دهید.
var App = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.App;
if (App) {
App.getInfo().then(function (i) {
document.getElementById('about').textContent = i.name + ' ' + i.version + ' (' + i.build + ')';
});
}مکث و ازسرگیری - وقتی کاربر میرود، یک پیشنویس ذخیره کنید و وقتی برمیگردد، تازهسازی کنید:
if (App) {
App.addListener('appStateChange', function (s) {
if (!s.isActive) saveDraft(); // went to the background
else refreshInbox(); // back in front
});
App.addListener('pause', function () { console.log('paused'); });
App.addListener('resume', function () { console.log('resumed'); });
}در یک اپلیکیشن ساختهشده با هوش مصنوعی:
import { App } from '@/lib/appmintNative';
const info = await App.getInfo(); // { name, id, build, version }
App.exitApp(); // closes the app on Androidنکتهها: رویداد backButton هرگز اجرا نمیشود: پوسته دکمهٔ برگشت را نگه میدارد (افزونه با disableBackButtonHandler اجرا میشود). برگشت را با AppMint.setBackHandler(fn) یا بستهٔ کمکی onBackGesture مدیریت کنید. برای پیوندهای عمیق از WebToApk.getLaunchUrl() / رویداد appmint:deep-link استفاده کنید (یا launchUrl() / onDeepLink() در اپلیکیشنهای ساختهشده با هوش مصنوعی). minimizeApp() فقط مخصوص اندروید است. هرگز دکمهٔ خروج را تنها راه ادامه قرار ندهید.
Capacitor.AppLauncher Capacitor#
Capacitor.Plugins.AppLauncher — canOpenUrl({ url }), openUrl({ url })
نمونه
اپلیکیشن دیگری را با پیوند باز میکند (whatsapp://send?text=…، tel:، geo:، یک پیوند https) و میپرسد آیا اپلیکیشنی میتواند آن را مدیریت کند (@capacitor/app-launcher 8.0.1).
خروجی: canOpenUrl() → Promise { value: boolean }. openUrl() → Promise { completed: boolean } (false وقتی هیچ اپلیکیشنی پیوند را نگرفت). نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی این افزونه را دارد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var AL = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppLauncher;
async function chatOnWhatsApp(text) {
if (!AL) return;
var url = 'whatsapp://send?text=' + encodeURIComponent(text);
var can = await AL.canOpenUrl({ url: url });
if (!can.value) { alert('WhatsApp is not installed'); return; }
var r = await AL.openUrl({ url: url });
if (!r.completed) alert('Could not open WhatsApp');
}در یک اپلیکیشن ساختهشده با هوش مصنوعی:
import { appLauncher } from '@/lib/appmintNative';
if (await appLauncher.canOpen('tel:+15551234567')) await appLauncher.open('tel:+15551234567');یک پیوند نقشه را بدون پرسیدن باز کنید:
async function openMap(query) {
const AL = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppLauncher;
if (!AL) { window.open('https://maps.google.com/?q=' + encodeURIComponent(query)); return; }
const r = await AL.openUrl({ url: 'geo:0,0?q=' + encodeURIComponent(query) });
if (!r.completed) alert('No maps app could open this');
}نکتهها: در Android 11 به بعد، یک اپلیکیشن فقط میتواند اپلیکیشنهای دیگری را «ببیند» که اعلام کرده است. اپلیکیشنهای ساختهشده پیوندهای https، geo، google.navigation، tel، mailto، sms، whatsapp، intent و upi را اعلام میکنند، بنابراین canOpenUrl برای طرحهای دیگر (مثلاً spotify:) حتی وقتی اپلیکیشن نصب است، false پاسخ میدهد. openUrl برای آنها همچنان کار میکند - آن را صدا بزنید و completed را بررسی کنید. در Android، canOpenUrl نام بسته را هم میپذیرد ('com.whatsapp')، با همان محدودیت دید.
Capacitor.AppUpdate Capacitor#
Capacitor.Plugins.AppUpdate — getAppUpdateInfo(), performImmediateUpdate(), startFlexibleUpdate(), completeFlexibleUpdate(), openAppStore()
نمونه
Google Play را برای نسخهٔ جدیدتر اپلیکیشن بررسی میکند و بهروزرسانی درونبرنامهای Play را شروع میکند. نسخهٔ همراهشده @capawesome/capacitor-app-update (template/plugins/app-update).
خروجی: getAppUpdateInfo() → { currentVersionName, currentVersionCode, availableVersionCode, updateAvailability, updatePriority, immediateUpdateAllowed, flexibleUpdateAllowed, clientVersionStalenessDays?, installStatus } (کدهای نسخه رشته هستند؛ updateAvailability 2 = یک بهروزرسانی موجود است). performImmediateUpdate() / startFlexibleUpdate() → { code }: 0 موفق، 1 لغوشده، 2 ناموفق، 3 در دسترس نیست، 4 مجاز نیست، 5 ابتدا getAppUpdateInfo() را صدا بزنید. openAppStore() → void. نیازمندی: چیزی برای روشنکردن لازم نیست؛ اپلیکیشن باید از Google Play نصب شده باشد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var AU = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppUpdate;
async function checkForUpdate() {
if (!AU) return;
try {
var info = await AU.getAppUpdateInfo(); // must come first
if (info.updateAvailability !== 2) return; // up to date
if (info.immediateUpdateAllowed) {
var r = await AU.performImmediateUpdate(); // Play's full-screen update
if (r.code === 1) console.log('user said not now');
} else {
await AU.openAppStore(); // the Play listing
}
} catch (e) {
console.log('Play update check failed:', e.message); // e.g. no Play services
}
}بهروزرسانی انعطافپذیر - در پسزمینه دانلود کنید، سپس وقتی کاربر موافقت کرد راهاندازی مجدد کنید:
async function flexibleUpdate() {
if (!AU) return;
var info = await AU.getAppUpdateInfo();
if (info.updateAvailability !== 2 || !info.flexibleUpdateAllowed) return;
await AU.addListener('onFlexibleUpdateStateChange', function (s) {
if (s.installStatus === 2) console.log(s.bytesDownloaded + ' / ' + s.totalBytesToDownload);
if (s.installStatus === 11) showRestartButton(); // 11 = DOWNLOADED
});
await AU.startFlexibleUpdate();
}
function restartNow() { if (AU) AU.completeFlexibleUpdate(); }در یک اپلیکیشن ساختهشده با هوش مصنوعی:
import { appUpdate } from '@/lib/appmintNative';
const info = await appUpdate.check(); // null on the web / without Play
if (info?.inPlace) await appUpdate.start(); // Android: immediate updateنکتهها: از updateAvailability === 2 بهعنوان تنها آزمون «بهروزرسانی موجود است» استفاده کنید. تابع check() در بستهٔ کمکی currentVersionName را با availableVersionCode مقایسه میکند که در اندروید هرگز برابر نیستند، پس updateAvailable آن در اندروید قابل اعتماد نیست - بهجای آن inPlace را بررسی کنید. start() حتی وقتی کاربر لغو کند، true برمیگرداند.
Capacitor.AppwrightDocScanner Capacitor#
Capacitor.Plugins.AppwrightDocScanner — scan({ pageLimit, pdf, quality }), isSupported()
نمونه
اسکنر سند Google ML Kit را باز میکند: کاربر از یک یا چند صفحه عکس میگیرد (یا آنها را وارد میکند)، لبهها پیدا و صاف میشوند و صفحهها بهصورت تصویر JPEG برمیگردند. افزونهٔ اختصاصی Appwright (AppwrightDocScannerPlugin.kt).
خروجی: scan() → Promise که همیشه حل میشود: { ok: true, pages: string[] (JPEG data URLs), pdfDataUrl?, pdfPath?, pdfError? } در صورت موفقیت، { ok: false, cancelled: true } وقتی کاربر برمیگردد، { ok: false, error } وقتی اسکنر نمیتواند شروع شود. isSupported() → { value: boolean } (Google Play services موجود است). نیازمندی: چیزی برای روشنکردن لازم نیست و مجوز دوربین هم لازم نیست (اسکنر داخل Play services اجرا میشود که مدل خود را در اولین استفاده دانلود میکند).
var Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightDocScanner;
async function scanReceipt() {
if (!Scanner) { alert('Scanning is not available here'); return; }
var s = await Scanner.isSupported();
if (!s.value) { alert('This phone has no Google Play services'); return; }
var r = await Scanner.scan({ pageLimit: 1, pdf: false, quality: 0.8 });
if (r.cancelled) return;
if (!r.ok) { alert('Scanner error: ' + r.error); return; }
document.getElementById('preview').src = r.pages[0];
}pageLimit 0 = بدون محدودیت. quality برای JPEG بین 0.1 تا 1 است. با pdf: true اسکنر یک PDF هم مینویسد: pdfDataUrl آن بهصورت یک URL از نوع data:application/pdf;base64,… است که صفحه میتواند دانلود، آپلود یا نمایش دهد، و pdfPath نسخهٔ آن در پوشهٔ کش اپلیکیشن است. اگر PDF خوانده نشد، صفحهها همچنان برمیگردند و pdfError دلیلش را میگوید.
در یک اپلیکیشن ساختهشده با هوش مصنوعی (null هنگام لغو، خطا یا در وب):
import { docScanner, can } from '@/lib/appmintNative';
if (can('docScanner') !== 'none') {
const res = await docScanner.scan({ pageLimit: 5, pdf: true });
if (res) setPages(res.pages); // res.pdfPath when pdf: true
}چند صفحه را اسکن کنید و PDF را ارائه دهید:
async function scanContract() {
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightDocScanner;
if (!Scanner) return;
const r = await Scanner.scan({ pageLimit: 0, pdf: true, quality: 0.9 });
if (!r.ok) { if (!r.cancelled) alert('Scanner error: ' + r.error); return; }
if (r.pdfDataUrl) {
const a = document.createElement('a');
a.href = r.pdfDataUrl; a.download = 'contract.pdf'; a.click();
} else if (r.pdfError) console.warn('PDF not made:', r.pdfError);
console.log(r.pages.length + ' pages scanned');
}نکتهها: صفحهها data URL کامل هستند و میتوانند بزرگ باشند - پیش از ذخیرهکردن تعداد زیادی از آنها در localStorage کوچکشان کنید. از pdfDataUrl استفاده کنید، نه pdfPath - مسیر فایل دستگاه یک URL نیست که صفحه بتواند بارگذاری کند. صفحهای که خوانده نشود رد میشود؛ بقیه همچنان برمیگردند.
Capacitor.AppwrightGallery Capacitor#
Capacitor.Plugins.AppwrightGallery — save({ source, fileName, album, kind })
نمونه
یک عکس یا ویدیو را در گالری گوشی ذخیره میکند (Pictures/<album> یا Movies/<album>). افزونهٔ اختصاصی پوستهٔ اپلیکیشن (AppwrightGalleryPlugin.kt).
خروجی: Promise از { uri } مورد ذخیرهشده. با یک code رد میشود: bad-source، download-failed، permission-denied (Android 7 تا 9، ذخیرهگاه رد شد) یا failed. نیازمندی: چیزی برای روشنکردن لازم نیست؛ در Android 10 به بعد مجوزی لازم نیست (Android 7 تا 9 بار اول ذخیرهگاه میخواهد).
const Gallery = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightGallery;
async function saveCard(canvas) {
const dataUrl = canvas.toDataURL('image/png');
if (!Gallery) { const a = document.createElement('a'); a.href = dataUrl; a.download = 'card.png'; a.click(); return; }
try {
await Gallery.save({ source: dataUrl, fileName: 'birthday-card.png', album: 'Cards' });
toast('Saved to your gallery');
} catch (e) {
toast('Could not save: ' + e.message);
}
}یک ویدیو را از سرور خود در آلبوم مخصوصش ذخیره کنید، با یک پیام برای هر کد خطا:
const Gallery = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightGallery;
async function saveClip(url) {
if (!Gallery) { window.open(url, '_blank'); return; }
try {
await Gallery.save({ source: url, fileName: 'highlight.mp4', album: 'Highlights', kind: 'video' });
toast('Video saved to Movies/Highlights');
} catch (e) {
if (e.code === 'download-failed') toast('Could not download the video. Check your connection.');
else if (e.code === 'permission-denied') toast('Allow storage access to save videos.');
else toast('Could not save: ' + e.message);
}
}عکسی را که کاربر ویرایش کرده بهصورت Blob (مثلاً از canvas.toBlob) با تبدیل آن ابتدا به یک URL از نوع data: ذخیره کنید:
const Gallery = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightGallery;
function blobToDataUrl(blob) {
return new Promise((resolve, reject) => {
const r = new FileReader();
r.onload = () => resolve(r.result);
r.onerror = () => reject(r.error);
r.readAsDataURL(blob);
});
}
async function saveEditedPhoto(canvas) {
if (!Gallery) return;
const blob = await new Promise((res) => canvas.toBlob(res, 'image/jpeg', 0.92));
const { uri } = await Gallery.save({ source: await blobToDataUrl(blob), fileName: 'edit-' + Date.now() + '.jpg', album: 'My Edits' });
console.log('saved as', uri);
}نکتهها: source یک URL از نوع data:، یک URL از نوع http(s) یا یک URI از نوع content:///file:// است؛ kind ('image'/'video') در صورت حذف، از نوع MIME خوانده میشود. اپلیکیشنهای ساختهشده با هوش مصنوعی از saveToGallery() از استفاده میکنند @/lib/appmintNative.
Capacitor.AppwrightHaptics Capacitor#
Capacitor.Plugins.AppwrightHaptics
نمونه
افزونهٔ اختصاصی AppMint برای الگوهای ویبرهٔ غنی: فهرستی از ضربهها، هر کدام با زمان شروع، طول و شدت خودش.
خروجی: play({ events }) مقدار { ok: true } یا { ok: false, error } را حل میکند ('unsupported' = بدون ویبره، 'empty' = بدون رویداد، یا پیام سیستم). هرگز رد نمیشود. isSupported() مقدار { value: true/false } را حل میکند. نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی مجوز ویبره را اعلام میکند، چه Vibrate در مرحله 4 (Access) تیک خورده باشد چه نه. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
هر رویداد { at, duration, intensity, sharpness } است: at = شروع به میلیثانیه، duration = طول به میلیثانیه (کمتر از 20 به یک ضربهٔ 30 میلیثانیهای تبدیل میشود)، intensity = 0 تا 1 (پیشفرض 0.8). sharpness پذیرفته میشود اما در اندروید نادیده گرفته میشود.
var AH = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.AppwrightHaptics : null;
async function heartbeat() {
if (!AH) return false;
var r = await AH.play({
events: [
{ at: 0, intensity: 0.8 },
{ at: 140, intensity: 0.5 },
{ at: 700, intensity: 0.8 },
{ at: 840, intensity: 0.5 }
]
});
if (!r.ok) console.log('pattern not played:', r.error);
return r.ok;
}
document.getElementById('like').addEventListener('click', heartbeat);دکمه را روی گوشیهای بدون ویبره پنهان کنید:
(async function () {
var btn = document.getElementById('feel-it');
var ok = false;
if (AH) { try { ok = (await AH.isSupported()).value; } catch (e) {} }
btn.hidden = !ok;
})();برای یک عمل موفق، یک ضربهٔ دوتایی سریع پخش کنید و گزارش دهید که چه زمانی نمیتواند پخش شود:
async function successBuzz() {
const AH = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightHaptics;
if (!AH) return;
const r = await AH.play({ events: [{ at: 0, duration: 40, intensity: 1 }, { at: 120, duration: 40, intensity: 0.6 }] });
if (!r.ok && r.error === 'unsupported') console.log('this phone has no vibrator');
}نکتهها: شدت فقط روی گوشیهایی کار میکند که کنترل دامنه دارند؛ گوشیهای دیگر زمانبندی را با یک شدت ثابت نگه میدارند. اگر سیستم ویبره را رد کند، play پاسخ { ok: false, error: '<the system message>' } میدهد. در اپلیکیشنهای ساختهشده با هوش مصنوعی از hapticPlay در @/lib/appmintNative استفاده کنید که الگوهای نامدار هم دارد.
Capacitor.AppwrightLiveProgress Capacitor#
Capacitor.Plugins.AppwrightLiveProgress — start / update / end
نمونه
افزونهٔ اندرویدی اختصاصی AppMint (نام آن در جاوااسکریپت AppwrightLiveProgress است) برای یک اعلان وضعیت ثابت، بیصدا و زنده (نوار پیشرفت، چرخنده یا ساعت در حال اجرا) که با لمس آن یک مسیر باز میشود.'
خروجی: start(opts) / update(opts) → Promise<{ ok: true, id }>، یا { ok: false, error } بدون ارسال چیزی - 'permission' وقتی اعلانها مجاز نیستند (Android 13 به بعد: هنوز داده نشده، یا برای اپلیکیشن خاموش شده)، 'channel_disabled' وقتی کاربر دستهٔ «Live status» را خاموش کرده؛ end({ id }) → Promise<void>. نیازمندی: اپلیکیشن اندروید و مجوز اعلان (Android 13 به بعد). در وب در دسترس نیست.
در یک اپلیکیشن ساختهشده با هوش مصنوعی از بستهٔ کمکی liveProgress از استفاده کنید @/lib/appmintNative:
import { liveProgress } from '@/lib/appmintNative';
await liveProgress.start({ id: 'order', title: 'Order #42', text: 'Being prepared', indeterminate: true });
await liveProgress.update({ id: 'order', title: 'Order #42', text: 'On the way', progress: 0.6, route: '/orders/42' });
await liveProgress.end('order');در یک صفحهٔ دستنویس:
async function showDelivery(step, total) {
const P = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightLiveProgress;
if (!P) return; // not in the Android app
if (window.Notification && Notification.permission !== 'granted') {
if (await Notification.requestPermission() !== 'granted') return;
}
const r = await P.update({
id: 'delivery',
title: 'Your delivery',
text: 'Stop ' + step + ' of ' + total,
progress: step / total, // 0–1; or indeterminate: true
route: '/track' // opened when the card is tapped
});
if (!r.ok) console.warn('live card not posted:', r.error);
}
async function deliveryDone() {
const P = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightLiveProgress;
if (P) await P.end({ id: 'delivery' });
}یک تایمر تمرین: startedAt کارت را خودکار به بالا میشمارد، پس یکبار ارسال میشود و وقتی تمرین تمام شد پایان مییابد:
const Live = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightLiveProgress;
let workoutStart = 0;
async function startWorkout(name) {
workoutStart = Date.now();
if (!Live) return;
const r = await Live.start({ id: 'workout', title: name, text: 'Workout in progress', startedAt: workoutStart, route: '/workout' });
if (!r.ok && r.error === 'channel_disabled') {
showHint('Turn on "Live status" in this app\'s notification settings to see the timer.');
}
}
async function stopWorkout() {
if (Live) await Live.end({ id: 'workout' });
saveWorkout({ durationMs: Date.now() - workoutStart });
}گزینهها: id (پیشفرض 'live')، title، text، progress (0 تا 1، برای نبودن نوار حذف کنید)، indeterminate، startedAt (epoch میلیثانیه، یک ساعت در حال اجرا نشان میدهد)، route.
نکتهها: start و update کار یکسانی میکنند (کارت را با همان شناسه ارسال یا جایگزین میکنند). کارت را نمیشود کنار زد - همیشه end را صدا بزنید. ابتدا مجوز را بگیرید: در Android 13 به بعد بدون آن، start پاسخ error: 'permission' میدهد و چیزی ارسال نمیکند.
Capacitor.AppwrightSystemPalette Capacitor#
Capacitor.Plugins.AppwrightSystemPalette — get()
نمونه
رنگهای Material You گوشی را برمیگرداند (پالتی که Android 12 به بعد از تصویر زمینه میسازد)، تا اپلیکیشن بتواند با اپلیکیشنهای سیستم هماهنگ شود. افزونهٔ اختصاصی AppMint (AppwrightSystemPalettePlugin.kt).
خروجی: Promise { available: false } زیر Android 12، وگرنه { available: true, accent1, accent2, accent3, neutral1, neutral2 } - هر کدام یک شیء از رنگهای هگز بهازای هر تُن، با تُنهای '0'، '10'، '50'، '100' … '900'، '1000' (مثلاً accent1['600'] === '#3F5F90'). نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی این افزونه را دارد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var Palette = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightSystemPalette;
async function useWallpaperColours() {
if (!Palette) return;
var p = await Palette.get();
if (!p.available) return; // keep the app's own colours
var root = document.documentElement.style;
root.setProperty('--accent', p.accent1['600']);
root.setProperty('--surface', p.neutral1['50']);
}
useWallpaperColours();در یک اپلیکیشن ساختهشده با هوش مصنوعی:
import { systemPalette } from '@/lib/appmintNative';
const p = await systemPalette();
if (p.available && p.accent1) document.documentElement.style.setProperty('--accent', p.accent1['600']);رنگهای روشن یا تیره را متناسب با تم سیستم انتخاب کنید و وقتی کاربر از تغییر تصویر زمینه برمیگردد، پالت را دوباره بخوانید:
var Palette = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightSystemPalette;
var darkQuery = window.matchMedia('(prefers-color-scheme: dark)');
async function applyPalette() {
if (!Palette) return;
var p = await Palette.get();
if (!p.available) return;
var dark = darkQuery.matches;
var s = document.documentElement.style;
s.setProperty('--accent', p.accent1[dark ? '200' : '600']);
s.setProperty('--on-accent', p.accent1[dark ? '800' : '0']);
s.setProperty('--bg', p.neutral1[dark ? '900' : '10']);
s.setProperty('--text', p.neutral1[dark ? '100' : '900']);
}
darkQuery.addEventListener('change', applyPalette);
document.addEventListener('visibilitychange', function () {
if (document.visibilityState === 'visible') applyPalette();
});
applyPalette();نکتهها: پیش از اعمال رنگهای پالت، کنتراست متن را بررسی کنید - تضمینی نیست که رنگ تصویر زمینه روی پسزمینهٔ شما خوانا باشد. مرورگرها رنگ تصویر زمینه را در اختیار نمیگذارند: در وب بستهٔ کمکی { available: false } پاسخ میدهد. وقتی کاربر تصویر زمینه را عوض کند رنگها تغییر میکنند؛ هنگام ازسرگیری دوباره get() را صدا بزنید.
Capacitor.AppwrightWidget Capacitor#
Capacitor.Plugins.AppwrightWidget — set(card), clear(), placedCount(), requestPin()
نمونه
ویجت صفحهٔ اصلی اپلیکیشن را پر میکند: یک کارت با عنوان، یک مقدار بزرگ، تا دوازده خط، رنگهای شما و یک مسیر لمس - همان کارتی که AppMint.widget.set() میگیرد، با همهٔ کلیدها. کارت روی گوشی ذخیره میشود و حتی بعد از راهاندازی مجدد نشان داده میشود. افزونهٔ اختصاصی AppMint (AppwrightWidgetPlugin.kt).
خروجی: set({ title?, value?, caption?, lines?, route?, bg?, ink?, accent?, textSize?, align?, wrap?, … }) → Promise { ok: true, placed }، با دلیل کارت نامعتبر رد میشود (placed = ویجتهایی که اکنون روی صفحهٔ اصلی هستند). clear() → void. placedCount() → { value }. requestPin() → { value: boolean } (true وقتی برگهٔ «افزودن ویجت» راهانداز باز شد). نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی ویجت را اعلام میکند. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var Widget = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightWidget;
async function updateWidget(tasks) {
if (!Widget) return;
await Widget.set({
title: 'Today',
value: tasks.length + ' tasks',
lines: tasks.slice(0, 6).map(function (t) { return t.title; }),
route: '/today', // opened when the widget is tapped
bg: '#0B0F1A', ink: '#FFFFFF', accent: '#22D3EE'
});
}پیشنهاد دهید که قرارش دهد (فقط وقتی هنوز هیچکدام جاگذاری نشده):
async function offerWidget() {
if (!Widget) return;
var n = (await Widget.placedCount()).value;
if (n > 0) return;
var r = await Widget.requestPin();
if (!r.value) alert('Long-press the home screen, tap Widgets and pick this app.');
}در یک اپلیکیشن ساختهشده با هوش مصنوعی:
import { widget } from '@/lib/appmintNative';
await widget.set({ title: 'Today', value: '3 tasks', lines: ['Gym', 'Call mum'], route: '/today' });
if ((await widget.placedCount()) === 0) await widget.requestPin();نکتهها: رنگها #RRGGBB، #AARRGGBB (آلفا اول) یا rgba() هستند؛ رنگهای خالی از یک کارت تیره با مقدار فیروزهای استفاده میکنند. برای خطهای استایلدار به AppMint.widget نگاه کنید، caption، textSize، align، wrap و font (فایل .ttf/.otf خودتان، بهصورت یک مسیر در اپلیکیشن شما). لمس، اپلیکیشن را در route بهصورت یک پیوند عمیق باز میکند (با WebToApk.getLaunchUrl() یا رویداد appmint:deep-link بخوانید). پیش از هر set()، ویجت میگوید «Nothing to show yet»؛ clear() آن را به همان حالت برمیگرداند. در مرورگر can('widget') است 'none'.
Capacitor.Badge Capacitor#
Capacitor.Plugins.Badge — the launcher-icon count
نمونه
افزونهٔ Badge (از capawesome) که عدد روی آیکن راهانداز اپلیکیشن را تنظیم میکند.
خروجی: Promiseها: set({ count })، clear()، increase()، decrease() → void؛ get() → { count }؛ isSupported() → { isSupported }. افزونهٔ اندروید متد مجوز ندارد. نیازمندی: در اندروید هیچ. در وب در دسترس نیست.
در یک اپلیکیشن ساختهشده با هوش مصنوعی از بستهٔ کمکی badge از استفاده کنید @/lib/appmintNative:
import { badge } from '@/lib/appmintNative';
await badge.set(3);
await badge.clear();در یک صفحهٔ دستنویس:
async function setUnread(count) {
const B = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Badge;
if (!B) return false; // not inside the app
try {
const s = await B.isSupported();
if (!s.isSupported) return false; // this launcher shows no badges
if (count > 0) await B.set({ count: count });
else await B.clear();
return true;
} catch (e) {
return false;
}
}
window.addEventListener('appmint:push', function () {
const inbox = JSON.parse(window.WebToApk ? WebToApk.getPushInbox() : '[]');
setUnread(inbox.filter(function (m) { return !m.read; }).length);
});با رسیدن و خواندهشدن موارد، به بالا و پایین بشمارید:
const B = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Badge;
async function onNewMessage() { if (B) await B.increase(); }
async function onMessageRead() { if (B) await B.decrease(); }
async function showCurrent() {
if (!B) return;
const { count } = await B.get();
console.log('badge shows', count);
}نکتهها: در اندروید ظاهر بستگی به راهانداز دارد (یک عدد، یک نقطه یا هیچ). navigator.setAppBadge(n) در اپلیکیشن روی همان نشان مینویسد (فقط روی راهاندازهایی وجود دارد که میتوانند شمارنده نشان دهند).
Capacitor.BarcodeScanner Capacitor#
Capacitor.Plugins.BarcodeScanner — scan, startScan, readBarcodesFromImage, isSupported
نمونه
اسکن QR و بارکد با API مربوط به @capacitor-mlkit/barcode-scanning - افزونهٔ اختصاصی پوستهٔ اپلیکیشن (BarcodeScannerPlugin.kt) روی همان اسکنر کد Google که AppMint.scanCode() دارد. فراخوانیهای قدیمیتر @capacitor-community/barcode-scanner (startScan() که { hasContent, content }، checkPermission، prepare، hideBackground را برمیگرداند) همین نام را دارند و آنها هم کار میکنند.
خروجی: scan({ formats?, autoZoom? }) → { barcodes: [{ rawValue, displayValue, format, valueType, bytes?, cornerPoints?, urlBookmark?, wifi?, email?, phone?, sms?, geoPoint?, contactInfo?, calendarEvent?, driverLicense? }] } (وقتی کاربر برمیگردد "scan canceled." رد میشود)؛ readBarcodesFromImage({ path, formats? }) → { barcodes }؛ isSupported() → { supported }؛ isGoogleBarcodeScannerModuleAvailable() → { available }؛ installGoogleBarcodeScannerModule() (پیشرفت بهصورت googleBarcodeScannerModuleInstallProgress)؛ checkPermissions() / requestPermissions() → { camera }؛ openSettings(). format مقادیری مثل 'QR_CODE'، 'EAN_13'، 'CODE_128'… است. نیازمندی: چیزی برای روشنکردن لازم نیست و مجوز دوربین هم لازم نیست - اسکنر Google صفحهٔ خودش را رسم میکند (Play services آن را در اولین استفاده دانلود میکند). window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.BarcodeScanner;
scanBtn.onclick = async () => {
if (!Scanner) return;
try {
const { barcodes } = await Scanner.scan({ formats: ['QR_CODE'] });
const code = barcodes[0];
if (code.valueType === 'URL') location.href = code.urlBookmark.url;
else resultBox.textContent = code.displayValue;
} catch (e) {
if (e.message !== 'scan canceled.') alert(e.message);
}
};جستجوی قیمت از روی بارکد محصول، با سبک شنونده (startScan + barcodesScanned) که اپلیکیشنهای ML Kit از قبل استفاده میکنند:
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.BarcodeScanner;
async function scanProduct() {
const listener = await Scanner.addListener('barcodesScanned', async ({ barcodes }) => {
await listener.remove();
await Scanner.stopScan();
const ean = barcodes[0].rawValue;
const res = await fetch('https://api.example.com/products/' + encodeURIComponent(ean));
priceBox.textContent = res.ok ? (await res.json()).price : 'Not found';
});
await Scanner.startScan({ formats: ['EAN_13', 'EAN_8', 'UPC_A', 'UPC_E'] });
}یک کد QR را از عکسی بخوانید که کاربر از قبل دارد:
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.BarcodeScanner;
const Camera = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Camera;
async function qrFromGallery() {
const photo = await Camera.getPhoto({ source: 'PHOTOS', resultType: 'uri', quality: 90 });
const { barcodes } = await Scanner.readBarcodesFromImage({ path: photo.path, formats: ['QR_CODE'] });
return barcodes.length ? barcodes[0].rawValue : null;
}نکتهها: startScan() بالادستی یک پیشنمایش زندهٔ دوربین پشت یک صفحهٔ شفاف نشان میدهد و تا stopScan() به اسکن ادامه میدهد؛ اینجا صفحهٔ اسکنر را باز میکند، اولین کد barcodeScanned / barcodesScanned را اجرا میکند و جلسه پایان مییابد (فراخوانی سپس برای کد جامعه با { hasContent, content, format } تکمیل میشود؛ اسکنر بستهشده با { hasContent: false } تکمیل میشود). چراغ قوه و زوم به آن پیشنمایش تعلق دارند، پس isTorchAvailable() برابر false است و setterهای چراغ قوه/زوم reject میشوند - صفحهٔ اسکنر دکمهٔ چراغ قوهٔ خودش را دارد. checkPermissions() وقتی اپلیکیشن اصلاً مجوز دوربین ندارد با granted پاسخ میدهد (اسکنر به هیچکدام نیاز ندارد)؛ اپلیکیشنی که از دوربین هم استفاده میکند وضعیت واقعیاش را میگیرد. اپلیکیشنهای ساختهشده با هوش مصنوعی از scanCode() استفاده میکنند از @/lib/appmintNative.
Capacitor.Browser Capacitor#
Capacitor.Plugins.Browser — open({ url, toolbarColor }), close(), addListener('browserFinished')
نمونه
یک صفحهٔ وب را در یک تب مرورگر داخل اپلیکیشن (Chrome Custom Tabs) باز میکند، تا کاربر شرایط، مستندات یا صفحهٔ ورود را بخواند و با یک حرکت برگردد (@capacitor/browser 8.0.3).
خروجی: open() / close() → Promise void. رویدادها: browserFinished (کاربر تب را بست) و browserPageLoaded. نیازمندی: هیچ - هر اپلیکیشنی این افزونه را دارد (باید مرورگری که از Custom Tabs پشتیبانی میکند، مانند Chrome، نصب باشد). window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var Browser = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Browser;
async function openTerms() {
if (!Browser) return;
var h = await Browser.addListener('browserFinished', function () {
console.log('user closed the terms');
h.remove();
});
await Browser.open({ url: 'https://example.com/terms', toolbarColor: '#0B0F1A' });
}در یک اپلیکیشن ساختهشده با هوش مصنوعی (یک تب جدید در وب):
import { browser } from '@/lib/appmintNative';
const off = browser.onClosed(() => refreshAccount());
await browser.open('https://example.com/terms', { toolbarColor: '#0B0F1A' });
// call off() when you no longer careیک پیوند را باز کنید و وقتی بازگشت ورود به صفحه رسید، تب را ببندید:
var Browser = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Browser;
async function openHelp() {
if (!Browser) { window.open('https://example.com/help', '_blank'); return; }
try {
await Browser.open({ url: 'https://example.com/help' });
} catch (e) {
alert('Could not open the page: ' + e.message);
}
}
window.addEventListener('appmint:deep-link', function () {
if (Browser) Browser.close().catch(function () {});
});نکتهها: url نباید خالی باشد. toolbarColor یک رنگ هگز است؛ رنگ نامعتبر نادیده گرفته میشود. close() در این نسخهٔ افزونه در اندروید هم کار میکند (فعالیت میزبان تب را میبندد) - بعد از بازگشت یک پیوند ورود به اپلیکیشن مفید است. تب یک مرورگر جداست: کوکیهای اپلیکیشن را به اشتراک نمیگذارد یا localStorage.
Capacitor.Calendar Capacitor#
Capacitor.Plugins.Calendar — createEvent, findEvents, deleteEvent, listCalendars, openCalendar
نمونه
رویدادها را در تقویم خود گوشی (Android CalendarContract) اضافه، پیدا و حذف میکند و اپلیکیشن تقویم را در یک تاریخ باز میکند. نسخهٔ همراهشده @capacitor/calendar (template/plugins/calendar).
خروجی: createEvent() → { id }؛ findEvents() → { events: [{ id, title, location?, notes?, startDate, endDate, isAllDay, calendarId, calendarName?, attendees? }] }؛ listCalendars() → { calendars: [{ id, name, displayName?, isPrimary }] }؛ deleteEvent()، openCalendar() → void. تاریخها میلیثانیهٔ epoch هستند. نیازمندی: هنگام ساخت، Calendar را در مرحله 4 (Access) تیک بزنید. برای اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی، وقتی فایلهای شما شامل یک فراخوانی Calendar.<method>( دقیقاً به همین شکل (مانند زیر) یا calendar.createEvent( بستهٔ کمکی باشد، ساخت خودش مجوز تقویم را هم اضافه میکند. افزونه در اولین استفاده از کاربر اجازهٔ دسترسی به تقویم میگیرد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var Calendar = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Calendar;
async function addDentist() {
if (!Calendar) return;
var start = new Date('2026-10-02T10:00:00').getTime();
try {
var r = await Calendar.createEvent({
title: 'Dentist', startDate: start, endDate: start + 60 * 60 * 1000,
location: 'Main St 5', notes: 'Bring the card', isAllDay: false,
firstReminderMinutes: 30
});
console.log('event id', r.id);
} catch (e) {
// e.code: OS-PLUG-CLDR-0020 permission denied, -0001 bad arguments
alert('Could not add the event: ' + e.message);
}
}این هفته را بخوانید، یکی را حذف کنید، تقویم را باز کنید:
async function thisWeek() {
if (!Calendar) return;
var now = Date.now();
var found = await Calendar.findEvents({ startDate: now, endDate: now + 7 * 864e5 });
found.events.forEach(function (ev) { console.log(ev.title, new Date(ev.startDate)); });
if (found.events.length) await Calendar.deleteEvent({ id: found.events[0].id });
await Calendar.openCalendar({ date: now });
}در یک اپلیکیشن ساختهشده با هوش مصنوعی (در وب createEvent یک فایل .ics دانلود میکند؛ خواندن برمیگرداند []):
import { calendar } from '@/lib/appmintNative';
if ((await calendar.requestPermission()) === 'granted') {
const id = await calendar.createEvent({ title: 'Dentist', start: new Date('2026-10-02T10:00'), end: new Date('2026-10-02T11:00') });
const week = await calendar.listEvents({ from: Date.now(), to: Date.now() + 7 * 864e5 });
if (id) await calendar.deleteEvent(id);
await calendar.openCalendar(new Date());
}نکتهها: بدون مجوز تقویم در اپلیکیشن، هیچ پنجرهای ظاهر نمیشود و هر فراخوانی رویداد رد میشود (مجوز موجود نیست)؛ کاربری که نه بگوید OS-PLUG-CLDR-0020 میگیرد. recurrence: { frequency: 'daily' | 'weekly' | 'monthly' | 'yearly', interval?, count?, endDate? } یک رویداد تکرارشونده میسازد. createEventInteractively({ title, startDate, endDate }) بهجای آن ویرایشگر خود اپلیکیشن تقویم را باز میکند: { id } رویداد ذخیرهشده را برمیگرداند، و وقتی کاربر ویرایشگر را بدون ذخیره ببندد OS-PLUG-CLDR-0006 رد میشود (برای تشخیص این دو، علاوه بر نوشتن به دسترسی خواندن هم نیاز دارد). deleteEvent({ id, fromDate }) یک رویداد تکرارشونده را پیش از fromDate پایان میدهد و رخدادهای قبلی را نگه میدارد. بستهٔ کمکی بهجای خطا، null / [] / false برمیگرداند.
Capacitor.Camera Capacitor#
Capacitor.Plugins.Camera
نمونه
افزونهٔ رسمی Capacitor Camera، که در اپلیکیشن ساخته شده: با دوربین عکس بگیرید یا از گالری عکس انتخاب کنید.
خروجی: Promiseها. getPhoto(opts) → { dataUrl | base64String | webPath, format, saved } (کدام فیلد بستگی به resultType دارد)، و وقتی کاربر لغو کند رد میشود؛ pickImages(opts) → { photos: [{ webPath, format }] }؛ checkPermissions() / requestPermissions({ permissions }) → { camera, photos }. نیازمندی: Camera را در مرحله 4 (Access) تیک بزنید. برای اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی، وقتی فایلهای شما شامل Camera.getPhoto( دقیقاً به همین شکل (مانند زیر)، getUserMedia با ویدیو، یا <input capture> باشد، ساخت خودش مجوز دوربین را هم اضافه میکند. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
یک عکس بگیرید و نشانش دهید.
async function takePhoto() {
var Camera = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Camera;
if (!Camera) { showMessage('Open the app to use the camera.'); return; }
try {
var perm = await Camera.requestPermissions({ permissions: ['camera'] });
if (perm.camera !== 'granted') { showMessage('Camera permission was refused.'); return; }
var photo = await Camera.getPhoto({
source: 'CAMERA', // 'CAMERA' | 'PHOTOS' | 'PROMPT'
resultType: 'dataUrl', // 'dataUrl' | 'base64' | 'uri'
quality: 80,
direction: 'REAR', // 'REAR' | 'FRONT'
correctOrientation: true,
saveToGallery: false
});
document.getElementById('photo').src = photo.dataUrl;
} catch (err) {
// The user closed the camera (or no camera app). Nothing to do.
}
}تا 5 عکس از گالری انتخاب کنید.
async function choosePhotos() {
var Camera = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Camera;
if (!Camera) return;
try {
var result = await Camera.pickImages({ quality: 80, limit: 5 });
result.photos.forEach(function (p) {
var img = document.createElement('img');
img.src = p.webPath; // a URL the page can load
document.getElementById('gallery').appendChild(img);
});
} catch (err) { /* cancelled */ }
}در یک اپلیکیشن ساختهشده با هوش مصنوعی از بستهٔ کمکی استفاده کنید که در وب هم کار میکند (و هنگام لغو، بهجای خطا null برمیگرداند):
import { camera } from '@/lib/appmintNative';
const photo = await camera.take({ source: 'camera' });نکتهها: pickImages مجوز دوربین نمیخواهد. اگر مجوز دوربین در اپلیکیشن نباشد (گزینه خاموش بود و ساخت هیچ فراخوانی دوربین پیدا نکرد)، مجوز دوربین بدون هیچ درخواستی رد میشود. یک <input type="file" accept="image/*" capture> هم دوربین را باز میکند. دوربین حساس است: آن را در فرم Data safety خود در Play اعلام کنید.
Capacitor.CapacitorBarcodeScanner Capacitor#
Capacitor.Plugins.CapacitorBarcodeScanner — scanBarcode({ hint })
نمونه
اسکن QR / بارکد با یک فراخوانی و با API رسمی @capacitor/barcode-scanner - افزونهٔ اختصاصی پوستهٔ اپلیکیشن (CapacitorBarcodeScannerPlugin.kt) روی همان اسکنر کد Google که AppMint.scanCode() دارد. کدی که برای بستهٔ npm نوشته شده (CapacitorBarcodeScanner.scanBarcode({ hint: CapacitorBarcodeScannerTypeHint.ALL })) بدون تغییر کار میکند.
خروجی: scanBarcode({ hint, scanInstructions?, cameraDirection?, scanOrientation? }) → { ScanResult, format }. hint / format اعداد بسته هستند: 0 QR_CODE، 1 AZTEC، 2 CODABAR، 3 CODE_39، 4 CODE_93، 5 CODE_128، 6 DATA_MATRIX، 8 ITF، 9 EAN_13، 10 EAN_8، 11 PDF_417، 14 UPC_A، 15 UPC_E، 17 ALL. وقتی کاربر اسکنر را ببندد با کد OS-PLUG-BARC-0006 رد میشود. نیازمندی: چیزی برای روشنکردن لازم نیست و مجوز دوربین هم لازم نیست - اسکنر Google صفحهٔ خودش را رسم میکند (Play services آن را در اولین استفاده دانلود میکند). window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorBarcodeScanner;
ticketBtn.onclick = async () => {
if (!Scanner) return;
try {
const { ScanResult } = await Scanner.scanBarcode({ hint: 0 }); // QR codes only
const ok = await fetch('/api/tickets/check?code=' + encodeURIComponent(ScanResult)).then((r) => r.ok);
statusBox.textContent = ok ? 'Valid ticket' : 'Unknown ticket';
} catch (e) {
if (e.code !== 'OS-PLUG-BARC-0006') alert(e.message);
}
};هر کدی را بپذیرید و به کاربر بگویید از چه نوعی بود:
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorBarcodeScanner;
const NAMES = { 0: 'QR code', 5: 'Code 128', 9: 'EAN-13', 10: 'EAN-8', 14: 'UPC-A', 15: 'UPC-E' };
async function scanAnything() {
const { ScanResult, format } = await Scanner.scanBarcode({ hint: 17 });
return (NAMES[format] || 'Barcode') + ': ' + ScanResult;
}خطایی را مدیریت کنید که بستهشدن اسکنر توسط کاربر نیست:
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorBarcodeScanner;
async function scanProduct() {
if (!Scanner) { alert('Scanning works only inside the app'); return null; }
try {
const { ScanResult } = await Scanner.scanBarcode({ hint: 9 }); // EAN-13
return ScanResult;
} catch (e) {
if (e.code === 'OS-PLUG-BARC-0006') return null; // user closed the scanner
alert('Scan failed: ' + e.message);
return null;
}
}نکتهها: scanInstructions، scanButton، cameraDirection و scanOrientation صفحهٔ دوربین خود upstream را استایل میدهند و روی اسکنر Google اثری ندارند (همیشه دوربین پشتی). MAXICODE، RSS_14، RSS_EXPANDED و UPC_EAN_EXTENSION بهعنوان hint پشتیبانی نمیشوند (OS-PLUG-BARC-0008 رد میشود)؛ 17 (ALL) همهٔ نوعهای پشتیبانیشده را اسکن میکند. اپلیکیشنهای ساختهشده با هوش مصنوعی از scanCode() از استفاده میکنند @/lib/appmintNative.
Capacitor.CapacitorCookies Capacitor#
Capacitor.Plugins.CapacitorCookies — getCookies / setCookie / deleteCookie / clearCookies / clearAllCookies
نمونه
کوکیهای اپلیکیشن را میخواند و مینویسد، از جمله کوکیهای میزبان دیگری که صفحهٔ شما با آن ارتباط دارد (هستهٔ Capacitor CapacitorCookies).
مقدار بازگشتی: getCookies({ url? }) ← { [name]: value } - با یک url، کوکیهایی که آن URL (میزبان و مسیر) میفرستاد؛ بدون آن، document.cookie خود صفحه. یک url را که http(s) نباشد reject میکند. setCookie({ key, value, url?, path?, expires? })، deleteCookie({ key, url? })، clearCookies({ url? })، clearAllCookies() ← Promise void؛ setCookie / deleteCookie بدون یک key رشتهای (و value) reject میشوند و سپس چیزی نمینویسند. نیازها: چیزی برای روشن کردن نیست - هر اپلیکیشن افزونه را میزبانی میکند. window.Capacitor روی صفحههایی وجود دارد که خود اپلیکیشن سرو میکند (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و، در اپلیکیشن حالت وبسایت، روی سایت خودتان (دامنه و زیردامنههایش) - هرگز روی سایتهای دیگری که اپلیکیشن باز میکند. پشتیبانی را تشخیص دهید.
var Cookies = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorCookies;
// Read the session cookie your API host set — not the page's own cookies.
async function apiSession() {
if (!Cookies) return null; // not inside the app
var jar = await Cookies.getCookies({ url: 'https://api.example.com/' });
return jar.session || null;
}
// Remember a choice for the API host, for 30 days, on one path only.
async function rememberRegion(region) {
if (!Cookies) return;
var expires = new Date(Date.now() + 30 * 864e5).toUTCString();
await Cookies.setCookie({ url: 'https://api.example.com', path: '/v2', key: 'region', value: region, expires: expires });
}خروج از حساب: کوکیهای آن میزبان، یا هر کوکی که اپلیکیشن نگه میدارد را حذف کنید.
async function signOut(everything) {
if (!Cookies) return;
if (everything) await Cookies.clearAllCookies();
else await Cookies.clearCookies({ url: 'https://api.example.com' });
}نکتهها: کوکیای که با یک path تنظیم شده فقط برای یک url زیر آن مسیر برگردانده میشود. مقادیر هنگام خواندن URL-decode میشوند. کوکیها بین هر صفحهای که اپلیکیشن نشان میدهد مشترک هستند، پس هرگز رازها را در کوکیای نگه ندارید که یک صفحهٔ خارجی بتواند بخواند - جای آنها در Preferences یا ذخیرهگاه امن اپلیکیشن است.
Capacitor.CapacitorSQLite Capacitor#
Capacitor.Plugins.CapacitorSQLite — createConnection, open, execute, query, run, executeSet, close
نمونه
یک پایگاهدادهٔ SQLite واقعی روی گوشی، با API مربوط به @capacitor-community/sqlite. نسخهٔ همراهشدهٔ @capacitor-community/sqlite (template/plugins/sqlite)، که روی SQLite خود اندروید اجرا میشود. کدی که برای بستهٔ npm نوشته شده (new SQLiteConnection(CapacitorSQLite)) بدون تغییر کار میکند؛ یک صفحهٔ دستنویس مستقیماً شیء افزونه را صدا میزند، مانند زیر.
خروجی: createConnection({ database, version, encrypted: false, mode: 'no-encryption', readonly: false })، open({ database })، close({ database })، closeConnection({ database }) → void؛ execute({ database, statements }) → { changes: { changes } }؛ run({ database, statement, values }) → { changes: { changes, lastId } }؛ query({ database, statement, values }) → { values: [rows] }؛ executeSet({ database, set: [{ statement, values }] }) → { changes }؛ isDBExists({ database }) / isDBOpen({ database }) → { result }؛ beginTransaction، commitTransaction، rollbackTransaction، isTransactionActive({ database })؛ deleteDatabase({ database })؛ exportToJson / importFromJson برای پشتیبانگیری. نیازمندی: چیزی برای روشنکردن لازم نیست و مجوزی هم لازم نیست. پایگاهداده در حافظهٔ خصوصی اپلیکیشن است و از بهروزرسانی اپلیکیشن جان سالم به در میبرد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
const DB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorSQLite;
const database = 'notes';
async function openNotes() {
if (!DB) return false;
await DB.createConnection({ database, version: 1, encrypted: false, mode: 'no-encryption', readonly: false });
await DB.open({ database, readonly: false });
await DB.execute({ database, statements:
'CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT NOT NULL, at INTEGER);' });
return true;
}
async function addNote(text) {
const r = await DB.run({ database, statement: 'INSERT INTO notes (text, at) VALUES (?, ?);', values: [text, Date.now()] });
return r.changes.lastId;
}
async function listNotes() {
const r = await DB.query({ database, statement: 'SELECT id, text, at FROM notes ORDER BY at DESC;', values: [] });
return r.values || [];
}چند نوشتن که یا همه باید انجام شوند یا هیچکدام - یک تراکنش با executeSet:
const DB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorSQLite;
async function moveMoney(database, fromId, toId, amount) {
await DB.executeSet({ database, transaction: true, set: [
{ statement: 'UPDATE accounts SET balance = balance - ? WHERE id = ?;', values: [amount, fromId] },
{ statement: 'UPDATE accounts SET balance = balance + ? WHERE id = ?;', values: [amount, toId] },
{ statement: 'INSERT INTO ledger (from_id, to_id, amount, at) VALUES (?, ?, ?, ?);', values: [fromId, toId, amount, Date.now()] },
] });
}پایگاهداده را در هر شروع اپلیکیشن فقط یکبار باز کنید، حتی وقتی دو صفحه همزمان درخواست میکنند:
const DB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorSQLite;
let ready = null;
function db(database) {
if (!ready) ready = (async () => {
try {
await DB.createConnection({ database, version: 1, encrypted: false, mode: 'no-encryption', readonly: false });
} catch (e) {
if (!/already exists/i.test(e.message)) throw e; // a page reload keeps the native connection
}
if (!(await DB.isDBOpen({ database, readonly: false })).result) await DB.open({ database, readonly: false });
return database;
})();
return ready;
}نکتهها: اپلیکیشن بدون SQLCipher ساخته شده، پس پایگاهدادهها رمزگذاری نمیشوند: encrypted: true، setEncryptionSecret، changeEncryptionSecret، isSecretStored و دیگر فراخوانیهای رمزگذاری با «Encryption is not available in this app» رد میشوند. isInConfigEncryption() پاسخ false میدهد. هر چیز دیگر (پرسوجوها، مقادیر پیوستشده، تراکنشها، ارتقاهای نسخهدار با addUpgradeStatement، درونبُرد/برونبُرد JSON) کد خود افزونه است. خطاها متن خطای SQLite را دارند.
Capacitor.Clipboard Capacitor#
Capacitor.Plugins.Clipboard — write(options), read()
نمونه
متن (یا پیوند) را در کلیپبورد سیستم کپی میکند و آن را دوباره میخواند (@capacitor/clipboard 8.0.1).
مقدار بازگشتی: write({ string?, url?, image?, label? }) ← Promise void. read() ← Promise { value, type } (type برای متن 'text/plain' است). نیازها: چیزی برای روشن کردن نیست - هر اپلیکیشن افزونه را میزبانی میکند. window.Capacitor روی صفحههایی وجود دارد که خود اپلیکیشن سرو میکند (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و، در اپلیکیشن حالت وبسایت، روی سایت خودتان (دامنه و زیردامنههایش) - هرگز روی سایتهای دیگری که اپلیکیشن باز میکند. پشتیبانی را تشخیص دهید.
async function copyCode(code) {
var Clipboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Clipboard;
if (!Clipboard) { alert('Copy is not available here'); return; }
await Clipboard.write({ string: code, label: 'Invite code' });
}
async function pasteCode(input) {
var Clipboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Clipboard;
if (!Clipboard) return;
try {
var r = await Clipboard.read();
input.value = r.value;
} catch (e) {
// An EMPTY clipboard is a rejection: "There is no data on the clipboard".
if (/no data/i.test(e.message)) input.value = '';
else alert('Could not read the clipboard: ' + e.message);
}
}در یک اپلیکیشن ساختهشده با هوش مصنوعی بستهٔ کمکی با شکل Capacitor یک کلیپبورد خالی را تبدیل میکند به '':
import { Clipboard } from '@/lib/appmintNative';
await Clipboard.write({ string: 'ABC-123' });
const { value } = await Clipboard.read(); // '' when the clipboard is emptyیک پیوند را کپی کنید و آن را با یک ضربهٔ بازخورد تأیید کنید:
async function copyLink(url) {
var P = window.Capacitor && window.Capacitor.Plugins;
if (!P || !P.Clipboard) { alert('Copy is not available here'); return; }
await P.Clipboard.write({ url: url });
if (P.Haptics) P.Haptics.impact({ style: 'LIGHT' });
copiedToast.hidden = false;
}نکتهها: write به یکی از string، url یا image (یک data URL) نیاز دارد، وگرنه با «No data provided» رد میشود. Android 12 به بعد هنگام خواندن، اعلان خودش را «pasted from…» نشان میدهد - این از سیستمعامل است، نه اپلیکیشن. write بستهٔ کمکی فقط میفرستد string || url.
Capacitor.Contacts Capacitor#
Capacitor.Plugins.Contacts — getContacts, getContact, pickContact, createContact, deleteContact
نمونه
دفترچه تلفن گوشی با API مربوط به @capacitor-community/contacts. نسخهٔ همراهشدهٔ @capacitor-community/contacts (template/plugins/contacts). کدی که برای بستهٔ npm نوشته شده بدون تغییر کار میکند.
خروجی: checkPermissions() / requestPermissions() → { contacts, contactsWrite } (هر کدام 'granted' | 'denied' | 'prompt'؛ contacts خواندن است، contactsWrite افزودن و حذف است)؛ getContacts({ projection }) → { contacts: [ContactPayload] }؛ getContact({ contactId, projection }) و pickContact({ projection }) → { contact }؛ createContact({ contact }) → { contactId }؛ deleteContact({ contactId }) → void. projection فیلدها را انتخاب میکند: { name, phones, emails, organization, birthday, note, urls, postalAddresses, image } (هر کدام true). نیازمندی: برای خواندن، Contacts را در مرحله 4 (Access) تیک بزنید و برای افزودن یا حذف، Edit Contacts را هم. ساختهای HTML، ZIP و AI-Studio وقتی کد Contacts.getContacts( / getContact( / pickContact( (خواندن) یا Contacts.createContact( / deleteContact( (هر دو) را صدا میزند، خودشان آنها را تیک میزنند. افزونه در اولین استفاده از کاربر اجازه میگیرد؛ بدون تیکخوردن گزینه، فراخوانی رد میشود با «Permission is required to access contacts.» - و در اپلیکیشنی که هیچکدام از Contacts، SMS یا Call log تیک نخورده، افزونه اصلاً در اپلیکیشن نیست (Capacitor خطای «not implemented» میدهد). window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
const Contacts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Contacts;
async function friendsWithPhones() {
if (!Contacts) return [];
const { contacts } = await Contacts.requestPermissions();
if (contacts !== 'granted') return [];
const res = await Contacts.getContacts({ projection: { name: true, phones: true } });
return res.contacts
.filter((c) => c.phones && c.phones.length)
.map((c) => ({ id: c.contactId, name: (c.name && c.name.display) || '', phone: c.phones[0].number }));
}بگذارید کاربر یک نفر را از انتخابگر سیستم انتخاب کند:
const Contacts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Contacts;
inviteBtn.onclick = async () => {
if (!Contacts) return;
try {
const { contact } = await Contacts.pickContact({ projection: { name: true, phones: true, emails: true } });
inviteField.value = (contact.emails && contact.emails[0] && contact.emails[0].address) || '';
} catch (e) {
// The user closed the picker, or refused access.
}
};یک کارت ویزیت را از اپلیکیشن در دفترچه تلفن ذخیره کنید:
const Contacts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Contacts;
async function saveCard(card) {
const perm = await Contacts.requestPermissions();
if (perm.contactsWrite !== 'granted') return null;
const { contactId } = await Contacts.createContact({ contact: {
name: { given: card.first, family: card.last },
organization: { company: card.company, jobTitle: card.title },
phones: [{ type: 'work', label: 'work', number: card.phone }],
emails: [{ type: 'work', label: 'work', address: card.email }],
} });
return contactId;
}نکتهها: pickContact() وقتی کاربر از انتخابگر خارج میشود با کد CANCELLED reject میشود. Android فقط وقتی projection بخواهد contactId، name، phones، emails، organization، birthday، note، urls، postalAddresses و image را پر میکند - فقط آنچه را نشان میدهید بخواهید. خواندن مخاطبین در Google Play یک مجوز حساس است: دلیلش را در فرم ایمنی دادههای فهرست توضیح دهید. اپلیکیشنهای ساختهشده با هوش مصنوعی از listContacts()، pickContact() و addContact() استفاده میکنند از @/lib/appmintNative.
Capacitor.Device Capacitor#
Capacitor.Plugins.Device
نمونه
افزونهٔ رسمی Capacitor Device، که در اپلیکیشن ساخته شده: مدل گوشی، نسخهٔ سیستمعامل، باتری، یک شناسهٔ ثابت و زبان.
خروجی: Promiseها. getInfo() → { model, platform, operatingSystem, osVersion, androidSDKVersion, manufacturer, isVirtual, webViewVersion, … }؛ getId() → { identifier }؛ getBatteryInfo() → { batteryLevel (0–1), isCharging }؛ getLanguageCode() → { value }. نیازمندی: چیزی برای روشنکردن لازم نیست. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
تلفن و باتری را نشان دهید.
async function showDevice() {
var cap = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Device;
if (!cap) { document.getElementById('out').textContent = navigator.userAgent; return; }
try {
var info = await cap.getInfo();
var battery = await cap.getBatteryInfo();
document.getElementById('out').textContent =
info.manufacturer + ' ' + info.model + ' - ' + info.operatingSystem + ' ' + info.osVersion +
' - battery ' + Math.round(battery.batteryLevel * 100) + '%' + (battery.isCharging ? ' (charging)' : '');
} catch (err) {
document.getElementById('out').textContent = 'Could not read device info';
}
}یک شناسهٔ ثابت و زبان.
async function helloServer() {
var cap = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Device;
if (!cap) return;
var id = (await cap.getId()).identifier;
var lang = (await cap.getLanguageCode()).value; // e.g. "en"
await fetch('https://api.example.com/hello?lang=' + encodeURIComponent(lang), {
method: 'POST', body: JSON.stringify({ device: id })
});
}در یک اپلیکیشن ساختهشده با هوش مصنوعی از بستهٔ کمکی استفاده کنید که در وب هم کار میکند:
import { Device } from '@/lib/appmintNative';
const info = await Device.getInfo();نکتهها: برای شناسهٔ ساخت اندروید، وصلهٔ امنیتی، صفحه، حافظه و شبکه، WebToApk.getDeviceInfo() پوسته جزئیات بیشتری میدهد. شناسههای افزونه شناسهٔ سختافزار نیستند؛ ممکن است بعد از بازنشانی کارخانه تغییر کنند.
Capacitor.Dialog Capacitor#
Capacitor.Plugins.Dialog — alert, confirm, prompt
نمونه
یک پنجرهٔ واقعی سیستم اندروید نشان میدهد: یک پیام، یک پرسش بله/خیر، یا یک پرسش متنی تکخطی (@capacitor/dialog 8.0.1).
خروجی: alert({ title?, message, buttonTitle? }) → Promise void. confirm({ title?, message, okButtonTitle?, cancelButtonTitle? }) → { value: boolean }. prompt({ title?, message, okButtonTitle?, cancelButtonTitle?, inputPlaceholder?, inputText? }) → { value: string, cancelled: boolean }. نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی این افزونه را دارد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var Dialog = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Dialog;
async function deleteNote(id) {
if (!Dialog) return;
var r = await Dialog.confirm({
title: 'Delete note?',
message: 'This cannot be undone.',
okButtonTitle: 'Delete',
cancelButtonTitle: 'Keep'
});
if (r.value) removeNote(id);
}هشدار و پرسش:
async function renameFlow() {
if (!Dialog) return;
await Dialog.alert({ title: 'Saved', message: 'Your changes are stored.', buttonTitle: 'OK' });
var p = await Dialog.prompt({ title: 'Rename', message: 'New name', inputText: 'Groceries', inputPlaceholder: 'List name' });
if (!p.cancelled && p.value.trim()) renameList(p.value.trim());
}در یک اپلیکیشن ساختهشده با هوش مصنوعی بستهٔ کمکی هرگز رد نمیشود: رد کردن { value: false } / { cancelled: true } است، و در وب از پنجرههای خود مرورگر استفاده میکند:
import { Dialog } from '@/lib/appmintNative';
const { value } = await Dialog.confirm({ title: 'Delete note?', message: 'This cannot be undone.' });
if (value) removeNote(id);نکتهها: message الزامی است - بدون آن افزونه با «Please provide a message for the dialog» رد میشود. پنجرهها مودال هستند؛ فقط برای تصمیمهایی استفاده کنید که باید مسدود کنند.
Capacitor.Filesystem Capacitor#
Capacitor.Plugins.Filesystem
نمونه
افزونهٔ استاندارد Capacitor Filesystem: فایلها را در حافظهٔ خود اپلیکیشن بخوانید و بنویسید (نه پوشهای که کاربر انتخاب کرده - برای آن از این استفاده کنید WebToApkFS).
خروجی: هر متد یک Promise برمیگرداند و در صورت شکست رد میشود (مثلاً خواندن فایلی که وجود ندارد). readFile → { data }، writeFile → { uri }، readdir → { files: [{ name, type, size, mtime, uri }] }، mkdir / deleteFile → هیچ. نیازمندی: چیزی برای روشنکردن لازم نیست؛ 'DATA' و 'CACHE' مجوزی نمیخواهند.
یک صفحه واردکردن Directory / Encoding ندارد، پس رشتههای ساده 'DATA' (فایلهای خصوصی اپلیکیشن، تا زمان حذف نگه داشته میشوند) یا 'CACHE' (سیستم ممکن است پاکش کند) را بدهید، و 'utf8' برای متن:
async function saveAndReadBack() {
var Fs = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Filesystem;
if (!Fs) { console.log('Filesystem plugin not available (not inside the app)'); return; }
try {
await Fs.mkdir({ path: 'notes', directory: 'DATA', recursive: true });
await Fs.writeFile({ path: 'notes/today.txt', data: 'Hello', directory: 'DATA', encoding: 'utf8', recursive: true });
var r = await Fs.readFile({ path: 'notes/today.txt', directory: 'DATA', encoding: 'utf8' });
console.log('text:', r.data);
var dir = await Fs.readdir({ path: 'notes', directory: 'DATA' });
dir.files.forEach(function (f) { console.log(f.type, f.name, f.size); }); // type: 'file' | 'directory'
await Fs.deleteFile({ path: 'notes/today.txt', directory: 'DATA' });
} catch (e) {
console.log('File error:', e.message); // e.g. the file does not exist
}
}برای نوشتن یا خواندن دادههای دودویی بهصورت base64، encoding را حذف کنید:
var Fs = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Filesystem;
var base64Data = btoa('raw bytes here'); // any base64 string, e.g. from a canvas or FileReader
if (Fs) {
Fs.writeFile({ path: 'blobs/data.bin', data: base64Data, directory: 'CACHE', recursive: true })
.then(function (w) { console.log('written to', w.uri); })
.catch(function (e) { console.log('write failed:', e.message); });
}در اپلیکیشنهای ساختهشده با هوش مصنوعی، بستهٔ کمکی @/lib/appmintNative که از این افزونه استفاده میکند fileTransfer است (دانلودها و آپلودها را در آماده میکند 'CACHE'):
import { fileTransfer } from '@/lib/appmintNative';
const r = await fileTransfer.download('https://example.com/report.pdf', 'report.pdf', {
onProgress: (p) => console.log(Math.round(p.fraction * 100) + '%'),
});
if (r.path) console.log('saved in the app at', r.path); // on the web the browser saves it insteadنکتهها: window.Capacitor فقط درون اپلیکیشن وجود دارد - همیشه پشتیبانی را تشخیص دهید. فایلهای 'DATA' خصوصی اپلیکیشناند و با حذف نصب پاک میشوند؛ برای گذاشتن فایلها جایی که کاربر ببیند، از WebToApkFS (پوشهای که کاربر مجاز میکند) یا یک دانلود استفاده کنید.
Capacitor.FileTransfer Capacitor#
Capacitor.Plugins.FileTransfer
نمونه
افزونهٔ رسمی Capacitor File Transfer: یک URL را در یک فایل روی گوشی دانلود میکند، یا یک فایل را از گوشی آپلود میکند، بهصورت بومی و با رویدادهای پیشرفت.
خروجی: downloadFile({url, path, headers?, progress?}) → Promise<{path}>؛ uploadFile({url, path, fileKey?, mimeType?, method?, headers?, progress?}) → Promise<{bytesSent, responseCode, response, headers}>. پیشرفت بهصورت رویدادهای شنوندهٔ 'progress' میرسد {type, url, bytes, contentLength, lengthComputable}. شکستها با {message, code} رد میشوند. نیازمندی: چیزی برای روشنکردن لازم نیست. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگر. همیشه وجود آن را بررسی کنید.
با نمایش پیشرفت، در کش اپلیکیشن دانلود کنید:
async function download(url, name, onPct) {
const P = window.Capacitor && window.Capacitor.Plugins;
if (!P || !P.FileTransfer || !P.Filesystem) return null; // not in the app
const target = await P.Filesystem.getUri({ path: name, directory: 'CACHE' });
const listener = await P.FileTransfer.addListener('progress', function (p) {
if (p.url === url && p.lengthComputable) onPct(Math.round(p.bytes / p.contentLength * 100));
});
try {
const r = await P.FileTransfer.downloadFile({ url: url, path: target.uri, progress: true });
return r.path;
} catch (e) {
alert('Download failed: ' + e.message);
return null;
} finally {
listener.remove();
}
}یک فایل را که از قبل روی گوشی است آپلود کنید:
const P = window.Capacitor && window.Capacitor.Plugins;
if (P && P.FileTransfer) {
P.FileTransfer.uploadFile({
url: 'https://example.com/api/upload', path: localFileUri,
fileKey: 'file', mimeType: 'image/jpeg', headers: { Authorization: 'Bearer ' + token }
}).then(function (r) { console.log('server said', r.responseCode, r.response); })
.catch(function (e) { alert('Upload failed: ' + e.message); });
}یک انتقال ناموفق را با کدش گزارش دهید:
async function safeDownload(url, target) {
const P = window.Capacitor && window.Capacitor.Plugins;
if (!P || !P.FileTransfer) { alert('Downloads need the app'); return null; }
try {
const r = await P.FileTransfer.downloadFile({ url: url, path: target });
return r.path;
} catch (e) {
console.log('transfer failed', e.code, e.message);
alert('Could not download the file.');
return null;
}
}نکتهها: مسیر باید یک مسیر فایل یا URI از نوع file:// باشد، نه یک Blob - ابتدا یک Blob را با Filesystem.writeFile در کش بنویسید. در Android 10 و قدیمیتر، یک مسیر در حافظهٔ عمومی مجوز ذخیرهگاه میخواهد. در اپلیکیشنهای ساختهشده با هوش مصنوعی، fileTransfer از @/lib/appmintNative را ترجیح دهید، که همهٔ اینها را انجام میدهد و در وب هم کار میکند.
Capacitor.FileViewer Capacitor#
Capacitor.Plugins.FileViewer
نمونه
افزونهٔ رسمی Capacitor File Viewer: یک سند یا فایل رسانه را در اپلیکیشن نمایشگر گوشی باز میکند، از یک آدرس وب، یک مسیر فایل محلی، یا فایلی که در اپلیکیشن بستهبندی شده.
خروجی: هر متد یک Promise<void> برمیگرداند که وقتی هیچ چیز نتواند فایل را باز کند با {message, code} رد میشود. نیازمندی: چیزی برای روشنکردن لازم نیست. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگر. همیشه وجود آن را بررسی کنید.
async function openPdf(url) {
const FV = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.FileViewer;
if (!FV) { window.open(url, '_blank'); return; } // a normal browser: open a tab
try {
await FV.openDocumentFromUrl({ url: url });
} catch (e) {
alert('No app on this phone can open this file.');
}
}یک فایل روی گوشی، مثلاً فایلی که با این نوشته شده Capacitor.Plugins.Filesystem:
async function openSaved(name) {
const P = window.Capacitor && window.Capacitor.Plugins;
if (!P || !P.FileViewer || !P.Filesystem) return;
const f = await P.Filesystem.getUri({ path: name, directory: 'CACHE' });
try {
await P.FileViewer.openDocumentFromLocalPath({ path: f.uri.replace(/^file:\/\//, '') });
} catch (e) {
alert('Cannot open ' + name + ': ' + e.message);
}
}openDocumentFromResources({path}) فایلی را باز میکند که در پوشهٔ assets خود APK بستهبندی شده است. همان سه متد برای ویدیو و صدا هم بهصورت previewMediaContentFromUrl، previewMediaContentFromLocalPath و previewMediaContentFromResources وجود دارند.
یک فایل را دانلود کنید و وقتی رسید آن را باز کنید:
async function downloadAndOpen(url, name) {
const P = window.Capacitor && window.Capacitor.Plugins;
if (!P || !P.FileTransfer || !P.Filesystem || !P.FileViewer) return;
const f = await P.Filesystem.getUri({ path: name, directory: 'CACHE' });
const r = await P.FileTransfer.downloadFile({ url: url, path: f.uri });
await P.FileViewer.openDocumentFromLocalPath({ path: r.path.replace(/^file:\/\//, '') });
}نکتهها: در اپلیکیشنهای ساختهشده با هوش مصنوعی، fileViewer.open(target) از @/lib/appmintNative را ترجیح دهید، که متد درست را انتخاب میکند و در وب هم کار میکند. یک مسیر محلی یک مسیر ساده است (بدون file://).
Capacitor.Geolocation Capacitor#
Capacitor.Plugins.Geolocation
نمونه
افزونهٔ رسمی Capacitor Geolocation، که در اپلیکیشن ساخته شده: موقعیت گوشی یکبار، یا بهروزرسانیهای پیوسته.
خروجی: Promiseها. getCurrentPosition(opts) → { timestamp, coords: { latitude, longitude, accuracy, altitude, speed, heading, … } }؛ watchPosition(opts, callback) → شناسهٔ پایش (یک رشته)؛ clearWatch({ id })؛ checkPermissions() / requestPermissions() → { location, coarseLocation } ('granted' | 'denied' | 'prompt' | …). نیازمندی: GPS و/یا Location در مرحله 4 (Access) - برای اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی، وقتی فایلهای شما getCurrentPosition یا watchPosition را صدا بزنند، ساخت خودش آنها را هم روشن میکند. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
یکبار موقعیتیابی، با پرسیدن از قبل.
async function whereAmI() {
var geo = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Geolocation;
if (!geo) { showMessage('Open the app to use location.'); return; }
try {
var perm = await geo.checkPermissions();
if (perm.location !== 'granted' && perm.coarseLocation !== 'granted') {
perm = await geo.requestPermissions();
if (perm.location !== 'granted' && perm.coarseLocation !== 'granted') {
showMessage('Location is off for this app.');
return;
}
}
var pos = await geo.getCurrentPosition({ enableHighAccuracy: true, timeout: 15000 });
showMessage(pos.coords.latitude.toFixed(5) + ', ' + pos.coords.longitude.toFixed(5));
} catch (err) {
showMessage('No location: ' + err.message); // location off in settings, timeout, …
}
}بهروزرسانیهای پیوسته. تابع بازخوانی دریافت میکند (position, error).
var watchId = null;
async function startTracking() {
var geo = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Geolocation;
if (!geo) return;
watchId = await geo.watchPosition({ enableHighAccuracy: true }, function (pos, err) {
if (err || !pos) return;
addPointToMap(pos.coords.latitude, pos.coords.longitude);
});
}
async function stopTracking() {
var geo = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Geolocation;
if (geo && watchId) { await geo.clearWatch({ id: watchId }); watchId = null; }
}در یک اپلیکیشن ساختهشده با هوش مصنوعی از بستهٔ کمکی استفاده کنید که در وب هم کار میکند:
import { Geolocation } from '@/lib/appmintNative';
const pos = await Geolocation.getCurrentPosition({ enableHighAccuracy: true });نکتهها: navigator.geolocation ساده در اپلیکیشن هم کار میکند. اگر کلیدهای موقعیت هنگام ساخت خاموش بودند، مجوز بدون هیچ درخواستی رد میشود. در Android 12 به بعد کاربر ممکن است فقط موقعیت تقریبی را مجاز کند (coarseLocation داده شده). موقعیت یک داده شخصی است: آن را در فرم Data safety خود در Play اعلام کنید.
Capacitor.Haptics Capacitor#
Capacitor.Plugins.Haptics
نمونه
افزونهٔ رسمی Capacitor Haptics (@capacitor/haptics)، که در اپلیکیشن ساخته شده: ضربههای سبک/متوسط/سنگین، بازخورد موفقیت/هشدار/خطا، تیکهای انتخاب و ویبره ساده.
مقدار بازگشتی: هر متد یک Promise برمیگرداند که بدون مقدار تکمیل میشود. نیازها: چیزی برای روشن کردن نیست - هر اپلیکیشن مجوز لرزش را اعلام میکند، چه لرزش در مرحلهٔ ۴ (دسترسی) تیک خورده باشد چه نه. window.Capacitor روی صفحههایی وجود دارد که خود اپلیکیشن سرو میکند (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و، در اپلیکیشن حالت وبسایت، روی سایت خودتان (دامنه و زیردامنههایش) - هرگز روی سایتهای دیگری که اپلیکیشن باز میکند. پشتیبانی را تشخیص دهید.
function haptics() {
return window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.Haptics : null;
}
async function tap(style) { // 'LIGHT' | 'MEDIUM' | 'HEAVY'
var h = haptics();
if (!h) return;
try { await h.impact({ style: style }); } catch (e) { console.log('haptics failed', e); }
}
async function result(type) { // 'SUCCESS' | 'WARNING' | 'ERROR'
var h = haptics();
if (h) { try { await h.notification({ type: type }); } catch (e) {} }
}
document.getElementById('add').addEventListener('click', function () { tap('LIGHT'); });
document.getElementById('pay').addEventListener('click', function () { result('SUCCESS'); });تیکهای انتخاب برای یک انتخابگر یا لغزنده، و یک ویبرهٔ ساده:
var h = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.Haptics : null;
var wheel = document.getElementById('wheel');
wheel.addEventListener('pointerdown', function () { if (h) h.selectionStart(); });
wheel.addEventListener('change', function () { if (h) h.selectionChanged(); });
wheel.addEventListener('pointerup', function () { if (h) h.selectionEnd(); });
document.getElementById('buzz').addEventListener('click', function () {
if (h) h.vibrate({ duration: 300 }); // milliseconds
});هنگام خطا ویبره بدهید و آن را با یک پیام قابلمشاهده همراه کنید:
var h = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Haptics;
function rejectInput(field) {
field.classList.add('invalid');
if (h) h.notification({ type: 'ERROR' }).catch(function () {});
}نکتهها: رشتهها با حروف بزرگ هستند ('HEAVY'، نه 'heavy'). در اپلیکیشنهای ساختهشده با هوش مصنوعی، import { Haptics } from '@/lib/appmintNative' همان نامها را میدهد. برای ریتمهای سفارشی با شدت برای هر ضربه، از Capacitor.Plugins.AppwrightHaptics.
Capacitor.InAppReview Capacitor#
Capacitor.Plugins.InAppReview — requestReview()
نمونه
از Google Play میخواهد برگهٔ «به این اپلیکیشن امتیاز بدهید» خودش را داخل اپلیکیشن نشان دهد. نسخهٔ همراهشده @capacitor-community/in-app-review (template/plugins/in-app-review).
خروجی: Promise void - وقتی جریان Play تمام شود حل میشود، و Play هرگز نمیگوید برگه نشان داده شد یا کاربر چه کرد. وقتی Play نتوانست جریان را شروع کند رد میشود. نیازمندی: چیزی برای روشنکردن لازم نیست؛ برای ظاهرشدن برگه، اپلیکیشن باید از Google Play نصب شده باشد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var Review = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.InAppReview;
async function afterThirdOrder() {
if (!Review) return;
try {
await Review.requestReview();
} catch (e) {
console.log('review flow not available:', e.message);
}
// continue the app flow either way — you cannot know if the user rated
}در یک اپلیکیشن ساختهشده با هوش مصنوعی:
import { requestReview } from '@/lib/appmintNative';
// after a success moment, not on launch
const asked = await requestReview(); // false where nothing could be asked (web)یکبار و بعد از یک لحظهٔ موفقیت بپرسید، و به خاطر بسپارید که پرسیدهاید:
var Review = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.InAppReview;
async function maybeAskForReview() {
if (!Review || localStorage.getItem('review_asked')) return;
localStorage.setItem('review_asked', '1');
try { await Review.requestReview(); } catch (e) { console.log('review not shown:', e.message); }
}نکتهها: Play تعداد دفعات نمایش برگه را محدود میکند و آن را برای هر فراخوانی نشان نمیدهد - هرگز پاداشی را به آن گره نزنید و هرگز از یک دکمهٔ «به ما امتیاز دهید» با انتظار بازشدن آن نپرسید (برای آن صفحهٔ فروشگاه را باز کنید). بعد از یک لحظهٔ موفقیت بپرسید، نه هنگام شروع. نصب دستی یا اشکالزدایی معمولاً چیزی نشان نمیدهد.
Capacitor.KeepAwake Capacitor#
Capacitor.Plugins.KeepAwake — keepAwake(), allowSleep(), isKeptAwake(), isSupported()
نمونه
وقتی چیزی باید دیده شود - یک دستور پخت، یک مسیر، یک کد QR، یک تایمر - مانع کمنورشدن و قفلشدن صفحه میشود. نسخهٔ همراهشده @capacitor-community/keep-awake (template/plugins/keep-awake).
خروجی: keepAwake() / allowSleep() → Promise void. isKeptAwake() → { isKeptAwake: boolean }. isSupported() → { isSupported: true }. نیازمندی: هیچ - هر اپلیکیشنی این افزونه را دارد؛ مجوزی لازم نیست. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var KA = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.KeepAwake;
async function startCooking() {
if (KA) await KA.keepAwake();
showSteps();
}
async function stopCooking() {
if (KA) await KA.allowSleep(); // always release when the view closes
}
if (KA) KA.isKeptAwake().then(function (r) { console.log('awake?', r.isKeptAwake); });در یک اپلیکیشن ساختهشده با هوش مصنوعی (Screen Wake Lock API در وب):
import { keepAwake } from '@/lib/appmintNative';
useEffect(() => {
void keepAwake(true);
return () => { void keepAwake(false); };
}, []);صفحه را فقط تا وقتی تایمر اجرا میشود روشن نگه دارید:
var KA = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.KeepAwake;
async function runTimer(seconds) {
if (KA) await KA.keepAwake();
await new Promise(function (done) { setTimeout(done, seconds * 1000); });
if (KA) await KA.allowSleep();
alert('Time is up');
}نکتهها: این پرچم به پنجرهٔ اپلیکیشن تعلق دارد: فقط وقتی اپلیکیشن جلوی صفحه است کار میکند و تا allowSleep() روشن میماند - در هر خروج از صفحه آن را آزاد کنید. keepAwake() وقتی هیچ چیز نتواند صفحه را روشن نگه دارد false برمیگرداند.
Capacitor.Keyboard Capacitor#
Capacitor.Plugins.Keyboard — show(), hide(), addListener('keyboardDidShow' | ...)
نمونه
صفحهکلید نرمافزاری را باز یا بسته میکند و به صفحه میگوید چه زمانی ظاهر میشود و چقدر بلند است (@capacitor/keyboard 8.0.5).
خروجی: show() / hide() → Promise void. addListener(event, fn) → یک Promise از یک دستگیره با remove()، مانند API خود Capacitor - آن را await کنید یا .then() را زنجیر کنید؛ مقدار برگشتی خودش هم remove() دارد؛ رویدادهای نمایش { keyboardHeight } را به پیکسل CSS میفرستند. رویدادها: keyboardWillShow، keyboardDidShow، keyboardWillHide، keyboardDidHide. نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی این افزونه را دارد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var Keyboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Keyboard;
if (Keyboard) {
Keyboard.addListener('keyboardDidShow', function (info) {
console.log('keyboard height', info.keyboardHeight);
document.body.classList.add('typing'); // e.g. hide the bottom tab bar
});
Keyboard.addListener('keyboardDidHide', function () {
document.body.classList.remove('typing');
});
}
function onSend() {
if (Keyboard) Keyboard.hide().catch(function () {}); // rejects if no field is focused
}در یک اپلیکیشن ساختهشده با هوش مصنوعی برای چیدمان از onKeyboard() استفاده کنید - فقط بخشی از صفحهکلید را گزارش میدهد که صفحهٔ تغییراندازهیافته هنوز آزاد نکرده - و برای بستن آن از hideKeyboard():
import { onKeyboard, hideKeyboard, Keyboard } from '@/lib/appmintNative';
const off = onKeyboard((px) => { composer.style.paddingBottom = `${px}px`; }); // call off() on unmount
hideKeyboard();
const h = Keyboard.addListener('keyboardWillShow', ({ keyboardHeight }) => console.log(keyboardHeight));
h.remove();پس از لمس یک دکمه، صفحهکلید را برای یک فیلد نشان دهید:
var Keyboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Keyboard;
searchBtn.addEventListener('click', function () {
searchInput.focus();
if (Keyboard) Keyboard.show().catch(function () {});
});نکتهها: پوسته از قبل صفحه را برای صفحهکلید تغییراندازه میدهد، پس keyboardHeight کامل را بهعنوان فاصله اضافه نکنید - یک نوار پایینی از قبل بالای کلیدهاست. setAccessoryBarVisible، setStyle، setResizeMode و setScroll در اندروید پیادهسازی نشدهاند - آنها را صدا نزنید. hide() وقتی هیچ چیز فوکوس ندارد با «Can't close keyboard, not currently focused» رد میشود.
Capacitor.LocalNotifications Capacitor#
Capacitor.Plugins.LocalNotifications — schedule, cancel, getPending, requestPermissions, events
نمونه
اعلانهایی که خود اپلیکیشن ارسال میکند - همین حالا یا در یک زمان - با API رسمی @capacitor/local-notifications (com.capacitorjs:local-notifications). کدی که برای بستهٔ npm نوشته شده بدون تغییر کار میکند.
خروجی: requestPermissions() / checkPermissions() → { display: 'granted' | 'denied' | 'prompt' }؛ schedule({ notifications: [{ id, title, body, schedule?: { at | on | every }, extra?, actionTypeId?, channelId? }] }) → { notifications: [{ id }] }؛ getPending() → { notifications }؛ cancel({ notifications: [{ id }] })؛ registerActionTypes({ types })؛ createChannel / listChannels / deleteChannel؛ checkExactNotificationSetting() → { exact_alarm }. رویدادها: localNotificationReceived، localNotificationActionPerformed (actionId برای لمس خود اعلان 'tap' است). نیازمندی: Notifications را در مرحله 4 (Access) تیک بزنید - بدون آن افزونه در اپلیکیشن نیست و هر فراخوانی با «not implemented» رد میشود. برای اعلانهای زماندار ⏰ Reminders را هم تیک بزنید (زمانبندی دقیق و ماندن پس از راهاندازی مجدد). ساختهای HTML، ZIP و AI-Studio وقتی کد @capacitor/local-notifications را وارد میکند و LocalNotifications.schedule( را صدا میزند، خودشان هر دو را تیک میزنند. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
const LN = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.LocalNotifications;
async function remindIn(minutes, text) {
if (!LN) return false;
const { display } = await LN.requestPermissions();
if (display !== 'granted') return false;
await LN.schedule({ notifications: [{
id: Date.now() % 2147483647,
title: 'Reminder',
body: text,
schedule: { at: new Date(Date.now() + minutes * 60000), allowWhileIdle: true },
extra: { screen: 'tasks' },
}] });
return true;
}وقتی کاربر یک اعلان را لمس میکند، صفحهٔ درست را باز کنید - حتی وقتی لمس اپلیکیشن را شروع کرده، چون رویداد منتظر شنونده میماند:
const LN = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.LocalNotifications;
if (LN) {
LN.addListener('localNotificationActionPerformed', ({ actionId, notification }) => {
if (actionId === 'tap' && notification.extra && notification.extra.screen) {
location.hash = '#/' + notification.extra.screen;
}
});
}یک یادآور عادت روزانه با دکمههای انجام شد / بعداً:
const LN = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.LocalNotifications;
async function dailyWaterReminder() {
await LN.registerActionTypes({ types: [{ id: 'water', actions: [
{ id: 'done', title: 'Done' },
{ id: 'snooze', title: 'In 30 min' },
] }] });
await LN.schedule({ notifications: [{
id: 42, title: 'Drink water', body: 'Time for a glass of water.',
actionTypeId: 'water', schedule: { on: { hour: 10, minute: 0 }, repeats: true },
}] });
LN.addListener('localNotificationActionPerformed', ({ actionId }) => {
if (actionId === 'snooze') {
LN.schedule({ notifications: [{ id: 43, title: 'Drink water', body: 'Snoozed reminder.',
schedule: { at: new Date(Date.now() + 30 * 60000) } }] });
}
});
}نکتهها: در Android 12 به بعد، یک اعلان زماندار به مجوز آلارم دقیق نیاز دارد: اولین schedule() ممکن است صفحهٔ سیستم «Alarms & reminders» را باز کند؛ اگر کاربر آن را خاموش بگذارد، اعلان باز هم کمی دیرتر نمایش داده میشود (نتیجه یک warning دارد). اعلانهای افزونه از کانال «Default» خودشان استفاده میکنند، جدا از اعلانهای دیگر اپلیکیشن. یک sound از فایلهای وب پشتیبانی نمیشود (Android صدای پیشفرض کانال را پخش میکند). وقتی اپلیکیشن PIN دارد، لمسها از طریق صفحهٔ قفل به صفحه میرسند. اپلیکیشنهای ساختهشده با هوش مصنوعی از notify() / LocalNotifications.schedule در @/lib/appmintNative استفاده میکنند که از طریق پشتهٔ اعلان خود اپلیکیشن ارسال میکند.
Capacitor.Network Capacitor#
Capacitor.Plugins.Network — getStatus(), addListener('networkStatusChange')
نمونه
به صفحه میگوید گوشی آنلاین است یا نه و روی چه نوع اتصالی، و وقتی آن تغییر میکند (@capacitor/network 8.0.1).
خروجی: getStatus() → Promise { connected: boolean, connectionType: 'wifi' | 'cellular' | 'none' | 'unknown' }. رویداد networkStatusChange همان شکل را میدهد. نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی این افزونه را دارد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var Network = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Network;
function showBanner(s) {
document.getElementById('offline').hidden = s.connected;
}
if (Network) {
Network.getStatus().then(showBanner);
Network.addListener('networkStatusChange', function (s) {
showBanner(s);
if (s.connected) retryQueuedWrites();
if (s.connectionType === 'cellular') console.log('on mobile data');
});
}در یک اپلیکیشن ساختهشده با هوش مصنوعی:
import { Network, networkStatus, onNetworkChange } from '@/lib/appmintNative';
const { connected, connectionType } = await Network.getStatus();
const now = networkStatus(); // sync: { connected, type }
const off = onNetworkChange((s) => setOnline(s.connected)); // call off() on unmountیک آپلود بزرگ را روی دادههای موبایل متوقف کنید:
var Network = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Network;
async function canUploadVideo() {
if (!Network) return navigator.onLine;
var s = await Network.getStatus();
if (!s.connected) return false;
return s.connectionType === 'wifi' || confirm('Upload over mobile data?');
}نکتهها: connected یعنی گوشی شبکه دارد، نه اینکه سرور شما پاسخ میدهد - همچنان درخواستهای ناموفق را مدیریت کنید. Network.getStatus() و networkStatus() بستهٔ کمکی از navigator.onLine / navigator.connection میخوانند، نه از افزونه، پس نوع آنها میتواند 'unknown' یا یک کلاس سرعت مثل '4g' باشد؛ onNetworkChange() در اپلیکیشن از رویداد افزونه استفاده میکند.
Capacitor.Preferences Capacitor#
Capacitor.Plugins.Preferences — get / set / remove / keys / clear
نمونه
یک ذخیرهگاه کوچک کلید-مقدار بومی (Android SharedPreferences) برای رشتهها (@capacitor/preferences 8.0.1).
خروجی: set({ key, value })، remove({ key })، clear() → Promise void؛ get({ key }) → { value } (null وقتی کلید وجود ندارد)؛ keys() → { keys: string[] }. نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی این افزونه را دارد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var Prefs = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Preferences;
async function saveTheme(name) {
if (!Prefs) return false; // not inside the app
await Prefs.set({ key: 'theme', value: name });
return true;
}
async function loadTheme() {
if (!Prefs) return null;
var r = await Prefs.get({ key: 'theme' });
return r.value; // null if never saved
}اشیا باید ابتدا به رشته تبدیل شوند:
async function saveUser() {
if (!Prefs) return;
await Prefs.set({ key: 'user', value: JSON.stringify({ id: 7, name: 'Asha' }) });
var u = JSON.parse((await Prefs.get({ key: 'user' })).value || 'null');
var all = (await Prefs.keys()).keys;
await Prefs.remove({ key: 'user' });
}کلیدهای ذخیرهشده را از یک صفحهٔ تنظیمات فهرست و پاک کنید:
async function resetSettings() {
if (!Prefs) return;
var k = (await Prefs.keys()).keys;
console.log('clearing', k.length, 'saved values');
await Prefs.clear();
}نکتهها: @/lib/appmintNative عمداً هیچ بستهٔ Preferences ندارد: localStorage در اپلیکیشن از قبل واقعی و پایدار است و یک ذخیرهگاه دوم دادههای یک اپلیکیشن را بین دو جا تقسیم میکند. اپلیکیشنهای ساختهشده با هوش مصنوعی باید همچنان از localStorage (یا زمان اجرای داده) استفاده کنند. فقط اگر میخواهید همهٔ تنظیمات شما آنجا باشد، در یک صفحهٔ دستنویس از Preferences استفاده کنید و برای هر مقدار یک ذخیرهگاه انتخاب کنید. configure({ group }) نام ذخیرهگاه را عوض میکند (پیشفرض CapacitorStorage).
Capacitor.PrivacyScreen Capacitor#
Capacitor.Plugins.PrivacyScreen — enable(), disable(), isEnabled()
نمونه
افزونهٔ رسمی @capacitor/privacy-screen: از اسکرینشات و ضبط صفحه جلوگیری میکند و محتوای اپلیکیشن را در نمای اپلیکیشنهای اخیر پنهان میکند. همراهشده تا پروژههای واردشدهٔ Capacitor که آن را صدا میزنند کار کنند.
خروجی: enable({android}) → {success}؛ disable() → {success}؛ isEnabled() → {enabled}. نیازمندی: چیزی برای روشنکردن لازم نیست.
const Privacy = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.PrivacyScreen;
async function openVault() {
if (Privacy) await Privacy.enable({ android: { privacyModeOnActivityHidden: 'dim' } });
showVault();
}
async function closeVault() {
if (Privacy) await Privacy.disable();
}پیش از تغییر، وضعیت فعلی را بررسی کنید:
async function toggleProtection() {
if (!Privacy) return;
var s = await Privacy.isEnabled();
if (s.enabled) await Privacy.disable();
else await Privacy.enable();
}صفحه را فقط تا وقتی یک نمای حساس باز است محافظت کنید:
async function showCardNumber() {
if (Privacy) await Privacy.enable({ android: { privacyModeOnActivityHidden: 'splash' } });
cardBox.hidden = false;
}
async function hideCardNumber() {
cardBox.hidden = true;
if (Privacy) await Privacy.disable();
}نکتهها: privacyModeOnActivityHidden: 'none'، 'dim' یا 'splash'. کدی که برای خود اپلیکیشن نوشته میشود باید از WebToApk.setSecureScreen(true) / privacyScreen.enable() در @/lib/appmintNative استفاده کند که از صفحه پیروی میکند (وقتی اپلیکیشن از آن خارج میشود آزاد میشود)؛ با ترکیب هر دو، آخرین فراخوانی برنده است.
Capacitor.PushNotifications Capacitor#
Capacitor.Plugins.PushNotifications — register, requestPermissions, registration, pushNotificationReceived
نمونه
اعلانهای push از سرور خودتان و از طریق پروژهٔ Firebase خودتان، با API رسمی @capacitor/push-notifications (com.capacitorjs:push-notifications، ثبتشده توسط PushNotificationsPlugin.kt پوسته). کدی که برای بستهٔ npm نوشته شده بدون تغییر کار میکند: register()، سپس با Firebase Admin SDK یا FCM HTTP v1 API به توکن رویداد registration بفرستید.
خروجی: requestPermissions() / checkPermissions() → { receive: 'granted' | 'denied' | 'prompt' }؛ register() / unregister() → void (توکن بهصورت رویداد registration { value } میرسد، شکست بهصورت registrationError { error })؛ getDeliveredNotifications() → { notifications }؛ removeDeliveredNotifications({ notifications })، removeAllDeliveredNotifications()؛ createChannel({ id, name, importance? })، listChannels()، deleteChannel({ id }). رویدادها: pushNotificationReceived (یک پیام وقتی اپلیکیشن باز است: { id, title?, body?, data }) و pushNotificationActionPerformed ({ actionId: 'tap', notification: { id, data } }). نیازمندی: با روشنبودن AppMint Push بسازید و google-services.json خود را بارگذاری کنید (مرحلهٔ اعلانها) - این همان پروژهٔ Firebase است که توکن به آن تعلق دارد. بدون آن، register() با کد PUSH_NOT_CONFIGURED («Push is not set up in this app») رد میشود. ساختهای HTML، ZIP و AI-Studio وقتی کد PushNotifications.register( / requestPermissions( / addListener( را صدا میزند، خودشان Notifications را تیک میزنند. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
const Push = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.PushNotifications;
async function enablePush(userId) {
if (!Push) return;
await Push.addListener('registration', ({ value }) => {
// Your server stores the token and sends to it later.
fetch('https://api.example.com/push-tokens', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userId, token: value, platform: 'android' }),
});
});
await Push.addListener('registrationError', ({ error }) => console.warn('push:', error));
const { receive } = await Push.requestPermissions();
if (receive !== 'granted') return;
try { await Push.register(); }
catch (e) { if (e.code === 'PUSH_NOT_CONFIGURED') alert('Push is not set up in this build.'); }
}به یک پیام وقتی اپلیکیشن باز است واکنش نشان دهید، و به لمس پیامی که در زمان بستهبودن اپلیکیشن رسیده (رویداد لمس منتظر شنوندهٔ شما میماند، پس راهاندازی سرد از دست نمیرود):
const Push = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.PushNotifications;
if (Push) {
Push.addListener('pushNotificationReceived', (msg) => {
alert((msg.title || 'New message') + (msg.body ? ': ' + msg.body : ''));
});
Push.addListener('pushNotificationActionPerformed', ({ notification }) => {
const orderId = notification.data && notification.data.orderId;
if (orderId) location.hash = '#/orders/' + orderId;
});
}یک کانال برای هشدارهای مهم (Android 8 به بعد)، که پیامهایی که در آن نامش را ببرند استفاده میکنند android.notification.channel_id:
const Push = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.PushNotifications;
async function setupChannels() {
if (!Push) return;
await Push.createChannel({ id: 'orders', name: 'Order updates', description: 'Your order status', importance: 4, vibration: true });
}نکتهها: پیامی که با بلوک notification فرستاده شود وقتی اپلیکیشن در پسزمینه است توسط خود Android نمایش داده میشود؛ لمس آن اپلیکیشن را باز میکند (اگر اپلیکیشن PIN دارد از طریق صفحهٔ قفل) و pushNotificationActionPerformed را اجرا میکند. وقتی اپلیکیشن باز است، پیامها بهصورت pushNotificationReceived میرسند و در سینی رسم نمیشوند. پیامهای فقطداده فقط وقتی صفحه باز است به آن میرسند. پیامهای AppMint Push کنار هم کار میکنند - هرگز به این افزونه نمیرسند. در اپلیکیشنی که بهجای AppMint Push با OneSignal ساخته شده، پیامها را OneSignal تحویل میدهد و هرگز به این افزونه نمیرسند. اپلیکیشنهای ساختهشده با هوش مصنوعی push سازنده را از طریق pushInbox() دریافت میکنند از @/lib/appmintNative.
Capacitor.ScreenBrightness Capacitor#
Capacitor.Plugins.ScreenBrightness — getBrightness(), setBrightness({ brightness })
نمونه
روشنایی صفحهٔ پنجرهٔ اپلیکیشن را تنظیم میکند - روشنایی کامل برای بلیت پرواز یا کد QR و سپس بازگشت. نسخهٔ همراهشده @capacitor-community/screen-brightness (template/plugins/screen-brightness).
خروجی: getBrightness() → Promise { brightness } (0 تا 1، یا -1 وقتی اپلیکیشن آن را تغییر نداده و صفحه از سیستم پیروی میکند). setBrightness({ brightness }) → Promise void. نیازمندی: هیچ - هر اپلیکیشنی این افزونه را دارد؛ مجوزی لازم نیست (فقط پنجرهٔ همین اپلیکیشن را تغییر میدهد، نه تنظیم سیستم). window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var SB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenBrightness;
async function showTicket() {
if (SB) await SB.setBrightness({ brightness: 1 }); // full brightness
document.getElementById('qr').hidden = false;
}
async function hideTicket() {
if (SB) await SB.setBrightness({ brightness: -1 }); // -1 = follow the system again
document.getElementById('qr').hidden = true;
}در یک اپلیکیشن ساختهشده با هوش مصنوعی:
import { brightness } from '@/lib/appmintNative';
await brightness.set(1); // clamped to 0–1; false where not available (web)
// ... on leaving the screen
await brightness.restore();
const level = await brightness.get(); // -1 = following the system / not availableابتدا سطح فعلی را بخوانید و دقیقاً همان را بازگردانید:
var SB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenBrightness;
var before = -1;
async function boost() {
if (!SB) return;
before = (await SB.getBrightness()).brightness;
await SB.setBrightness({ brightness: 1 });
}
async function undo() {
if (SB) await SB.setBrightness({ brightness: before });
}نکتهها: همیشه یک عدد بدهید - setBrightness({}) مقداری برای اعمال ندارد. وقتی نما بسته میشود با -1 بازگردانید؛ بازنویسی با بستهشدن اپلیکیشن هم پایان مییابد. یک صفحهٔ وب نمیتواند نور پسزمینه را کنترل کند، پس can('brightness') در مرورگر 'none' است.
Capacitor.ScreenOrientation Capacitor#
Capacitor.Plugins.ScreenOrientation — orientation(), lock({ orientation }), unlock()
نمونه
جهت صفحه را میخواند، آن را برای یک نمایش (یک بازی، یک نمودار، یک پد امضا) قفل میکند و دوباره آزاد میکند (@capacitor/screen-orientation 8.0.1).
خروجی: orientation() → Promise { type } (مثلاً 'portrait-primary'). lock() / unlock() → Promise void. رویداد screenOrientationChange { type } را میدهد. نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی این افزونه را دارد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
orientation مقادیر: 'portrait', 'landscape', 'portrait-primary', 'portrait-secondary', 'landscape-primary', 'landscape-secondary', 'natural', 'any'.
var SO = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenOrientation;
async function openChart() {
if (SO) await SO.lock({ orientation: 'landscape' });
showChart();
}
async function closeChart() {
if (SO) await SO.unlock(); // always release when leaving the view
hideChart();
}
if (SO) {
SO.orientation().then(function (o) { console.log('now', o.type); });
SO.addListener('screenOrientationChange', function (o) { console.log('rotated to', o.type); });
}در یک اپلیکیشن ساختهشده با هوش مصنوعی:
import { lockOrientation, ScreenOrientation } from '@/lib/appmintNative';
const ok = await lockOrientation('landscape'); // false when refused (always on desktop)
await lockOrientation('any'); // release
await ScreenOrientation.lock({ orientation: 'portrait' });
await ScreenOrientation.unlock();قفل ردشده را مدیریت کنید و به کاربر بگویید:
var SO = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenOrientation;
var Toast = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Toast;
async function tryLandscape() {
if (!SO) { document.getElementById('rotate-hint').hidden = false; return; } // ask the user to rotate by hand
try {
await SO.lock({ orientation: 'landscape' });
} catch (e) {
if (Toast) Toast.show({ text: 'Could not rotate the screen', duration: 'short' });
}
}نکتهها: بستههای کمکی فقط portrait / landscape / any را میشناسند: ScreenOrientation.lock({ orientation: 'landscape-secondary' }) به landscape ساده قفل میشود. به کاربر راهی برای خروج از یک نمای قفلشده بدهید.
Capacitor.ScreenReader Capacitor#
Capacitor.Plugins.ScreenReader — isEnabled(), speak({ value, language }), addListener('stateChange')
نمونه
به صفحه میگوید TalkBack روشن است یا نه، و یک اعلان را میخواند (@capacitor/screen-reader 8.0.1).
خروجی: isEnabled() → Promise { value: boolean }. speak() → Promise void. رویداد stateChange وقتی TalkBack روشن یا خاموش میشود { value: boolean } را میدهد. نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی این افزونه را دارد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var SR = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenReader;
function setCalmMode(on) {
document.documentElement.classList.toggle('no-motion', on); // shorten animations
}
if (SR) {
SR.isEnabled().then(function (r) { setCalmMode(r.value); });
SR.addListener('stateChange', function (s) { setCalmMode(s.value); });
}
async function announceSaved() {
if (SR) await SR.speak({ value: 'Order placed', language: 'en' });
}در یک اپلیکیشن ساختهشده با هوش مصنوعی (speak در وب از تبدیل متن به گفتار استفاده میکند؛ isEnabled() در آنجا false است):
import { screenReader } from '@/lib/appmintNative';
const on = await screenReader.isEnabled();
const off = screenReader.onChange((enabled) => setCalmMode(enabled));
await screenReader.speak('Order placed', 'en');وجود افزونه را بررسی کنید و صفحه را بدون آن قابلاستفاده نگه دارید:
var SR = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenReader;
async function say(message) {
if (SR) { await SR.speak({ value: message }); return; }
document.getElementById('live-region').textContent = message; // an aria-live="polite" element
}نکتهها: language بهطور پیشفرض 'en' است. برای بیشتر اعلانها نشانهگذاری معمولی و دسترسپذیر (برچسبها، ناحیههای aria-live) را ترجیح دهید؛ از speak برای تغییر وضعیتهای کوتاه و مهم استفاده کنید. هیچ API وبی برای تشخیص صفحهخوان وجود ندارد، پس can('screenReader') در مرورگر 'none' است.
Capacitor.SpeechRecognition Capacitor#
Capacitor.Plugins.SpeechRecognition
نمونه
گفتار کاربر را با تشخیصدهندهٔ گفتار اندروید به متن تبدیل میکند (افزونهٔ جامعهٔ @capacitor-community/speech-recognition که در اپلیکیشن ساخته شده است). Android WebView تشخیص گفتار Web Speech خودش را ندارد، پس این راه دیکتهکردن است.
خروجی: Promiseها. available() → { available }. checkPermissions() / requestPermissions() → { speechRecognition: 'granted' | 'denied' | 'prompt' }. start({ partialResults: false }) → { status: 'success', matches: [...] } بعد از اینکه کاربر حرفزدن را متوقف کند؛ با خطاهایی مثل نبود گفتار یا نبود تطبیق رد میشود. نیازمندی: هنگام ساخت Mic را در مرحله 4 (Access) تیک بزنید (برای اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی، وقتی فایلهای شما SpeechRecognition را ذکر کنند، ساخت خودش مجوز میکروفون را هم اضافه میکند)، و کاربر باید میکروفون را مجاز کند. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
دیکتهٔ یکباره (همانطور که @/lib/appmintNative speech از آن استفاده میکند):
var SR = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.SpeechRecognition : null;
async function dictate() {
var out = document.getElementById('text');
if (!SR || !(await SR.available()).available) { out.textContent = 'Voice input is not available on this phone.'; return; }
var p = (await SR.checkPermissions()).speechRecognition;
if (p !== 'granted') p = (await SR.requestPermissions()).speechRecognition;
if (p !== 'granted') { out.textContent = 'Microphone permission was not given.'; return; }
try {
var r = await SR.start({ language: 'en-US', maxResults: 3, partialResults: false, popup: false });
out.textContent = r.matches && r.matches.length ? r.matches[0] : '';
} catch (e) {
out.textContent = 'Did not catch that. Try again.';
}
}
document.getElementById('mic').addEventListener('click', dictate);متن زنده در حین صحبت کاربر (partialResults: true)، و وضعیت شنیدن:
// Add the listeners ONCE, when the page starts.
if (SR) {
SR.addListener('partialResults', function (d) {
// Words as they come, and then the final text, all arrive here.
if (d.matches && d.matches.length) document.getElementById('text').textContent = d.matches[0];
});
SR.addListener('listeningState', function (d) {
// 'started' = the user began speaking, 'stopped' = the user stopped speaking
document.body.classList.toggle('listening', d.status === 'started');
});
}
document.getElementById('mic-live').addEventListener('click', async function () {
if (!SR) return;
try {
await SR.start({ language: 'en-US', partialResults: true, popup: false }); // resolves at once, no matches
} catch (e) {
document.getElementById('text').textContent = 'Could not start: ' + e.message;
}
});
document.getElementById('stop').addEventListener('click', function () { if (SR) SR.stop(); });دکمهٔ میکروفون را فقط وقتی نشان دهید که دیکته کار میکند، و وقتی صفحه پنهان شد گوش دادن را متوقف کنید:
var SR = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.SpeechRecognition : null;
var mic = document.getElementById('mic');
mic.hidden = true;
if (SR) {
SR.available().then(function (r) { mic.hidden = !r.available; });
}
document.addEventListener('visibilitychange', function () {
if (document.hidden && SR) SR.stop();
});نکتهها:
- در حالت زنده (
partialResults: true)، متن نهایی بعد از وضعیت'stopped'میرسد، پس شنوندهٔpartialResultsرا در'stopped'حذف نکنید. خطایی بعد از شروع (بدون گفتار، بدون تطبیق) در این حالت گزارش نمیشود. languageیک برچسب مانند'en-US'یا'ta-IN'است (پیشفرض: زبان گوشی).popup: trueبهجای آن، پنجرهٔ شنیدن خود Google را نشان میدهد.getSupportedLanguages()→{ languages }وisListening()→{ listening }هم وجود دارند.start()اگر ابتدا نپرسیده باشید با'Missing permission'رد میشود. شنیدن بعد از یک مکث در گفتار خودش متوقف میشود.
Capacitor.SplashScreen Capacitor#
Capacitor.Plugins.SplashScreen — show(), hide()
نمونه
API مربوط به @capacitor/splash-screen روی صفحهٔ شروع برنددار خود اپلیکیشن، تا پروژههای واردشدهٔ Capacitor / AI Studio که وقتی صفحهٔ اولشان آماده شد SplashScreen.hide() را صدا میزنند، در اپلیکیشن اندروید کار کنند.
خروجی: hide() → Promise (صفحهٔ شروع بعد از گذشت حداقل زمان صفحهٔ شروعِ سازنده میرود)؛ show({showDuration, autoHide}) → Promise (صفحهٔ شروع روی صفحه برمیگردد و با autoHide - که پیشفرض است - بعد از showDuration میلیثانیه، پیشفرض 3000، میرود). نیازمندی: چیزی برای روشنکردن لازم نیست.
const Splash = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.SplashScreen;
async function boot() {
await loadFirstScreen();
if (Splash) await Splash.hide(); // otherwise the shell hides it at first paint
}
boot();یک تعویض حساب کند را با صفحهٔ شروع بپوشانید و تا نمایش دادههای جدید روی صفحه نگه دارید:
const Splash = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.SplashScreen;
async function switchAccount(accountId) {
if (Splash) await Splash.show({ autoHide: false }); // stays until hide()
try {
await loadAccount(accountId);
renderHome();
} finally {
if (Splash) await Splash.hide();
}
}پس از خروج از حساب، صفحهٔ شروع برنددار را برای یک لحظه نشان دهید؛ خودش بعد از showDuration:
const Splash = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.SplashScreen;
async function signOut() {
await clearSession();
showSignInScreen();
if (Splash) {
try {
await Splash.show({ showDuration: 1200 });
} catch (e) {
console.warn('splash not shown:', e.code);
}
}
}نکتهها: بدون فراخوانی hide()، صفحهٔ شروع باز هم در اولین رسم صفحه میرود، مثل هر اپلیکیشن. اپلیکیشنهای ساختهشده با هوش مصنوعی از splash.hold() / splash.ready() از استفاده میکنند @/lib/appmintNative.
Capacitor.StatusBar Capacitor#
Capacitor.Plugins.StatusBar — setStyle, setBackgroundColor, show, hide, getInfo
نمونه
سبک آیکن، رنگ و نمایانبودن نوار وضعیت را تغییر میدهد (@capacitor/status-bar 8.0.2).
خروجی: هر متد → Promise void، بهجز getInfo() → { visible, style, color, overlays, height }. نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی این افزونه را دارد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
style پسزمینهای را که مناسبش است نام میبرد: 'DARK' = آیکونهای روشن (برای نوار تیره)، 'LIGHT' = آیکونهای تیره، 'DEFAULT' = پیروی از سیستم.
var StatusBar = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.StatusBar;
if (StatusBar) {
StatusBar.setStyle({ style: 'DARK' }); // light icons
StatusBar.hide(); // e.g. while a video plays
// later
StatusBar.show();
}نوار را با پل پوسته رنگ کنید، نه با افزونه. در Android 15 به بعد، setBackgroundColor افزونه کاری نمیکند (حالت لبهبهلبه آن را نادیده میگیرد). پوسته خود نوار را رنگ میکند و سبک آیکن را در همان فراخوانی میگیرد:
if (window.WebToApk && window.WebToApk.setStatusBarColor) {
window.WebToApk.setStatusBarColor('#0B0F1A', 'light'); // dark bar, light icons
} else if (StatusBar) {
StatusBar.setBackgroundColor({ color: '#0B0F1A' }); // hex only, e.g. #RRGGBB
}در یک اپلیکیشن ساختهشده با هوش مصنوعی از setStatusBar(color, contentStyle) استفاده کنید؛ پل پوسته را ترجیح میدهد و رنگ و آیکنها را در یک فراخوانی تنظیم میکند:
import { setStatusBar, StatusBar } from '@/lib/appmintNative';
setStatusBar('#0B0F1A', 'light'); // dark bar, light icons
await StatusBar.setBackgroundColor({ color: '#FFFFFF' }); // colour only; icons picked from luminanceنکتهها: setBackgroundColor رنگی را که رشتهٔ هگز نباشد رد میکند. در ساختهای تمامصفحه / کیوسک، نوارها توسط پوسته پنهان میشوند. در اپلیکیشن اندروید، StatusBar.setStyle() بستهٔ کمکی بهتنهایی چیزی را تغییر نمیدهد (پل برای رنگکردن به یک رنگ نیاز دارد) - سبک را همراه با یک رنگ به setStatusBar() بدهید.
Capacitor.TextToSpeech Capacitor#
Capacitor.Plugins.TextToSpeech — speak(), stop(), getSupportedLanguages(), getSupportedVoices()
نمونه
افزونهٔ جامعه @capacitor-community/text-to-speech روی موتور تبدیل متن به گفتار گوشی. داخل ساخته شده تا پروژههای Capacitor واردشده که آن را فراخوانی میکنند کار کنند.
خروجی: speak({text, lang, rate, pitch, volume, voice}) → Promise که وقتی جمله خوانده شد حل میشود؛ stop()؛ getSupportedLanguages() → {languages}؛ getSupportedVoices() → {voices}؛ isLanguageSupported({lang}) → {supported}. نیازمندی: چیزی برای روشنکردن لازم نیست.
const Tts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextToSpeech;
async function readAloud(text) {
if (!Tts) { speechSynthesis.speak(new SpeechSynthesisUtterance(text)); return; }
await Tts.speak({ text: text, lang: 'en-US', rate: 1.0, pitch: 1.0, volume: 1.0 });
}
document.getElementById('stop').onclick = () => Tts && Tts.stop();زبان را پیش از خواندن بررسی کنید و وقتی نصب نیست پیام نشان دهید:
const Tts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextToSpeech;
async function speakIn(lang, text) {
if (!Tts) return false;
const { supported } = await Tts.isLanguageSupported({ lang: lang });
if (!supported) { showMessage('This phone has no ' + lang + ' voice installed.'); return false; }
await Tts.speak({ text: text, lang: lang });
return true;
}یک پاراگراف را با دکمهٔ توقف بلند بخوانید و خطای خواندن را مدیریت کنید:
const Tts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextToSpeech;
async function readParagraph(el, btn) {
if (!Tts) return;
btn.textContent = 'Stop';
btn.onclick = () => Tts.stop();
try {
await Tts.speak({ text: el.textContent, lang: 'en-US', rate: 0.9 }); // resolves when finished
} catch (e) {
console.warn('could not speak:', e.message);
} finally {
btn.textContent = 'Listen';
btn.onclick = () => readParagraph(el, btn);
}
}نکتهها: window.speechSynthesis در اپلیکیشن هم کار میکند (موتور خود پوسته) و همان چیزی است که اپلیکیشنهای ساختهشده با هوش مصنوعی از طریق speak() استفاده میکنند؛ این افزونه مسیر با شکل Capacitor است.
Capacitor.TextZoom Capacitor#
Capacitor.Plugins.TextZoom — get(), getPreferred(), set({ value })
نمونه
اندازهٔ متن صفحهٔ اپلیکیشن را میخواند و تغییر میدهد، برای یک کنترل «اندازهٔ متن» داخل اپلیکیشن (@capacitor/text-zoom 8.0.1).
خروجی: get() → Promise { value } (بزرگنمایی فعلی، 1 = 100%). getPreferred() → { value } (اندازهای که کاربر در تنظیمات اندروید انتخاب کرده). set({ value }) → Promise void. نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی این افزونه را دارد؛ مجوزی لازم نیست. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var TZ = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextZoom;
async function biggerText() {
if (!TZ) return;
var now = (await TZ.get()).value;
await TZ.set({ value: Math.min(2, now + 0.1) });
}
async function resetText() {
if (!TZ) return;
var pref = (await TZ.getPreferred()).value; // e.g. 1.15 when the phone uses large text
await TZ.set({ value: pref });
}در یک اپلیکیشن ساختهشده با هوش مصنوعی (در وب بهجای آن اندازهٔ قلم ریشه را مقیاس میدهد):
import { textZoom } from '@/lib/appmintNative';
const size = await textZoom.get();
await textZoom.set(size + 0.1); // clamped to 0.5–3
await textZoom.set(await textZoom.getPreferred()); // back to the system sizeیک لغزندهٔ اندازهٔ متن که انتخاب را به خاطر میسپارد:
var TZ = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextZoom;
var slider = document.getElementById('text-size'); // <input type="range" min="0.8" max="1.6" step="0.1">
if (TZ) {
var saved = parseFloat(localStorage.getItem('textZoom'));
if (saved) TZ.set({ value: saved });
slider.addEventListener('change', function () {
TZ.set({ value: parseFloat(slider.value) });
localStorage.setItem('textZoom', slider.value);
});
} else {
slider.hidden = true;
}نکتهها: اپلیکیشن از قبل اندازهٔ متن سیستم را دنبال میکند؛ این برای یک کنترل اضافی داخل اپلیکیشن است. چیدمان خود را در اندازههای بزرگ آزمایش کنید - ارتفاعهای ثابت روی کنترلهای متنی بریده میشوند.
Capacitor.Toast Capacitor#
Capacitor.Plugins.Toast — show({ text, duration, position })
نمونه
یک پیام کوتاه سیستمی اندروید مانند «Saved» یا «Copied» نشان میدهد (@capacitor/toast 8.0.1).
خروجی: Promise void. نیازمندی: چیزی برای روشنکردن لازم نیست - هر اپلیکیشنی این افزونه را دارد. window.Capacitor در صفحههایی وجود دارد که خود اپلیکیشن ارائه میدهد (اپلیکیشنهای HTML، ZIP و ساختهشده با هوش مصنوعی) و در یک اپلیکیشن حالت وبسایت در سایت خودتان (دامنه و زیردامنههایش) - هرگز در سایتهای دیگری که اپلیکیشن باز میکند. وجود آن را بررسی کنید.
var Toast = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Toast;
function saved() {
if (Toast) Toast.show({ text: 'Saved', duration: 'short', position: 'bottom' });
}duration 'short' (حدود 2 ثانیه) یا 'long' (حدود 3.5 ثانیه) است. position مقدار 'top'، 'center' یا 'bottom'.
در یک اپلیکیشن ساختهشده با هوش مصنوعی از toast() یا Toast با شکل Capacitor استفاده کنید؛ در وب یک نوار پیام با رنگهای اپلیکیشن رسم میکنند:
import { Toast, toast } from '@/lib/appmintNative';
await Toast.show({ text: 'Added to list', duration: 'long' });
toast('Copied'); // short form, same resultوجود افزونه را بررسی کنید و وقتی افزونه نیست، یک پیام داخل صفحه نشان دهید:
function notify(message) {
var Toast = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Toast;
if (Toast) { Toast.show({ text: message, duration: 'short' }); return; }
var el = document.getElementById('snackbar'); // a plain in-page message
el.textContent = message;
el.hidden = false;
setTimeout(function () { el.hidden = true; }, 2000);
}نکتهها: text لازم است («Must provide text»). سیستم toast را به سبک سازندهٔ گوشی رسم میکند و نسخههای جدیدتر Android برای toastهای متنی position را نادیده میگیرند. toast بهراحتی از دست میرود - هرگز برای خطایی که کاربر باید به آن عمل کند استفاده نکنید؛ برای آن از Dialog.alert استفاده کنید.
Capacitor.Torch Capacitor#
Capacitor.Plugins.Torch — enable(), disable(), toggle(), isEnabled(), isAvailable()
نمونه
چراغقوهٔ گوشی، با API مربوط به @capawesome/capacitor-torch. افزونهٔ اختصاصی پوستهٔ اپلیکیشن (TorchPlugin.kt).
خروجی: enable() / disable() / toggle() → Promise (وقتی جریان دوربین خود اپلیکیشن باز است CAMERA_IN_USE رد میشود، بدون فلش UNAVAILABLE)؛ isEnabled() → {enabled}؛ isAvailable() → {available}. نیازمندی: چیزی برای روشنکردن لازم نیست و مجوزی هم لازم نیست.
const Torch = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Torch;
async function setupLightButton() {
if (!Torch || !(await Torch.isAvailable()).available) { lightBtn.hidden = true; return; }
lightBtn.onclick = async () => {
try {
await Torch.toggle();
lightBtn.classList.toggle('on', (await Torch.isEnabled()).enabled);
} catch (e) {
alert(e.message);
}
};
}یک سیگنال SOS را از یک دکمه چشمک بزنید، و اگر دوربین وسط کار فلش را گرفت چراغ را خاموش کنید:
const Torch = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Torch;
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
sosBtn.onclick = async () => {
if (!Torch || !(await Torch.isAvailable()).available) return;
const flashes = [200, 200, 200, 600, 600, 600, 200, 200, 200]; // S O S, in ms
try {
for (const ms of flashes) {
await Torch.enable(); await wait(ms);
await Torch.disable(); await wait(200);
}
} catch (e) {
await Torch.disable().catch(() => {});
alert(e.code === 'CAMERA_IN_USE' ? 'Close the camera first.' : e.message);
}
};یک دکمهٔ چراغ را با سیستم هماهنگ نگه دارید، چون کاربر میتواند وقتی اپلیکیشن در پسزمینه است چراغقوه را از کاشی تنظیمات سریع روشن کند:
const Torch = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Torch;
async function syncLightButton() {
if (!Torch) return;
const { enabled } = await Torch.isEnabled();
lightBtn.classList.toggle('on', enabled);
lightBtn.setAttribute('aria-pressed', String(enabled));
}
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') syncLightButton();
});
syncLightButton();نکتهها: چراغ از وضعیت سیستم پیروی میکند (خاموشکردن آن از کاشی تنظیمات سریع بهصورت خاموش خوانده میشود) و وقتی اپلیکیشن بسته شود خاموش میشود. وقتی یک جریان getUserMedia باز است، آن را از طریق trackروشن کنید: track.applyConstraints({ advanced: [{ torch: true }] }). اپلیکیشنهای ساختهشده با هوش مصنوعی از torch از استفاده میکنند @/lib/appmintNative.