JavaScript bridge API
Background jobs
Work that keeps going after the app is closed: a durable auto-save, a periodic sync.
workCancel bridge#
window.WebToApk.workCancel(id: String)
No permission needed; results echo as `appmint:work` / window.onAppMintWork.
Described by its group, Background jobs (WorkManager): durable auto-save + periodic native sync, rather than on its own.
Example
Cancels a background job (one-off or repeating) by its id and deletes its saved request.
Returns: nothing directly. The appmint:work event (and window.onAppMintWork) answers { id, status: 'cancelled' }. Needs: nothing.
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';
}
});Notes: it answers cancelled even when no job had that id. An auto-save that has not been sent yet is dropped, so cancel only when you really do not want it delivered.
workEnqueueOnline bridge#
window.WebToApk.workEnqueueOnline(id: String, url: String, method: String, headersJson: String, payload: String)
No permission needed; results echo as `appmint:work` / window.onAppMintWork.
Described by its group, Background jobs (WorkManager): durable auto-save + periodic native sync, rather than on its own.
Example
Hands one HTTP request to Android to send when the phone is online - even if the user closes the app or restarts the phone. Use it for a reliable auto-save.
Returns: nothing directly. The answer comes as the appmint:work event (and window.onAppMintWork(detail) if you define it): { id, status: 'enqueued' }, or { id, status: 'failed', reason } with reason invalid_arguments (empty id or a URL not starting with http) or enqueue_failed. Needs: nothing.
Durable auto-save: the same id replaces a save that has not been sent yet, so the newest state wins.
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);
});Notes: enqueued means Android accepted the job, not that the server got it; there is no event when it is delivered. Delivery rules: a 2xx reply finishes the job; a 4xx reply stops it (no retry); a network error or 5xx retries with growing delays, up to 8 tries. Content-Type: application/json is added unless you set one. A GET sends no body. The page's JavaScript does not run in the background - only this native request does.
workList bridge#
window.WebToApk.workList(requestId: String)
No permission needed; results echo as `appmint:work` / window.onAppMintWork.
Described by its group, Background jobs (WorkManager): durable auto-save + periodic native sync, rather than on its own.
Example
Lists the background jobs this app has queued or scheduled.
Returns: nothing directly. The appmint:work event (and window.onAppMintWork) answers { requestId, jobs: [{ id, periodic, url, createdAt, pendingDelivery }] }. pendingDelivery is true while a one-off job has not been delivered yet (and always for a periodic job). Needs: nothing.
A small Promise wrapper that matches the answer by 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';
});Notes: a one-off job leaves the list once it is delivered, rejected with a 4xx, or given up after 8 tries. A numeric requestId may come back as a number, so compare with String(...).
workSchedulePeriodic bridge#
window.WebToApk.workSchedulePeriodic(id: String, url: String, method: String, headersJson: String, payload: String, intervalMinutes: Int)
No permission needed; results echo as `appmint:work` / window.onAppMintWork.
Described by its group, Background jobs (WorkManager): durable auto-save + periodic native sync, rather than on its own.
Example
Schedules a repeating HTTP request that Android sends in the background (when online), even while the app is closed. Good for a sync trigger or a heartbeat.
Returns: nothing directly. The answer comes as the appmint:work event (and window.onAppMintWork(detail)): { id, status: 'scheduled', intervalMinutes }, or { id, status: 'failed', reason } with reason invalid_arguments or schedule_failed. Needs: nothing.
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);
};Notes: Android decides the exact moment; 15 minutes is the shortest interval, and battery saving can delay runs. The body is fixed when you schedule; to change it, schedule again with the same id. A 4xx reply does not cancel a periodic job; the next run tries again. Stop it with workCancel('sync').