API پل جاوااسکریپت
کارهای پسزمینه
کاری که پس از بسته شدن اپلیکیشن ادامه مییابد: ذخیره خودکار پایدار، همگامسازی دورهای.
workCancel پل#
window.WebToApk.workCancel(id: String)
مجوزی لازم نیست؛ نتایج بهصورت `appmint:work` / window.onAppMintWork منعکس میشوند.
با گروه خودش، کارهای پسزمینه (WorkManager): ذخیره خودکار پایدار + همگامسازی بومی دورهای، توضیح داده شده است، نه بهتنهایی.
نمونه
یک کار پسزمینه (یکباره یا تکرارشونده) را با شناسهاش لغو میکند و درخواست ذخیرهشدهاش را حذف میکند.
خروجی: مستقیماً هیچ. رویداد appmint:work (و window.onAppMintWork) با { id, status: 'cancelled' } پاسخ میدهد. نیازمندی: هیچ.
function stopSync() {
if (!(window.WebToApk && window.WebToApk.workCancel)) return;
WebToApk.workCancel('sync');
}
window.addEventListener('appmint:work', function (e) {
if (e.detail.id === 'sync' && e.detail.status === 'cancelled') {
document.getElementById('sync-status').textContent = 'Background sync is off';
}
});یک پیشنویس را دور بیندازید: ذخیره خودکار هنوز ارسالنشدهاش را لغو کنید، سپس وقتی اندروید تأیید کرد ویرایشگر را پاک کنید:
function discardDraft() {
if (!(window.WebToApk && window.WebToApk.workCancel)) { clearEditor(); return; }
function onWork(e) {
if (e.detail.id !== 'autosave' || e.detail.status !== 'cancelled') return;
window.removeEventListener('appmint:work', onWork);
clearEditor();
}
window.addEventListener('appmint:work', onWork);
WebToApk.workCancel('autosave');
}هنگام خروج، همه کارهای این اپلیکیشن را با شناسههایی که workList گزارش میدهد لغو کنید:
function cancelAllJobs() {
if (!(window.WebToApk && window.WebToApk.workList && window.WebToApk.workCancel)) return;
const requestId = 'signout-' + Date.now();
function onWork(e) {
if (String(e.detail.requestId) !== requestId) return;
window.removeEventListener('appmint:work', onWork);
(e.detail.jobs || []).forEach(function (job) {
WebToApk.workCancel(job.id); // each answers { id, status: 'cancelled' }
});
}
window.addEventListener('appmint:work', onWork);
WebToApk.workList(requestId);
}نکتهها: حتی وقتی هیچ کاری آن شناسه را نداشته باشد cancelled پاسخ میدهد. ذخیره خودکاری که هنوز ارسال نشده کنار گذاشته میشود، پس فقط وقتی لغو کنید که واقعاً نمیخواهید تحویل داده شود.
workEnqueueOnline پل#
window.WebToApk.workEnqueueOnline(id: String, url: String, method: String, headersJson: String, payload: String)
مجوزی لازم نیست؛ نتایج بهصورت `appmint:work` / window.onAppMintWork منعکس میشوند.
با گروه خودش، کارهای پسزمینه (WorkManager): ذخیره خودکار پایدار + همگامسازی بومی دورهای، توضیح داده شده است، نه بهتنهایی.
نمونه
یک درخواست HTTP را به اندروید میسپارد تا وقتی گوشی آنلاین است ارسال کند - حتی اگر کاربر اپلیکیشن را ببندد یا گوشی را دوباره راهاندازی کند. برای ذخیره خودکار قابل اعتماد از آن استفاده کنید.
خروجی: مستقیماً هیچ. پاسخ بهصورت رویداد appmint:work میرسد (و window.onAppMintWork(detail) اگر تعریف کرده باشید): { id, status: 'enqueued' }، یا { id, status: 'failed', reason } با دلیل invalid_arguments (شناسه خالی یا URLی که با http شروع نمیشود) یا enqueue_failed. نیازمندی: هیچ.
ذخیره خودکار پایدار: همان شناسه ذخیرهای را که هنوز ارسال نشده جایگزین میکند، پس جدیدترین وضعیت برنده است.
function autoSave(state, token) {
if (!(window.WebToApk && window.WebToApk.workEnqueueOnline)) {
showMessage('Offline auto-save works in the installed app only.');
return;
}
WebToApk.workEnqueueOnline(
'autosave', // your job id
'https://api.example.com/save', // http(s) URL
'POST', // POST | PUT | GET ...
JSON.stringify({ Authorization: 'Bearer ' + token }), // headers as a JSON string
JSON.stringify(state) // body as a string ('' for none)
);
}
window.addEventListener('appmint:work', function (e) {
const d = e.detail;
if (d.id !== 'autosave') return;
if (d.status === 'enqueued') showSavedBadge('Will sync when online');
if (d.status === 'failed') showMessage('Could not queue the save: ' + d.reason);
});هر ارسال فرم را بهصورت یک کار جدا در صف بگذارید (برای هر ارسال یک شناسه یکتا، تا دومی جایگزین اولی نشود) و منتظر پاسخ اندروید بمانید:
function queueFeedback(form) {
return new Promise(function (resolve, reject) {
if (!(window.WebToApk && window.WebToApk.workEnqueueOnline)) {
reject(new Error('not_in_app'));
return;
}
const id = 'feedback-' + Date.now();
function onWork(e) {
if (e.detail.id !== id) return; // another job's answer
window.removeEventListener('appmint:work', onWork);
if (e.detail.status === 'enqueued') resolve(id);
else reject(new Error(e.detail.reason)); // invalid_arguments | enqueue_failed
}
window.addEventListener('appmint:work', onWork);
WebToApk.workEnqueueOnline(id, 'https://api.example.com/feedback', 'POST', '{}',
JSON.stringify({ rating: form.rating.value, text: form.text.value }));
});
}یک یادداشت را با PUT بهصورت متن ساده ذخیره کنید؛ تنظیم Content-Type خودتان جلوی افزوده شدن پیشفرض JSON را میگیرد:
function saveNote(noteId, text) {
if (!(window.WebToApk && window.WebToApk.workEnqueueOnline)) return;
WebToApk.workEnqueueOnline(
'note-' + noteId, // same note, same id: only the newest text is sent
'https://api.example.com/notes/' + encodeURIComponent(noteId),
'PUT',
JSON.stringify({ 'Content-Type': 'text/plain; charset=utf-8' }),
text
);
}
document.getElementById('note').addEventListener('change', function (e) {
saveNote(e.target.dataset.noteId, e.target.value);
});نکتهها: enqueued یعنی اندروید کار را پذیرفت، نه اینکه سرور آن را گرفت؛ وقتی تحویل شد رویدادی نیست. قواعد تحویل: پاسخ 2xx کار را تمام میکند؛ پاسخ 4xx آن را متوقف میکند (بدون تلاش دوباره)؛ خطای شبکه یا 5xx با تأخیرهای فزاینده تا ۸ بار دوباره تلاش میکند. Content-Type: application/json اضافه میشود مگر اینکه خودتان تنظیم کنید. یک GET بدنه نمیفرستد. جاوااسکریپت صفحه در پسزمینه اجرا نمیشود - فقط همین درخواست بومی.
workList پل#
window.WebToApk.workList(requestId: String)
مجوزی لازم نیست؛ نتایج بهصورت `appmint:work` / window.onAppMintWork منعکس میشوند.
با گروه خودش، کارهای پسزمینه (WorkManager): ذخیره خودکار پایدار + همگامسازی بومی دورهای، توضیح داده شده است، نه بهتنهایی.
نمونه
کارهای پسزمینهای را که این اپلیکیشن در صف گذاشته یا زمانبندی کرده فهرست میکند.
خروجی: مستقیماً هیچ. رویداد appmint:work (و window.onAppMintWork) با { requestId, jobs: [{ id, periodic, url, createdAt, pendingDelivery }] } پاسخ میدهد. pendingDelivery تا وقتی یک کار یکباره تحویل نشده true است (و برای کار دورهای همیشه). نیازمندی: هیچ.
یک پوششدهنده کوچک Promise که پاسخ را با requestId تطبیق میدهد:
function listJobs() {
return new Promise(function (resolve) {
if (!(window.WebToApk && window.WebToApk.workList)) { resolve([]); return; }
const requestId = 'jobs-' + Date.now();
function onWork(e) {
if (String(e.detail.requestId) !== requestId) return; // not our answer
window.removeEventListener('appmint:work', onWork);
resolve(e.detail.jobs || []);
}
window.addEventListener('appmint:work', onWork);
WebToApk.workList(requestId);
});
}
listJobs().then(function (jobs) {
const unsent = jobs.filter(function (j) { return !j.periodic && j.pendingDelivery; });
document.getElementById('unsent').textContent =
unsent.length ? unsent.length + ' change(s) waiting for network' : 'All changes saved';
});هر کار را در صفحه تنظیمات نشان دهید، با زمان قرار گرفتنش در صف:
window.addEventListener('appmint:work', function (e) {
if (e.detail.requestId !== 'settings-jobs') return;
const list = document.getElementById('jobs');
list.innerHTML = '';
(e.detail.jobs || []).forEach(function (job) {
const li = document.createElement('li');
li.textContent = job.id + (job.periodic ? ' (repeats)' : job.pendingDelivery ? ' (waiting)' : '') +
' - since ' + new Date(job.createdAt).toLocaleString();
list.appendChild(li);
});
});
if (window.WebToApk && window.WebToApk.workList) WebToApk.workList('settings-jobs');وقتی اپلیکیشن باز میشود، کلید «همگامسازی پسزمینه» را بر اساس اینکه کار تکرارشونده 'sync' هنوز ثبت شده تنظیم کنید:
window.addEventListener('appmint:work', function (e) {
if (e.detail.requestId !== 'startup') return;
const on = (e.detail.jobs || []).some(function (j) { return j.id === 'sync' && j.periodic; });
document.getElementById('sync-toggle').checked = on;
});
document.addEventListener('DOMContentLoaded', function () {
if (window.WebToApk && window.WebToApk.workList) WebToApk.workList('startup');
});نکتهها: یک کار یکباره وقتی تحویل شد، با 4xx رد شد، یا پس از ۸ تلاش رها شد از فهرست خارج میشود. یک requestId عددی ممکن است بهصورت عدد برگردد، پس مقایسه کنید با String(...).
workSchedulePeriodic پل#
window.WebToApk.workSchedulePeriodic(id: String, url: String, method: String, headersJson: String, payload: String, intervalMinutes: Int)
مجوزی لازم نیست؛ نتایج بهصورت `appmint:work` / window.onAppMintWork منعکس میشوند.
با گروه خودش، کارهای پسزمینه (WorkManager): ذخیره خودکار پایدار + همگامسازی بومی دورهای، توضیح داده شده است، نه بهتنهایی.
نمونه
یک درخواست HTTP تکرارشونده را زمانبندی میکند که اندروید در پسزمینه (وقتی آنلاین است) میفرستد، حتی وقتی اپلیکیشن بسته است. برای راهانداز همگامسازی یا ضربان خوب است.
خروجی: مستقیماً هیچ. پاسخ بهصورت رویداد appmint:work میرسد (و window.onAppMintWork(detail)): { id, status: 'scheduled', intervalMinutes }، یا { id, status: 'failed', reason } با دلیل invalid_arguments یا schedule_failed. نیازمندی: هیچ.
function startBackgroundSync(userId) {
if (!(window.WebToApk && window.WebToApk.workSchedulePeriodic)) {
showMessage('Background sync works in the installed app only.');
return;
}
WebToApk.workSchedulePeriodic(
'sync', // job id (scheduling again updates it)
'https://api.example.com/sync',
'POST',
JSON.stringify({ 'X-User': userId }), // headers as a JSON string
JSON.stringify({ userId: userId }), // the same body is sent every time
30 // minutes; values under 15 become 15
);
}
// Optional page hook instead of addEventListener:
window.onAppMintWork = function (d) {
if (d.id === 'sync' && d.status === 'scheduled') {
console.log('sync every', d.intervalMinutes, 'minutes');
}
if (d.status === 'failed') console.warn('job', d.id, 'failed:', d.reason);
};یک ضربان در هر ساعت: GET بدنهای نمیفرستد، پس رشته خالی بدهید، و وقتی هدر لازم ندارید '{}':
function startHeartbeat(deviceId) {
if (!(window.WebToApk && window.WebToApk.workSchedulePeriodic)) return;
WebToApk.workSchedulePeriodic(
'heartbeat',
'https://api.example.com/ping?device=' + encodeURIComponent(deviceId),
'GET',
'{}',
'',
60
);
}بگذارید کاربر انتخاب کند هر چند وقت همگامسازی شود و فاصلهای را که اندروید واقعاً استفاده میکند نشان دهید (هر چه کمتر از ۱۵ باشد ۱۵ برمیگردد):
document.getElementById('sync-every').addEventListener('change', function (e) {
if (!(window.WebToApk && window.WebToApk.workSchedulePeriodic)) return;
const minutes = parseInt(e.target.value, 10); // e.g. 5, 30, 120
WebToApk.workSchedulePeriodic('sync', 'https://api.example.com/sync', 'POST', '{}',
JSON.stringify({ reason: 'periodic' }), minutes); // same id: updates the existing job
});
window.addEventListener('appmint:work', function (e) {
const d = e.detail;
if (d.id !== 'sync') return;
if (d.status === 'scheduled') {
document.getElementById('sync-note').textContent = 'Syncing about every ' + d.intervalMinutes + ' minutes';
} else if (d.status === 'failed') {
document.getElementById('sync-note').textContent = 'Could not schedule sync (' + d.reason + ')';
}
});نکتهها: لحظه دقیق را اندروید تعیین میکند؛ ۱۵ دقیقه کوتاهترین فاصله است و صرفهجویی باتری میتواند اجراها را به تأخیر بیندازد. بدنه هنگام زمانبندی ثابت میشود؛ برای تغییر آن، دوباره با همان شناسه زمانبندی کنید. پاسخ 4xx کار دورهای را لغو نمیکند؛ اجرای بعدی دوباره تلاش میکند. آن را متوقف کنید با workCancel('sync').