API jembatan JavaScript
Berjalan di latar belakang
Layanan foreground yang dimulai dan dihentikan halaman, lokasi yang terus datang saat aplikasi di latar belakang, geofence yang terpicu saat aplikasi tertutup, dan kode Anda sendiri yang dijalankan berkala setelah restart. Masing-masing membutuhkan sakelarnya di build dan deklarasi Play Console.
AppMint.background helper#
AppMint.background.register(name, options) / unregister / list / runNow / done / isBackgroundRun / currentRun / onRun
Contoh
Menjalankan kode halaman Anda SENDIRI secara berkala saat aplikasi tertutup - menyegarkan data, memeriksa harga, memposting notifikasi. Setiap proses memuat halaman Anda secara tak terlihat (origin yang sama, localStorage/IndexedDB yang sama, tanpa layar, tanpa iklan) dengan ?appmint_background=1&appmint_task=<name>&appmint_run=<runId>, memicu appmint:background { name, runId } sekali setelah dimuat, dan menunggu done(runId, { ok }). Satu proses dihentikan setelah sekitar 9 menit.
Mengembalikan: setiap metode mengembalikan Promise. register β { ok: true, name, intervalMinutes } atau { ok: false, reason } (not_enabled, invalid_name, interval_below_15_minutes, invalid_interval, schedule_failed). unregister β true / false. list β [{ name, intervalMinutes, requiresNetwork, requiresCharging, registeredAt, lastRunAt, lastResult }] (lastResult: ok, retry, failed, timeout, unsupported_mode, page_load_failed, β¦). runNow β { ok } (satu proses secepat kondisinya memungkinkan - untuk pengujian). done β true saat proses diakhiri. isBackgroundRun() dan currentRun() bersifat sinkron. Membutuhkan: centang Run page code while closed (langkah Access β Background). Aplikasi situs web dan offline/ZIP; aplikasi dokumen dan media tidak punya kode halaman untuk dijalankan.
Satu halaman, dua peran:
function startApp() {
const bg = window.AppMint && AppMint.background;
if (bg && bg.isBackgroundRun()) return; // a background run: no UI work
renderUi();
if (bg) bg.register('prices', { intervalMinutes: 60, requiresNetwork: true }).then(function (r) {
if (!r.ok) console.warn('background task not scheduled:', r.reason);
});
}
// Runs only in the background copy of the page.
window.addEventListener('appmint:background', async function (e) {
const run = e.detail; // { name: 'prices', runId: 'β¦' }
try {
const price = await fetch('https://api.example.com/price').then(function (r) { return r.json(); });
const last = Number(localStorage.getItem('lastPrice') || 0);
if (price.value < last) {
WebToApk.notify(JSON.stringify({ title: 'Price dropped', body: 'Now ' + price.value, tag: 'price' }));
}
localStorage.setItem('lastPrice', String(price.value));
AppMint.background.done(run.runId, { ok: true });
} catch (err) {
AppMint.background.done(run.runId, { ok: false, retry: true }); // retried with backoff
}
});
startApp();Halaman yang dipasang terlambat (React, rute lazy) memakai onRun, yang juga terpicu jika proses sudah dimulai, atau hook halaman:
if (window.AppMint && AppMint.background) {
AppMint.background.onRun(function (run) { syncInbox().then(function () { AppMint.background.done(run.runId, { ok: true }); }); });
}
window.onAppMintBackground = function (run) { console.log('background run', run.name, run.runId, AppMint.background.currentRun()); };Kelola:
AppMint.background.list().then(function (tasks) { console.table(tasks); });
AppMint.background.runNow('prices');
AppMint.background.unregister('prices');Catatan: Android yang menentukan saat tepatnya; 15 menit adalah interval terpendek dan penghematan baterai bisa menunda proses. Dengan Start after phone restart setiap tugas juga berjalan sekali setelah restart. WebToApk dalam sebuah proses hanya memiliki notify, showNotification, buffer lokasi, geofence, workEnqueueOnline, isBackgroundServiceRunning dan metode tugas ini; yang lain tidak ada (deteksi fitur).
addGeofence jembatan#
window.WebToApk.addGeofence(json: String): String
Menambahkan geofence {id, lat, lng, radiusM, events, dwellMs?, notify?} β JSON {ok, status:'adding'} atau {ok:false, reason}; hasilnya adalah appmint:geofence-added.
Contoh
Sebuah lingkaran yang memicu enter, exit dan/atau dwell saat aplikasi tertutup, dengan opsi memposting notifikasi. Geofence bertahan setelah ponsel dihidupkan ulang (ditambahkan kembali secara otomatis).
Mengembalikan: addGeofence β string JSON { ok: true, status: 'adding', id } atau { ok: false, reason } - not_enabled, invalid_id, invalid_position, invalid_radius (1 m β¦ 100 km), invalid_events, location_permission_required, background_permission_required, foreign_origin. Jawaban Play services datang sebagai appmint:geofence-added (window.onAppMintGeofenceAdded) = { id, ok, reason? } (location_off, too_many_geofences - 100 per aplikasi, play_services_unavailable). Sebuah transisi datang sebagai appmint:geofence (window.onAppMintGeofence) = { id, event: 'enter' | 'exit' | 'dwell', time, lat, lng, queued? } - queued: true saat terjadi ketika aplikasi tertutup dan diserahkan pada awal berikutnya. removeGeofence β true jika ada; getGeofences β array JSON dari apa yang Anda tambahkan. Membutuhkan: centang Geofences di build, dan "Allow all the time" (requestBackgroundLocation()).
function watchOffice() {
const b = window.WebToApk;
if (!(b && b.addGeofence)) return;
const r = JSON.parse(b.addGeofence(JSON.stringify({
id: 'office', lat: 51.5033, lng: -0.1196, radiusM: 150,
events: ['enter', 'exit', 'dwell'], dwellMs: 5 * 60000,
notify: {
enter: { title: 'At the office', body: 'Tap to check in' },
exit: { title: 'Left the office', body: 'Tap to check out' }
}
})));
if (!r.ok && r.reason === 'background_permission_required') b.requestBackgroundLocation();
}
window.addEventListener('appmint:geofence-added', function (e) {
if (!e.detail.ok) showMessage('Geofence ' + e.detail.id + ' not added: ' + e.detail.reason);
});
window.addEventListener('appmint:geofence', function (e) {
logVisit(e.detail.id, e.detail.event, e.detail.time);
});
console.log(JSON.parse(WebToApk.getGeofences()).map(function (g) { return g.id; }));
WebToApk.removeGeofence('office');Deteksi fitur dan laporkan setiap penolakan:
function addCircle(id, lat, lng, radiusM) {
const b = window.WebToApk;
if (!(b && b.addGeofence)) { showMessage('Place alerts need the app'); return false; }
const r = JSON.parse(b.addGeofence(JSON.stringify({ id: id, lat: lat, lng: lng, radiusM: radiusM, events: ['enter'] })));
if (r.ok) return true;
if (r.reason === 'not_enabled') showMessage('Geofences are not switched on in this build');
else if (r.reason === 'background_permission_required') b.requestBackgroundLocation();
else if (r.reason === 'invalid_radius') showMessage('Pick a radius between 1 m and 100 km');
else showMessage('Could not add the place: ' + r.reason);
return false;
}Tampilkan apa yang terdaftar dan hapus satu:
const mine = JSON.parse(WebToApk.getGeofences()); // [] when none
mine.forEach(function (g) { addRow(g.id); });
document.getElementById('forget').onclick = function () {
const existed = WebToApk.removeGeofence('office'); // true if it was there
if (!existed) showMessage('That place was not registered');
};backgroundDone jembatan#
window.WebToApk.backgroundDone(runId: String, resultJson: String): Boolean
AppMint.background.done(runId, result): mengakhiri satu proses latar belakang; selalu false di dalam aplikasi itu sendiri.
Contoh
Didokumentasikan bersama WebToApk.backgroundRegister - contoh di sana menunjukkan yang ini juga.
Metode mentah di balik AppMint.background - gunakan AppMint.background.register(...) (mengembalikan promise dan menangani event proses). Dicantumkan di sini agar setiap metode jembatan punya contoh.
Mengembalikan: backgroundRegister β JSON { ok: true, name, intervalMinutes } atau { ok: false, reason } (not_enabled, invalid_name - huruf, angka, _, -, hingga 64 - interval_below_15_minutes, invalid_interval, schedule_failed). backgroundUnregister β true jika ada. backgroundList β array JSON. backgroundRunNow β JSON { ok, name } atau { ok: false, reason: 'not_registered' }. backgroundDone(runId, resultJson) β true dalam proses latar belakang, selalu false di dalam aplikasi. isBackgroundRun() β false di dalam aplikasi, true dalam proses latar belakang. Membutuhkan: centang Run page code while closed.
const b = window.WebToApk;
if (b && b.backgroundRegister) {
const r = JSON.parse(b.backgroundRegister('refresh', JSON.stringify({ intervalMinutes: 60, requiresNetwork: true })));
if (!r.ok) console.warn('not scheduled:', r.reason);
console.log(JSON.parse(b.backgroundList()));
console.log(b.isBackgroundRun()); // false here: this is the app on screen
// b.backgroundRunNow('refresh'); b.backgroundUnregister('refresh');
// In a run: b.backgroundDone(runId, JSON.stringify({ ok: true }))
}Deteksi fitur dan bedakan proses aplikasi dari proses latar belakang:
const b = window.WebToApk;
if (!(b && b.backgroundRegister)) {
console.log('background tasks are only in the app');
} else if (b.isBackgroundRun()) {
// the invisible copy: do the work, no UI
} else {
const r = JSON.parse(b.backgroundRegister('sync', JSON.stringify({ intervalMinutes: 5 })));
if (!r.ok) console.warn(r.reason); // 'interval_below_15_minutes'
}Uji sebuah tugas dan bersihkan:
const run = JSON.parse(WebToApk.backgroundRunNow('sync'));
if (!run.ok && run.reason === 'not_registered') WebToApk.backgroundRegister('sync', JSON.stringify({ intervalMinutes: 30 }));
JSON.parse(WebToApk.backgroundList()).forEach(function (t) { console.log(t.name, t.intervalMinutes, t.lastResult); });
WebToApk.backgroundUnregister('old-task'); // true if it existedbackgroundList jembatan#
window.WebToApk.backgroundList(): String
AppMint.background.list(): array JSON {name, intervalMinutes, requiresNetwork, requiresCharging, registeredAt, lastRunAt, lastResult}.
Contoh
Didokumentasikan bersama WebToApk.backgroundRegister - contoh di sana menunjukkan yang ini juga.
Metode mentah di balik AppMint.background - gunakan AppMint.background.register(...) (mengembalikan promise dan menangani event proses). Dicantumkan di sini agar setiap metode jembatan punya contoh.
Mengembalikan: backgroundRegister β JSON { ok: true, name, intervalMinutes } atau { ok: false, reason } (not_enabled, invalid_name - huruf, angka, _, -, hingga 64 - interval_below_15_minutes, invalid_interval, schedule_failed). backgroundUnregister β true jika ada. backgroundList β array JSON. backgroundRunNow β JSON { ok, name } atau { ok: false, reason: 'not_registered' }. backgroundDone(runId, resultJson) β true dalam proses latar belakang, selalu false di dalam aplikasi. isBackgroundRun() β false di dalam aplikasi, true dalam proses latar belakang. Membutuhkan: centang Run page code while closed.
const b = window.WebToApk;
if (b && b.backgroundRegister) {
const r = JSON.parse(b.backgroundRegister('refresh', JSON.stringify({ intervalMinutes: 60, requiresNetwork: true })));
if (!r.ok) console.warn('not scheduled:', r.reason);
console.log(JSON.parse(b.backgroundList()));
console.log(b.isBackgroundRun()); // false here: this is the app on screen
// b.backgroundRunNow('refresh'); b.backgroundUnregister('refresh');
// In a run: b.backgroundDone(runId, JSON.stringify({ ok: true }))
}Deteksi fitur dan bedakan proses aplikasi dari proses latar belakang:
const b = window.WebToApk;
if (!(b && b.backgroundRegister)) {
console.log('background tasks are only in the app');
} else if (b.isBackgroundRun()) {
// the invisible copy: do the work, no UI
} else {
const r = JSON.parse(b.backgroundRegister('sync', JSON.stringify({ intervalMinutes: 5 })));
if (!r.ok) console.warn(r.reason); // 'interval_below_15_minutes'
}Uji sebuah tugas dan bersihkan:
const run = JSON.parse(WebToApk.backgroundRunNow('sync'));
if (!run.ok && run.reason === 'not_registered') WebToApk.backgroundRegister('sync', JSON.stringify({ intervalMinutes: 30 }));
JSON.parse(WebToApk.backgroundList()).forEach(function (t) { console.log(t.name, t.intervalMinutes, t.lastResult); });
WebToApk.backgroundUnregister('old-task'); // true if it existedbackgroundRegister jembatan#
window.WebToApk.backgroundRegister(name: String, optionsJson: String): String
AppMint.background.register(name, {intervalMinutes >= 15, requiresNetwork, requiresCharging}) β JSON {ok, name, intervalMinutes} atau {ok:false, reason}.
Contoh
Metode mentah di balik AppMint.background - gunakan AppMint.background.register(...) (mengembalikan promise dan menangani event proses). Dicantumkan di sini agar setiap metode jembatan punya contoh.
Mengembalikan: backgroundRegister β JSON { ok: true, name, intervalMinutes } atau { ok: false, reason } (not_enabled, invalid_name - huruf, angka, _, -, hingga 64 - interval_below_15_minutes, invalid_interval, schedule_failed). backgroundUnregister β true jika ada. backgroundList β array JSON. backgroundRunNow β JSON { ok, name } atau { ok: false, reason: 'not_registered' }. backgroundDone(runId, resultJson) β true dalam proses latar belakang, selalu false di dalam aplikasi. isBackgroundRun() β false di dalam aplikasi, true dalam proses latar belakang. Membutuhkan: centang Run page code while closed.
const b = window.WebToApk;
if (b && b.backgroundRegister) {
const r = JSON.parse(b.backgroundRegister('refresh', JSON.stringify({ intervalMinutes: 60, requiresNetwork: true })));
if (!r.ok) console.warn('not scheduled:', r.reason);
console.log(JSON.parse(b.backgroundList()));
console.log(b.isBackgroundRun()); // false here: this is the app on screen
// b.backgroundRunNow('refresh'); b.backgroundUnregister('refresh');
// In a run: b.backgroundDone(runId, JSON.stringify({ ok: true }))
}Deteksi fitur dan bedakan proses aplikasi dari proses latar belakang:
const b = window.WebToApk;
if (!(b && b.backgroundRegister)) {
console.log('background tasks are only in the app');
} else if (b.isBackgroundRun()) {
// the invisible copy: do the work, no UI
} else {
const r = JSON.parse(b.backgroundRegister('sync', JSON.stringify({ intervalMinutes: 5 })));
if (!r.ok) console.warn(r.reason); // 'interval_below_15_minutes'
}Uji sebuah tugas dan bersihkan:
const run = JSON.parse(WebToApk.backgroundRunNow('sync'));
if (!run.ok && run.reason === 'not_registered') WebToApk.backgroundRegister('sync', JSON.stringify({ intervalMinutes: 30 }));
JSON.parse(WebToApk.backgroundList()).forEach(function (t) { console.log(t.name, t.intervalMinutes, t.lastResult); });
WebToApk.backgroundUnregister('old-task'); // true if it existedbackgroundRunNow jembatan#
window.WebToApk.backgroundRunNow(name: String): String
AppMint.background.runNow(name): satu proses latar belakang secepat kondisinya memungkinkan.
Contoh
Didokumentasikan bersama WebToApk.backgroundRegister - contoh di sana menunjukkan yang ini juga.
Metode mentah di balik AppMint.background - gunakan AppMint.background.register(...) (mengembalikan promise dan menangani event proses). Dicantumkan di sini agar setiap metode jembatan punya contoh.
Mengembalikan: backgroundRegister β JSON { ok: true, name, intervalMinutes } atau { ok: false, reason } (not_enabled, invalid_name - huruf, angka, _, -, hingga 64 - interval_below_15_minutes, invalid_interval, schedule_failed). backgroundUnregister β true jika ada. backgroundList β array JSON. backgroundRunNow β JSON { ok, name } atau { ok: false, reason: 'not_registered' }. backgroundDone(runId, resultJson) β true dalam proses latar belakang, selalu false di dalam aplikasi. isBackgroundRun() β false di dalam aplikasi, true dalam proses latar belakang. Membutuhkan: centang Run page code while closed.
const b = window.WebToApk;
if (b && b.backgroundRegister) {
const r = JSON.parse(b.backgroundRegister('refresh', JSON.stringify({ intervalMinutes: 60, requiresNetwork: true })));
if (!r.ok) console.warn('not scheduled:', r.reason);
console.log(JSON.parse(b.backgroundList()));
console.log(b.isBackgroundRun()); // false here: this is the app on screen
// b.backgroundRunNow('refresh'); b.backgroundUnregister('refresh');
// In a run: b.backgroundDone(runId, JSON.stringify({ ok: true }))
}Deteksi fitur dan bedakan proses aplikasi dari proses latar belakang:
const b = window.WebToApk;
if (!(b && b.backgroundRegister)) {
console.log('background tasks are only in the app');
} else if (b.isBackgroundRun()) {
// the invisible copy: do the work, no UI
} else {
const r = JSON.parse(b.backgroundRegister('sync', JSON.stringify({ intervalMinutes: 5 })));
if (!r.ok) console.warn(r.reason); // 'interval_below_15_minutes'
}Uji sebuah tugas dan bersihkan:
const run = JSON.parse(WebToApk.backgroundRunNow('sync'));
if (!run.ok && run.reason === 'not_registered') WebToApk.backgroundRegister('sync', JSON.stringify({ intervalMinutes: 30 }));
JSON.parse(WebToApk.backgroundList()).forEach(function (t) { console.log(t.name, t.intervalMinutes, t.lastResult); });
WebToApk.backgroundUnregister('old-task'); // true if it existedbackgroundUnregister jembatan#
window.WebToApk.backgroundUnregister(name: String): Boolean
AppMint.background.unregister(name); false jika tidak ada tugas dengan nama itu.
Contoh
Didokumentasikan bersama WebToApk.backgroundRegister - contoh di sana menunjukkan yang ini juga.
Metode mentah di balik AppMint.background - gunakan AppMint.background.register(...) (mengembalikan promise dan menangani event proses). Dicantumkan di sini agar setiap metode jembatan punya contoh.
Mengembalikan: backgroundRegister β JSON { ok: true, name, intervalMinutes } atau { ok: false, reason } (not_enabled, invalid_name - huruf, angka, _, -, hingga 64 - interval_below_15_minutes, invalid_interval, schedule_failed). backgroundUnregister β true jika ada. backgroundList β array JSON. backgroundRunNow β JSON { ok, name } atau { ok: false, reason: 'not_registered' }. backgroundDone(runId, resultJson) β true dalam proses latar belakang, selalu false di dalam aplikasi. isBackgroundRun() β false di dalam aplikasi, true dalam proses latar belakang. Membutuhkan: centang Run page code while closed.
const b = window.WebToApk;
if (b && b.backgroundRegister) {
const r = JSON.parse(b.backgroundRegister('refresh', JSON.stringify({ intervalMinutes: 60, requiresNetwork: true })));
if (!r.ok) console.warn('not scheduled:', r.reason);
console.log(JSON.parse(b.backgroundList()));
console.log(b.isBackgroundRun()); // false here: this is the app on screen
// b.backgroundRunNow('refresh'); b.backgroundUnregister('refresh');
// In a run: b.backgroundDone(runId, JSON.stringify({ ok: true }))
}Deteksi fitur dan bedakan proses aplikasi dari proses latar belakang:
const b = window.WebToApk;
if (!(b && b.backgroundRegister)) {
console.log('background tasks are only in the app');
} else if (b.isBackgroundRun()) {
// the invisible copy: do the work, no UI
} else {
const r = JSON.parse(b.backgroundRegister('sync', JSON.stringify({ intervalMinutes: 5 })));
if (!r.ok) console.warn(r.reason); // 'interval_below_15_minutes'
}Uji sebuah tugas dan bersihkan:
const run = JSON.parse(WebToApk.backgroundRunNow('sync'));
if (!run.ok && run.reason === 'not_registered') WebToApk.backgroundRegister('sync', JSON.stringify({ intervalMinutes: 30 }));
JSON.parse(WebToApk.backgroundList()).forEach(function (t) { console.log(t.name, t.intervalMinutes, t.lastResult); });
WebToApk.backgroundUnregister('old-task'); // true if it existedclearBufferedLocations jembatan#
window.WebToApk.clearBufferedLocations(): Boolean
Mengosongkan buffer yang dibaca getBufferedLocations (panggil setelah Anda menyimpan titik-titiknya).
Contoh
Didokumentasikan bersama WebToApk.getBufferedLocations - contoh di sana menunjukkan yang ini juga.
Posisi yang direkam saat halaman Anda tidak aktif (aplikasi di latar belakang atau tertutup), yang terlama lebih dulu, hingga 10.000.
Mengembalikan: getBufferedLocations() β array string JSON berisi { type: 'fix', lat, lng, accuracy, time, β¦, background: true }; '[]' saat Background location nonaktif. clearBufferedLocations() β true saat dikosongkan. Membutuhkan: Background location di build.
function syncTrack() {
if (!(window.WebToApk && WebToApk.getBufferedLocations)) return;
const points = JSON.parse(WebToApk.getBufferedLocations());
if (!points.length) return;
points.forEach(function (p) { drawPoint(p.lat, p.lng); });
saveTrack(points).then(function () { WebToApk.clearBufferedLocations(); });
}
document.addEventListener('visibilitychange', function () { if (!document.hidden) syncTrack(); });Mulai pelacakan, lalu tangani penolakan. Panggilan mulai menjawab dengan string JSON.
function startTracking() {
if (!(window.WebToApk && WebToApk.startLocationUpdates)) return;
const r = JSON.parse(WebToApk.startLocationUpdates(JSON.stringify({
intervalMs: 15000, accuracy: 'balanced', background: true
})));
if (!r.ok) showMessage('Tracking not started: ' + r.reason); // not_enabled, location_permission_required, ...
}Posisi langsung saat halaman terbuka datang sebagai appmint:location; buffer menyimpan sisanya.
window.addEventListener('appmint:location', function (e) {
drawPoint(e.detail.lat, e.detail.lng);
});
document.getElementById('stop').addEventListener('click', function () {
if (window.WebToApk && WebToApk.stopLocationUpdates) WebToApk.stopLocationUpdates();
if (WebToApk.getBufferedLocations) {
const left = JSON.parse(WebToApk.getBufferedLocations());
console.log(left.length + ' fixes still buffered');
}
});clearGeofenceEvents jembatan#
window.WebToApk.clearGeofenceEvents(): Boolean
Mengosongkan riwayat transisi yang dibaca getGeofenceEvents.
Contoh
Didokumentasikan bersama WebToApk.getGeofenceEvents - contoh di sana menunjukkan yang ini juga.
100 transisi geofence terakhir, yang terlama lebih dulu - termasuk yang terjadi saat aplikasi tertutup. Baca saat mulai jika halaman Anda dipasang terlambat dan mungkin melewatkan event appmint:geofence yang antre.
Mengembalikan: getGeofenceEvents() β array string JSON berisi { id, event, time, lat, lng }; clearGeofenceEvents() β true. Membutuhkan: Geofences di build.
if (window.WebToApk && WebToApk.getGeofenceEvents) {
JSON.parse(WebToApk.getGeofenceEvents()).forEach(function (ev) {
logVisit(ev.id, ev.event, ev.time);
});
WebToApk.clearGeofenceEvents();
}Tambahkan geofence, lalu pantau transisinya selama halaman terbuka.
if (window.WebToApk && WebToApk.addGeofence) {
const r = JSON.parse(WebToApk.addGeofence(JSON.stringify({
id: 'shop-1', lat: 12.9716, lng: 77.5946, radiusM: 150, events: ['enter', 'exit']
})));
if (!r.ok) showMessage('Geofence refused: ' + r.reason); // not_enabled, invalid_radius, ...
}
window.addEventListener('appmint:geofence', function (e) {
logVisit(e.detail.id, e.detail.event, e.detail.time);
});Tampilkan apa yang terdaftar dan hapus satu saat pengguna meninggalkan sebuah fitur.
function dropGeofence(id) {
if (!(window.WebToApk && WebToApk.removeGeofence)) return false;
const known = JSON.parse(WebToApk.getGeofences()).length;
const removed = WebToApk.removeGeofence(id);
console.log(removed ? 'removed' : 'not found', 'of', known, 'registered');
return removed;
}getBufferedLocations jembatan#
window.WebToApk.getBufferedLocations(): String
Array JSON berisi posisi yang direkam saat halaman tidak aktif, yang terlama lebih dulu (hingga 10.000).
Contoh
Posisi yang direkam saat halaman Anda tidak aktif (aplikasi di latar belakang atau tertutup), yang terlama lebih dulu, hingga 10.000.
Mengembalikan: getBufferedLocations() β array string JSON berisi { type: 'fix', lat, lng, accuracy, time, β¦, background: true }; '[]' saat Background location nonaktif. clearBufferedLocations() β true saat dikosongkan. Membutuhkan: Background location di build.
function syncTrack() {
if (!(window.WebToApk && WebToApk.getBufferedLocations)) return;
const points = JSON.parse(WebToApk.getBufferedLocations());
if (!points.length) return;
points.forEach(function (p) { drawPoint(p.lat, p.lng); });
saveTrack(points).then(function () { WebToApk.clearBufferedLocations(); });
}
document.addEventListener('visibilitychange', function () { if (!document.hidden) syncTrack(); });Mulai pelacakan, lalu tangani penolakan. Panggilan mulai menjawab dengan string JSON.
function startTracking() {
if (!(window.WebToApk && WebToApk.startLocationUpdates)) return;
const r = JSON.parse(WebToApk.startLocationUpdates(JSON.stringify({
intervalMs: 15000, accuracy: 'balanced', background: true
})));
if (!r.ok) showMessage('Tracking not started: ' + r.reason); // not_enabled, location_permission_required, ...
}Posisi langsung saat halaman terbuka datang sebagai appmint:location; buffer menyimpan sisanya.
window.addEventListener('appmint:location', function (e) {
drawPoint(e.detail.lat, e.detail.lng);
});
document.getElementById('stop').addEventListener('click', function () {
if (window.WebToApk && WebToApk.stopLocationUpdates) WebToApk.stopLocationUpdates();
if (WebToApk.getBufferedLocations) {
const left = JSON.parse(WebToApk.getBufferedLocations());
console.log(left.length + ' fixes still buffered');
}
});getGeofenceEvents jembatan#
window.WebToApk.getGeofenceEvents(): String
Array JSON berisi 100 transisi geofence terakhir {id, event, time, lat, lng}, yang terlama lebih dulu.
Contoh
100 transisi geofence terakhir, yang terlama lebih dulu - termasuk yang terjadi saat aplikasi tertutup. Baca saat mulai jika halaman Anda dipasang terlambat dan mungkin melewatkan event appmint:geofence yang antre.
Mengembalikan: getGeofenceEvents() β array string JSON berisi { id, event, time, lat, lng }; clearGeofenceEvents() β true. Membutuhkan: Geofences di build.
if (window.WebToApk && WebToApk.getGeofenceEvents) {
JSON.parse(WebToApk.getGeofenceEvents()).forEach(function (ev) {
logVisit(ev.id, ev.event, ev.time);
});
WebToApk.clearGeofenceEvents();
}Tambahkan geofence, lalu pantau transisinya selama halaman terbuka.
if (window.WebToApk && WebToApk.addGeofence) {
const r = JSON.parse(WebToApk.addGeofence(JSON.stringify({
id: 'shop-1', lat: 12.9716, lng: 77.5946, radiusM: 150, events: ['enter', 'exit']
})));
if (!r.ok) showMessage('Geofence refused: ' + r.reason); // not_enabled, invalid_radius, ...
}
window.addEventListener('appmint:geofence', function (e) {
logVisit(e.detail.id, e.detail.event, e.detail.time);
});Tampilkan apa yang terdaftar dan hapus satu saat pengguna meninggalkan sebuah fitur.
function dropGeofence(id) {
if (!(window.WebToApk && WebToApk.removeGeofence)) return false;
const known = JSON.parse(WebToApk.getGeofences()).length;
const removed = WebToApk.removeGeofence(id);
console.log(removed ? 'removed' : 'not found', 'of', known, 'registered');
return removed;
}getGeofences jembatan#
window.WebToApk.getGeofences(): String
Array JSON berisi geofence yang telah ditambahkan aplikasi ini (bertahan setelah restart).
Contoh
Didokumentasikan bersama WebToApk.addGeofence - contoh di sana menunjukkan yang ini juga.
Sebuah lingkaran yang memicu enter, exit dan/atau dwell saat aplikasi tertutup, dengan opsi memposting notifikasi. Geofence bertahan setelah ponsel dihidupkan ulang (ditambahkan kembali secara otomatis).
Mengembalikan: addGeofence β string JSON { ok: true, status: 'adding', id } atau { ok: false, reason } - not_enabled, invalid_id, invalid_position, invalid_radius (1 m β¦ 100 km), invalid_events, location_permission_required, background_permission_required, foreign_origin. Jawaban Play services datang sebagai appmint:geofence-added (window.onAppMintGeofenceAdded) = { id, ok, reason? } (location_off, too_many_geofences - 100 per aplikasi, play_services_unavailable). Sebuah transisi datang sebagai appmint:geofence (window.onAppMintGeofence) = { id, event: 'enter' | 'exit' | 'dwell', time, lat, lng, queued? } - queued: true saat terjadi ketika aplikasi tertutup dan diserahkan pada awal berikutnya. removeGeofence β true jika ada; getGeofences β array JSON dari apa yang Anda tambahkan. Membutuhkan: centang Geofences di build, dan "Allow all the time" (requestBackgroundLocation()).
function watchOffice() {
const b = window.WebToApk;
if (!(b && b.addGeofence)) return;
const r = JSON.parse(b.addGeofence(JSON.stringify({
id: 'office', lat: 51.5033, lng: -0.1196, radiusM: 150,
events: ['enter', 'exit', 'dwell'], dwellMs: 5 * 60000,
notify: {
enter: { title: 'At the office', body: 'Tap to check in' },
exit: { title: 'Left the office', body: 'Tap to check out' }
}
})));
if (!r.ok && r.reason === 'background_permission_required') b.requestBackgroundLocation();
}
window.addEventListener('appmint:geofence-added', function (e) {
if (!e.detail.ok) showMessage('Geofence ' + e.detail.id + ' not added: ' + e.detail.reason);
});
window.addEventListener('appmint:geofence', function (e) {
logVisit(e.detail.id, e.detail.event, e.detail.time);
});
console.log(JSON.parse(WebToApk.getGeofences()).map(function (g) { return g.id; }));
WebToApk.removeGeofence('office');Deteksi fitur dan laporkan setiap penolakan:
function addCircle(id, lat, lng, radiusM) {
const b = window.WebToApk;
if (!(b && b.addGeofence)) { showMessage('Place alerts need the app'); return false; }
const r = JSON.parse(b.addGeofence(JSON.stringify({ id: id, lat: lat, lng: lng, radiusM: radiusM, events: ['enter'] })));
if (r.ok) return true;
if (r.reason === 'not_enabled') showMessage('Geofences are not switched on in this build');
else if (r.reason === 'background_permission_required') b.requestBackgroundLocation();
else if (r.reason === 'invalid_radius') showMessage('Pick a radius between 1 m and 100 km');
else showMessage('Could not add the place: ' + r.reason);
return false;
}Tampilkan apa yang terdaftar dan hapus satu:
const mine = JSON.parse(WebToApk.getGeofences()); // [] when none
mine.forEach(function (g) { addRow(g.id); });
document.getElementById('forget').onclick = function () {
const existed = WebToApk.removeGeofence('office'); // true if it was there
if (!existed) showMessage('That place was not registered');
};getLocationPermissionState jembatan#
window.WebToApk.getLocationPermissionState(): String
JSON {foreground:'granted'|'denied', background:'granted'|'denied', precise: boolean}.
Contoh
Didokumentasikan bersama WebToApk.requestBackgroundLocation - contoh di sana menunjukkan yang ini juga.
Meminta lokasi, lalu "Allow all the time" (Android 10+ memintanya terpisah; di Android 11+ langkah kedua membuka halaman pengaturan lokasi aplikasi). Geofence membutuhkannya; begitu juga memulai ulang pelacakan lokasi setelah ponsel dihidupkan ulang.
Mengembalikan: tidak ada secara langsung; jawabannya datang sebagai appmint:location-permission (dan window.onAppMintLocationPermission(detail)) = { foreground: 'granted' | 'denied', background: 'granted' | 'denied', precise: boolean, error?: 'not_enabled' }. getLocationPermissionState() β objek yang sama sebagai string JSON, tanpa bertanya. Membutuhkan: Background location atau Geofences di build.
function askAlways() {
const b = window.WebToApk;
if (!(b && b.requestBackgroundLocation)) return;
const now = JSON.parse(b.getLocationPermissionState());
if (now.background === 'granted') { enableGeofences(); return; }
// Explain first: Play requires an in-app disclosure before this request.
if (!confirm('Allow location "all the time" so we can remind you when you arrive?')) return;
b.requestBackgroundLocation();
}
window.addEventListener('appmint:location-permission', function (e) {
if (e.detail.background === 'granted') enableGeofences();
else showMessage('Choose "Allow all the time" in the location settings to use arrival reminders.');
});Periksa statusnya dulu dan jelaskan apa yang harus diketuk pengguna:
const b = window.WebToApk;
if (b && b.getLocationPermissionState) {
const s = JSON.parse(b.getLocationPermissionState());
if (s.foreground !== 'granted') showMessage('Location is off for this app.');
else if (s.background !== 'granted') showMessage('Tap "Allow all the time" to enable arrival reminders.');
else if (!s.precise) showMessage('Precise location is off; arrival alerts may be late.');
}Minta izin, lalu tambahkan geofence setelah izin diberikan:
window.addEventListener('appmint:location-permission', function (e) {
if (e.detail.error === 'not_enabled') return showMessage('This build has no background location.');
if (e.detail.background !== 'granted') return;
const r = JSON.parse(WebToApk.addGeofence(JSON.stringify({
id: 'home', lat: 51.5033, lng: -0.1196, radiusM: 120, events: ['enter']
})));
if (!r.ok) showMessage('Could not add the place: ' + r.reason);
}, { once: true });
WebToApk.requestBackgroundLocation();isBackgroundRun jembatan#
window.WebToApk.isBackgroundRun(): Boolean
False di sini: halaman aplikasi sendiri tidak pernah menjadi proses latar belakang (proses headless menjawab true).
Contoh
Didokumentasikan bersama WebToApk.backgroundRegister - contoh di sana menunjukkan yang ini juga.
Metode mentah di balik AppMint.background - gunakan AppMint.background.register(...) (mengembalikan promise dan menangani event proses). Dicantumkan di sini agar setiap metode jembatan punya contoh.
Mengembalikan: backgroundRegister β JSON { ok: true, name, intervalMinutes } atau { ok: false, reason } (not_enabled, invalid_name - huruf, angka, _, -, hingga 64 - interval_below_15_minutes, invalid_interval, schedule_failed). backgroundUnregister β true jika ada. backgroundList β array JSON. backgroundRunNow β JSON { ok, name } atau { ok: false, reason: 'not_registered' }. backgroundDone(runId, resultJson) β true dalam proses latar belakang, selalu false di dalam aplikasi. isBackgroundRun() β false di dalam aplikasi, true dalam proses latar belakang. Membutuhkan: centang Run page code while closed.
const b = window.WebToApk;
if (b && b.backgroundRegister) {
const r = JSON.parse(b.backgroundRegister('refresh', JSON.stringify({ intervalMinutes: 60, requiresNetwork: true })));
if (!r.ok) console.warn('not scheduled:', r.reason);
console.log(JSON.parse(b.backgroundList()));
console.log(b.isBackgroundRun()); // false here: this is the app on screen
// b.backgroundRunNow('refresh'); b.backgroundUnregister('refresh');
// In a run: b.backgroundDone(runId, JSON.stringify({ ok: true }))
}Deteksi fitur dan bedakan proses aplikasi dari proses latar belakang:
const b = window.WebToApk;
if (!(b && b.backgroundRegister)) {
console.log('background tasks are only in the app');
} else if (b.isBackgroundRun()) {
// the invisible copy: do the work, no UI
} else {
const r = JSON.parse(b.backgroundRegister('sync', JSON.stringify({ intervalMinutes: 5 })));
if (!r.ok) console.warn(r.reason); // 'interval_below_15_minutes'
}Uji sebuah tugas dan bersihkan:
const run = JSON.parse(WebToApk.backgroundRunNow('sync'));
if (!run.ok && run.reason === 'not_registered') WebToApk.backgroundRegister('sync', JSON.stringify({ intervalMinutes: 30 }));
JSON.parse(WebToApk.backgroundList()).forEach(function (t) { console.log(t.name, t.intervalMinutes, t.lastResult); });
WebToApk.backgroundUnregister('old-task'); // true if it existedisBackgroundServiceRunning jembatan#
window.WebToApk.isBackgroundServiceRunning(): Boolean
Apakah layanan foreground aplikasi sedang berjalan (untuk keep-running maupun lokasi latar belakang).
Contoh
Didokumentasikan bersama WebToApk.startBackgroundService - contoh di sana menunjukkan yang ini juga.
Menjaga aplikasi Anda tetap berjalan saat pengguna pergi: layanan foreground Android yang sebenarnya dengan notifikasi. Selama berjalan, halaman tidak dijeda, sehingga JavaScript-nya, <audio> dan musik latar aplikasi tetap berlanjut (Android tetap memperlambat timer halaman yang tidak dilihat siapa pun).
Mengembalikan: startBackgroundService β string JSON { ok: true, status: 'starting', type, notificationShown } atau { ok: false, reason } - alasan not_enabled, invalid_options, type_not_declared, invalid_progress, location_permission_required, start_not_allowed. updateBackgroundService β { ok: true } atau { ok: false, reason: 'not_running' }. stopBackgroundService / isBackgroundServiceRunning β true / false. Perubahan status datang sebagai appmint:background-service (dan window.onAppMintBackgroundService(detail)): { state: 'running' | 'stopped' | 'failed' | 'not_restarted', reason?, types?, restored?, queued? }. Membutuhkan: centang Keep running in background (langkah Access β Background) dan pilih tipe layanan. Di Android 13+ notifikasi hanya terlihat setelah pengguna mengizinkan notifikasi (notificationShown: false jika tidak - layanan tetap berjalan).
function startWorkout() {
const b = window.WebToApk;
if (!(b && b.startBackgroundService)) return; // browser
const r = JSON.parse(b.startBackgroundService(JSON.stringify({
title: 'Workout in progress',
text: '00:00 elapsed',
stopLabel: 'Stop', // a Stop button on the notification
progress: { value: 0, max: 100 }
})));
if (!r.ok) showMessage('Could not keep running: ' + r.reason);
}
function tick(seconds) {
if (window.WebToApk && WebToApk.isBackgroundServiceRunning()) {
WebToApk.updateBackgroundService(JSON.stringify({
title: 'Workout in progress', text: seconds + ' s elapsed', stopLabel: 'Stop',
progress: { value: Math.min(100, seconds / 18), max: 100 }
}));
}
}
function finishWorkout() {
if (window.WebToApk && WebToApk.stopBackgroundService) WebToApk.stopBackgroundService();
}
window.addEventListener('appmint:background-service', function (e) {
// reason: 'user' (Stop button), 'page', 'timeout' (Android 15 dataSync 6-hour limit),
// 'task_removed' (app swiped away); after a phone restart, state 'not_restarted' with
// 'android_forbids_type_at_boot' | 'background_permission_required' | 'start_not_allowed'
if (e.detail.state === 'stopped') showMessage('Stopped (' + e.detail.reason + ')');
});Tangani jawaban yang berarti build atau ponsel tidak bisa melakukannya:
function startKeepAlive() {
const b = window.WebToApk;
if (!(b && typeof b.startBackgroundService === 'function')) return;
const r = JSON.parse(b.startBackgroundService(JSON.stringify({ title: 'Syncing', text: 'Uploading photos' })));
if (r.ok) return;
if (r.reason === 'not_enabled') showMessage('Keep running in background is not on in this build.');
else if (r.reason === 'type_not_declared') showMessage('This build declares no service type.');
else showMessage('Could not start: ' + r.reason);
}Gabungkan dengan loop unggah: tetap berjalan hanya selama antrean masih punya pekerjaan.
async function uploadAll(files) {
const b = window.WebToApk;
const keep = b && b.startBackgroundService &&
JSON.parse(b.startBackgroundService(JSON.stringify({ title: 'Uploading', text: '0 of ' + files.length }))).ok;
for (let i = 0; i < files.length; i++) {
await upload(files[i]);
if (keep) b.updateBackgroundService(JSON.stringify({ title: 'Uploading', text: (i + 1) + ' of ' + files.length }));
}
if (keep) b.stopBackgroundService();
}Catatan: tipe harus salah satu yang dideklarasikan build (yang dipilih di wizard, ditambah location saat Background location aktif). Menggeser aplikasi hingga tertutup menghentikan layanan keep-running kecuali Anda memberikan keepAfterSwipe: true (halaman itu sendiri sudah hilang saat itu). Play Console meminta deklarasi layanan foreground dengan video singkat untuk setiap tipe yang dideklarasikan.
isIgnoringBatteryOptimizations jembatan#
window.WebToApk.isIgnoringBatteryOptimizations(): Boolean
Apakah pengguna mengecualikan aplikasi ini dari optimisasi baterai (Doze app standby).
Contoh
Memeriksa dan meminta pengecualian optimisasi baterai, agar Doze tidak menunda pekerjaan latar belakang Anda.
Mengembalikan: isIgnoringBatteryOptimizations() β true / false. requestIgnoreBatteryOptimizations() β 'already_ignoring', 'dialog_opened' (dialog Allow/Deny sistem - hanya saat build mencentang Ask to skip battery optimisation directly), 'settings_opened' (daftar optimisasi baterai; tanpa izin, tanpa deklarasi Play) atau 'unavailable'. Membutuhkan: tidak ada untuk daftar pengaturan. Dialog langsung mendeklarasikan REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, yang diterima Play hanya jika itu fungsi inti aplikasi.
document.getElementById('reliable').addEventListener('click', function () {
const b = window.WebToApk;
if (!(b && b.isIgnoringBatteryOptimizations)) return;
if (b.isIgnoringBatteryOptimizations()) { showMessage('Already unrestricted'); return; }
const how = b.requestIgnoreBatteryOptimizations();
if (how === 'settings_opened') showMessage('Find this app in the list and choose "Not optimised".');
});Sampaikan apa yang terjadi untuk setiap jawaban.
function askBatteryExemption() {
const b = window.WebToApk;
if (!(b && b.requestIgnoreBatteryOptimizations)) { showMessage('Only available in the app'); return; }
const how = b.requestIgnoreBatteryOptimizations();
const text = {
already_ignoring: 'Already unrestricted',
dialog_opened: 'Please tap Allow',
settings_opened: 'Choose "Not optimised" for this app',
unavailable: 'This phone has no such setting'
};
showMessage(text[how] || how);
}Pasangkan dengan pelacakan latar belakang, karena Doze akan menjedanya.
if (window.WebToApk && WebToApk.startLocationUpdates) {
const r = JSON.parse(WebToApk.startLocationUpdates(JSON.stringify({ intervalMs: 30000 })));
if (r.ok && !WebToApk.isIgnoringBatteryOptimizations()) {
showMessage('For steady tracking, turn off battery optimisation for this app.');
}
}removeGeofence jembatan#
window.WebToApk.removeGeofence(id: String): Boolean
Menghapus geofence dengan id ini; false jika tidak ada.
Contoh
Didokumentasikan bersama WebToApk.addGeofence - contoh di sana menunjukkan yang ini juga.
Sebuah lingkaran yang memicu enter, exit dan/atau dwell saat aplikasi tertutup, dengan opsi memposting notifikasi. Geofence bertahan setelah ponsel dihidupkan ulang (ditambahkan kembali secara otomatis).
Mengembalikan: addGeofence β string JSON { ok: true, status: 'adding', id } atau { ok: false, reason } - not_enabled, invalid_id, invalid_position, invalid_radius (1 m β¦ 100 km), invalid_events, location_permission_required, background_permission_required, foreign_origin. Jawaban Play services datang sebagai appmint:geofence-added (window.onAppMintGeofenceAdded) = { id, ok, reason? } (location_off, too_many_geofences - 100 per aplikasi, play_services_unavailable). Sebuah transisi datang sebagai appmint:geofence (window.onAppMintGeofence) = { id, event: 'enter' | 'exit' | 'dwell', time, lat, lng, queued? } - queued: true saat terjadi ketika aplikasi tertutup dan diserahkan pada awal berikutnya. removeGeofence β true jika ada; getGeofences β array JSON dari apa yang Anda tambahkan. Membutuhkan: centang Geofences di build, dan "Allow all the time" (requestBackgroundLocation()).
function watchOffice() {
const b = window.WebToApk;
if (!(b && b.addGeofence)) return;
const r = JSON.parse(b.addGeofence(JSON.stringify({
id: 'office', lat: 51.5033, lng: -0.1196, radiusM: 150,
events: ['enter', 'exit', 'dwell'], dwellMs: 5 * 60000,
notify: {
enter: { title: 'At the office', body: 'Tap to check in' },
exit: { title: 'Left the office', body: 'Tap to check out' }
}
})));
if (!r.ok && r.reason === 'background_permission_required') b.requestBackgroundLocation();
}
window.addEventListener('appmint:geofence-added', function (e) {
if (!e.detail.ok) showMessage('Geofence ' + e.detail.id + ' not added: ' + e.detail.reason);
});
window.addEventListener('appmint:geofence', function (e) {
logVisit(e.detail.id, e.detail.event, e.detail.time);
});
console.log(JSON.parse(WebToApk.getGeofences()).map(function (g) { return g.id; }));
WebToApk.removeGeofence('office');Deteksi fitur dan laporkan setiap penolakan:
function addCircle(id, lat, lng, radiusM) {
const b = window.WebToApk;
if (!(b && b.addGeofence)) { showMessage('Place alerts need the app'); return false; }
const r = JSON.parse(b.addGeofence(JSON.stringify({ id: id, lat: lat, lng: lng, radiusM: radiusM, events: ['enter'] })));
if (r.ok) return true;
if (r.reason === 'not_enabled') showMessage('Geofences are not switched on in this build');
else if (r.reason === 'background_permission_required') b.requestBackgroundLocation();
else if (r.reason === 'invalid_radius') showMessage('Pick a radius between 1 m and 100 km');
else showMessage('Could not add the place: ' + r.reason);
return false;
}Tampilkan apa yang terdaftar dan hapus satu:
const mine = JSON.parse(WebToApk.getGeofences()); // [] when none
mine.forEach(function (g) { addRow(g.id); });
document.getElementById('forget').onclick = function () {
const existed = WebToApk.removeGeofence('office'); // true if it was there
if (!existed) showMessage('That place was not registered');
};requestBackgroundLocation jembatan#
window.WebToApk.requestBackgroundLocation()
Meminta lokasi, lalu "Allow all the time"; hasilnya datang sebagai appmint:location-permission.
Contoh
Meminta lokasi, lalu "Allow all the time" (Android 10+ memintanya terpisah; di Android 11+ langkah kedua membuka halaman pengaturan lokasi aplikasi). Geofence membutuhkannya; begitu juga memulai ulang pelacakan lokasi setelah ponsel dihidupkan ulang.
Mengembalikan: tidak ada secara langsung; jawabannya datang sebagai appmint:location-permission (dan window.onAppMintLocationPermission(detail)) = { foreground: 'granted' | 'denied', background: 'granted' | 'denied', precise: boolean, error?: 'not_enabled' }. getLocationPermissionState() β objek yang sama sebagai string JSON, tanpa bertanya. Membutuhkan: Background location atau Geofences di build.
function askAlways() {
const b = window.WebToApk;
if (!(b && b.requestBackgroundLocation)) return;
const now = JSON.parse(b.getLocationPermissionState());
if (now.background === 'granted') { enableGeofences(); return; }
// Explain first: Play requires an in-app disclosure before this request.
if (!confirm('Allow location "all the time" so we can remind you when you arrive?')) return;
b.requestBackgroundLocation();
}
window.addEventListener('appmint:location-permission', function (e) {
if (e.detail.background === 'granted') enableGeofences();
else showMessage('Choose "Allow all the time" in the location settings to use arrival reminders.');
});Periksa statusnya dulu dan jelaskan apa yang harus diketuk pengguna:
const b = window.WebToApk;
if (b && b.getLocationPermissionState) {
const s = JSON.parse(b.getLocationPermissionState());
if (s.foreground !== 'granted') showMessage('Location is off for this app.');
else if (s.background !== 'granted') showMessage('Tap "Allow all the time" to enable arrival reminders.');
else if (!s.precise) showMessage('Precise location is off; arrival alerts may be late.');
}Minta izin, lalu tambahkan geofence setelah izin diberikan:
window.addEventListener('appmint:location-permission', function (e) {
if (e.detail.error === 'not_enabled') return showMessage('This build has no background location.');
if (e.detail.background !== 'granted') return;
const r = JSON.parse(WebToApk.addGeofence(JSON.stringify({
id: 'home', lat: 51.5033, lng: -0.1196, radiusM: 120, events: ['enter']
})));
if (!r.ok) showMessage('Could not add the place: ' + r.reason);
}, { once: true });
WebToApk.requestBackgroundLocation();requestIgnoreBatteryOptimizations jembatan#
window.WebToApk.requestIgnoreBatteryOptimizations(): String
Meminta pengecualian baterai: 'already_ignoring' | 'dialog_opened' | 'settings_opened' | 'unavailable'.
Contoh
Didokumentasikan bersama WebToApk.isIgnoringBatteryOptimizations - contoh di sana menunjukkan yang ini juga.
Memeriksa dan meminta pengecualian optimisasi baterai, agar Doze tidak menunda pekerjaan latar belakang Anda.
Mengembalikan: isIgnoringBatteryOptimizations() β true / false. requestIgnoreBatteryOptimizations() β 'already_ignoring', 'dialog_opened' (dialog Allow/Deny sistem - hanya saat build mencentang Ask to skip battery optimisation directly), 'settings_opened' (daftar optimisasi baterai; tanpa izin, tanpa deklarasi Play) atau 'unavailable'. Membutuhkan: tidak ada untuk daftar pengaturan. Dialog langsung mendeklarasikan REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, yang diterima Play hanya jika itu fungsi inti aplikasi.
document.getElementById('reliable').addEventListener('click', function () {
const b = window.WebToApk;
if (!(b && b.isIgnoringBatteryOptimizations)) return;
if (b.isIgnoringBatteryOptimizations()) { showMessage('Already unrestricted'); return; }
const how = b.requestIgnoreBatteryOptimizations();
if (how === 'settings_opened') showMessage('Find this app in the list and choose "Not optimised".');
});Sampaikan apa yang terjadi untuk setiap jawaban.
function askBatteryExemption() {
const b = window.WebToApk;
if (!(b && b.requestIgnoreBatteryOptimizations)) { showMessage('Only available in the app'); return; }
const how = b.requestIgnoreBatteryOptimizations();
const text = {
already_ignoring: 'Already unrestricted',
dialog_opened: 'Please tap Allow',
settings_opened: 'Choose "Not optimised" for this app',
unavailable: 'This phone has no such setting'
};
showMessage(text[how] || how);
}Pasangkan dengan pelacakan latar belakang, karena Doze akan menjedanya.
if (window.WebToApk && WebToApk.startLocationUpdates) {
const r = JSON.parse(WebToApk.startLocationUpdates(JSON.stringify({ intervalMs: 30000 })));
if (r.ok && !WebToApk.isIgnoringBatteryOptimizations()) {
showMessage('For steady tracking, turn off battery optimisation for this app.');
}
}startBackgroundService jembatan#
window.WebToApk.startBackgroundService(optionsJson: String): String
Memulai layanan foreground aplikasi: {title, text, type?, progress?, stopLabel?, keepAfterSwipe?} β JSON {ok, status, type, notificationShown} atau {ok:false, reason}.
Contoh
Menjaga aplikasi Anda tetap berjalan saat pengguna pergi: layanan foreground Android yang sebenarnya dengan notifikasi. Selama berjalan, halaman tidak dijeda, sehingga JavaScript-nya, <audio> dan musik latar aplikasi tetap berlanjut (Android tetap memperlambat timer halaman yang tidak dilihat siapa pun).
Mengembalikan: startBackgroundService β string JSON { ok: true, status: 'starting', type, notificationShown } atau { ok: false, reason } - alasan not_enabled, invalid_options, type_not_declared, invalid_progress, location_permission_required, start_not_allowed. updateBackgroundService β { ok: true } atau { ok: false, reason: 'not_running' }. stopBackgroundService / isBackgroundServiceRunning β true / false. Perubahan status datang sebagai appmint:background-service (dan window.onAppMintBackgroundService(detail)): { state: 'running' | 'stopped' | 'failed' | 'not_restarted', reason?, types?, restored?, queued? }. Membutuhkan: centang Keep running in background (langkah Access β Background) dan pilih tipe layanan. Di Android 13+ notifikasi hanya terlihat setelah pengguna mengizinkan notifikasi (notificationShown: false jika tidak - layanan tetap berjalan).
function startWorkout() {
const b = window.WebToApk;
if (!(b && b.startBackgroundService)) return; // browser
const r = JSON.parse(b.startBackgroundService(JSON.stringify({
title: 'Workout in progress',
text: '00:00 elapsed',
stopLabel: 'Stop', // a Stop button on the notification
progress: { value: 0, max: 100 }
})));
if (!r.ok) showMessage('Could not keep running: ' + r.reason);
}
function tick(seconds) {
if (window.WebToApk && WebToApk.isBackgroundServiceRunning()) {
WebToApk.updateBackgroundService(JSON.stringify({
title: 'Workout in progress', text: seconds + ' s elapsed', stopLabel: 'Stop',
progress: { value: Math.min(100, seconds / 18), max: 100 }
}));
}
}
function finishWorkout() {
if (window.WebToApk && WebToApk.stopBackgroundService) WebToApk.stopBackgroundService();
}
window.addEventListener('appmint:background-service', function (e) {
// reason: 'user' (Stop button), 'page', 'timeout' (Android 15 dataSync 6-hour limit),
// 'task_removed' (app swiped away); after a phone restart, state 'not_restarted' with
// 'android_forbids_type_at_boot' | 'background_permission_required' | 'start_not_allowed'
if (e.detail.state === 'stopped') showMessage('Stopped (' + e.detail.reason + ')');
});Tangani jawaban yang berarti build atau ponsel tidak bisa melakukannya:
function startKeepAlive() {
const b = window.WebToApk;
if (!(b && typeof b.startBackgroundService === 'function')) return;
const r = JSON.parse(b.startBackgroundService(JSON.stringify({ title: 'Syncing', text: 'Uploading photos' })));
if (r.ok) return;
if (r.reason === 'not_enabled') showMessage('Keep running in background is not on in this build.');
else if (r.reason === 'type_not_declared') showMessage('This build declares no service type.');
else showMessage('Could not start: ' + r.reason);
}Gabungkan dengan loop unggah: tetap berjalan hanya selama antrean masih punya pekerjaan.
async function uploadAll(files) {
const b = window.WebToApk;
const keep = b && b.startBackgroundService &&
JSON.parse(b.startBackgroundService(JSON.stringify({ title: 'Uploading', text: '0 of ' + files.length }))).ok;
for (let i = 0; i < files.length; i++) {
await upload(files[i]);
if (keep) b.updateBackgroundService(JSON.stringify({ title: 'Uploading', text: (i + 1) + ' of ' + files.length }));
}
if (keep) b.stopBackgroundService();
}Catatan: tipe harus salah satu yang dideklarasikan build (yang dipilih di wizard, ditambah location saat Background location aktif). Menggeser aplikasi hingga tertutup menghentikan layanan keep-running kecuali Anda memberikan keepAfterSwipe: true (halaman itu sendiri sudah hilang saat itu). Play Console meminta deklarasi layanan foreground dengan video singkat untuk setiap tipe yang dideklarasikan.
startLocationUpdates jembatan#
window.WebToApk.startLocationUpdates(optionsJson: String): String
Pembaruan lokasi {intervalMs, minDistanceM, accuracy, background, uploadUrl?, headers?} β JSON {ok, background, backgroundPermission, precise} atau {ok:false, reason}; posisi datang sebagai appmint:location.
Contoh
Pembaruan lokasi yang terus datang saat aplikasi di latar belakang (pelacak lari, aplikasi pengantaran). Dengan background: true (default) pembaruan berjalan di dalam layanan foreground aplikasi. Setiap posisi dikirim ke halaman sebagai appmint:location selama halaman ada, ke buffer (getBufferedLocations()) saat tidak ada, dan - bila Anda memberikan uploadUrl - ke server Anda sebagai POST JSON dari kode native, sehingga pelacakan berfungsi walau halaman sudah tidak ada.
Mengembalikan: string JSON { ok: true, background, backgroundPermission, precise } atau { ok: false, reason } - not_enabled, invalid_options, invalid_interval (1 dtk β¦ 24 jam), invalid_distance, invalid_accuracy, invalid_upload_url, location_permission_required, start_not_allowed, foreign_origin. stopLocationUpdates() β true jika ada yang berjalan. Posisi: appmint:location / window.onAppMintLocation(detail) = { type: 'fix', lat, lng, accuracy, altitude?, speed?, bearing?, time, provider, background }, atau { type: 'error', reason: 'play_services_unavailable' | 'location_unavailable' | 'location_permission_required' }. Membutuhkan: centang Background location (langkah Access β Background) dan izin lokasi pengguna terlebih dahulu.
function startTracking(token) {
const b = window.WebToApk;
if (!(b && b.startLocationUpdates)) return;
navigator.geolocation.getCurrentPosition(function () { // asks for location first
const r = JSON.parse(b.startLocationUpdates(JSON.stringify({
intervalMs: 10000, minDistanceM: 10, accuracy: 'high', background: true,
uploadUrl: 'https://api.example.com/track',
headers: { Authorization: 'Bearer ' + token }
})));
if (!r.ok) showMessage('Tracking not started: ' + r.reason);
});
}
window.addEventListener('appmint:location', function (e) {
if (e.detail.type === 'fix') drawPoint(e.detail.lat, e.detail.lng);
else showMessage('Location stopped: ' + e.detail.reason);
});
function stopTracking() { if (window.WebToApk) WebToApk.stopLocationUpdates(); }Laporkan opsi yang salah atau izin yang hilang dengan reason:
function tryTrack() {
const b = window.WebToApk;
if (!(b && typeof b.startLocationUpdates === 'function')) {
showMessage('Background tracking needs the installed app.');
return;
}
const r = JSON.parse(b.startLocationUpdates(JSON.stringify({ intervalMs: 500 })));
if (!r.ok && r.reason === 'invalid_interval') showMessage('Interval must be 1 second or more.');
if (!r.ok && r.reason === 'location_permission_required') showMessage('Allow location first.');
}Pasangan alami dengan buffer: berhenti di akhir shift dan unggah apa yang direkam selama halaman tidak aktif.
async function endShift() {
if (!window.WebToApk) return;
WebToApk.stopLocationUpdates();
const points = JSON.parse(WebToApk.getBufferedLocations());
if (points.length) {
await fetch('/api/shift/points', { method: 'POST', body: JSON.stringify(points) });
WebToApk.clearBufferedLocations();
}
}Catatan: layanan lokasi yang dimulai dari aplikasi terus mendapat posisi di latar belakang tanpa "Allow all the time"; memulainya ulang setelah ponsel dihidupkan ulang membutuhkannya (requestBackgroundLocation()). POST yang gagal diserahkan ke WorkManager dan dikirim saat jaringan kembali. Ponsel tanpa Google Play services menjawab play_services_unavailable. Play Console membutuhkan deklarasi lokasi latar belakang.
stopBackgroundService jembatan#
window.WebToApk.stopBackgroundService(): Boolean
Menghentikan layanan yang dimulai oleh startBackgroundService (lokasi latar belakang, jika berjalan, tetap berlanjut).
Contoh
Didokumentasikan bersama WebToApk.startBackgroundService - contoh di sana menunjukkan yang ini juga.
Menjaga aplikasi Anda tetap berjalan saat pengguna pergi: layanan foreground Android yang sebenarnya dengan notifikasi. Selama berjalan, halaman tidak dijeda, sehingga JavaScript-nya, <audio> dan musik latar aplikasi tetap berlanjut (Android tetap memperlambat timer halaman yang tidak dilihat siapa pun).
Mengembalikan: startBackgroundService β string JSON { ok: true, status: 'starting', type, notificationShown } atau { ok: false, reason } - alasan not_enabled, invalid_options, type_not_declared, invalid_progress, location_permission_required, start_not_allowed. updateBackgroundService β { ok: true } atau { ok: false, reason: 'not_running' }. stopBackgroundService / isBackgroundServiceRunning β true / false. Perubahan status datang sebagai appmint:background-service (dan window.onAppMintBackgroundService(detail)): { state: 'running' | 'stopped' | 'failed' | 'not_restarted', reason?, types?, restored?, queued? }. Membutuhkan: centang Keep running in background (langkah Access β Background) dan pilih tipe layanan. Di Android 13+ notifikasi hanya terlihat setelah pengguna mengizinkan notifikasi (notificationShown: false jika tidak - layanan tetap berjalan).
function startWorkout() {
const b = window.WebToApk;
if (!(b && b.startBackgroundService)) return; // browser
const r = JSON.parse(b.startBackgroundService(JSON.stringify({
title: 'Workout in progress',
text: '00:00 elapsed',
stopLabel: 'Stop', // a Stop button on the notification
progress: { value: 0, max: 100 }
})));
if (!r.ok) showMessage('Could not keep running: ' + r.reason);
}
function tick(seconds) {
if (window.WebToApk && WebToApk.isBackgroundServiceRunning()) {
WebToApk.updateBackgroundService(JSON.stringify({
title: 'Workout in progress', text: seconds + ' s elapsed', stopLabel: 'Stop',
progress: { value: Math.min(100, seconds / 18), max: 100 }
}));
}
}
function finishWorkout() {
if (window.WebToApk && WebToApk.stopBackgroundService) WebToApk.stopBackgroundService();
}
window.addEventListener('appmint:background-service', function (e) {
// reason: 'user' (Stop button), 'page', 'timeout' (Android 15 dataSync 6-hour limit),
// 'task_removed' (app swiped away); after a phone restart, state 'not_restarted' with
// 'android_forbids_type_at_boot' | 'background_permission_required' | 'start_not_allowed'
if (e.detail.state === 'stopped') showMessage('Stopped (' + e.detail.reason + ')');
});Tangani jawaban yang berarti build atau ponsel tidak bisa melakukannya:
function startKeepAlive() {
const b = window.WebToApk;
if (!(b && typeof b.startBackgroundService === 'function')) return;
const r = JSON.parse(b.startBackgroundService(JSON.stringify({ title: 'Syncing', text: 'Uploading photos' })));
if (r.ok) return;
if (r.reason === 'not_enabled') showMessage('Keep running in background is not on in this build.');
else if (r.reason === 'type_not_declared') showMessage('This build declares no service type.');
else showMessage('Could not start: ' + r.reason);
}Gabungkan dengan loop unggah: tetap berjalan hanya selama antrean masih punya pekerjaan.
async function uploadAll(files) {
const b = window.WebToApk;
const keep = b && b.startBackgroundService &&
JSON.parse(b.startBackgroundService(JSON.stringify({ title: 'Uploading', text: '0 of ' + files.length }))).ok;
for (let i = 0; i < files.length; i++) {
await upload(files[i]);
if (keep) b.updateBackgroundService(JSON.stringify({ title: 'Uploading', text: (i + 1) + ' of ' + files.length }));
}
if (keep) b.stopBackgroundService();
}Catatan: tipe harus salah satu yang dideklarasikan build (yang dipilih di wizard, ditambah location saat Background location aktif). Menggeser aplikasi hingga tertutup menghentikan layanan keep-running kecuali Anda memberikan keepAfterSwipe: true (halaman itu sendiri sudah hilang saat itu). Play Console meminta deklarasi layanan foreground dengan video singkat untuk setiap tipe yang dideklarasikan.
stopLocationUpdates jembatan#
window.WebToApk.stopLocationUpdates(): Boolean
Menghentikan pembaruan lokasi yang dimulai oleh startLocationUpdates; false jika tidak ada yang berjalan.
Contoh
Didokumentasikan bersama WebToApk.startLocationUpdates - contoh di sana menunjukkan yang ini juga.
Pembaruan lokasi yang terus datang saat aplikasi di latar belakang (pelacak lari, aplikasi pengantaran). Dengan background: true (default) pembaruan berjalan di dalam layanan foreground aplikasi. Setiap posisi dikirim ke halaman sebagai appmint:location selama halaman ada, ke buffer (getBufferedLocations()) saat tidak ada, dan - bila Anda memberikan uploadUrl - ke server Anda sebagai POST JSON dari kode native, sehingga pelacakan berfungsi walau halaman sudah tidak ada.
Mengembalikan: string JSON { ok: true, background, backgroundPermission, precise } atau { ok: false, reason } - not_enabled, invalid_options, invalid_interval (1 dtk β¦ 24 jam), invalid_distance, invalid_accuracy, invalid_upload_url, location_permission_required, start_not_allowed, foreign_origin. stopLocationUpdates() β true jika ada yang berjalan. Posisi: appmint:location / window.onAppMintLocation(detail) = { type: 'fix', lat, lng, accuracy, altitude?, speed?, bearing?, time, provider, background }, atau { type: 'error', reason: 'play_services_unavailable' | 'location_unavailable' | 'location_permission_required' }. Membutuhkan: centang Background location (langkah Access β Background) dan izin lokasi pengguna terlebih dahulu.
function startTracking(token) {
const b = window.WebToApk;
if (!(b && b.startLocationUpdates)) return;
navigator.geolocation.getCurrentPosition(function () { // asks for location first
const r = JSON.parse(b.startLocationUpdates(JSON.stringify({
intervalMs: 10000, minDistanceM: 10, accuracy: 'high', background: true,
uploadUrl: 'https://api.example.com/track',
headers: { Authorization: 'Bearer ' + token }
})));
if (!r.ok) showMessage('Tracking not started: ' + r.reason);
});
}
window.addEventListener('appmint:location', function (e) {
if (e.detail.type === 'fix') drawPoint(e.detail.lat, e.detail.lng);
else showMessage('Location stopped: ' + e.detail.reason);
});
function stopTracking() { if (window.WebToApk) WebToApk.stopLocationUpdates(); }Laporkan opsi yang salah atau izin yang hilang dengan reason:
function tryTrack() {
const b = window.WebToApk;
if (!(b && typeof b.startLocationUpdates === 'function')) {
showMessage('Background tracking needs the installed app.');
return;
}
const r = JSON.parse(b.startLocationUpdates(JSON.stringify({ intervalMs: 500 })));
if (!r.ok && r.reason === 'invalid_interval') showMessage('Interval must be 1 second or more.');
if (!r.ok && r.reason === 'location_permission_required') showMessage('Allow location first.');
}Pasangan alami dengan buffer: berhenti di akhir shift dan unggah apa yang direkam selama halaman tidak aktif.
async function endShift() {
if (!window.WebToApk) return;
WebToApk.stopLocationUpdates();
const points = JSON.parse(WebToApk.getBufferedLocations());
if (points.length) {
await fetch('/api/shift/points', { method: 'POST', body: JSON.stringify(points) });
WebToApk.clearBufferedLocations();
}
}Catatan: layanan lokasi yang dimulai dari aplikasi terus mendapat posisi di latar belakang tanpa "Allow all the time"; memulainya ulang setelah ponsel dihidupkan ulang membutuhkannya (requestBackgroundLocation()). POST yang gagal diserahkan ke WorkManager dan dikirim saat jaringan kembali. Ponsel tanpa Google Play services menjawab play_services_unavailable. Play Console membutuhkan deklarasi lokasi latar belakang.
updateBackgroundService jembatan#
window.WebToApk.updateBackgroundService(optionsJson: String): String
Mengubah notifikasi layanan yang sedang berjalan (opsi sama seperti startBackgroundService) β JSON {ok} atau {ok:false, reason:'not_running'}.
Contoh
Didokumentasikan bersama WebToApk.startBackgroundService - contoh di sana menunjukkan yang ini juga.
Menjaga aplikasi Anda tetap berjalan saat pengguna pergi: layanan foreground Android yang sebenarnya dengan notifikasi. Selama berjalan, halaman tidak dijeda, sehingga JavaScript-nya, <audio> dan musik latar aplikasi tetap berlanjut (Android tetap memperlambat timer halaman yang tidak dilihat siapa pun).
Mengembalikan: startBackgroundService β string JSON { ok: true, status: 'starting', type, notificationShown } atau { ok: false, reason } - alasan not_enabled, invalid_options, type_not_declared, invalid_progress, location_permission_required, start_not_allowed. updateBackgroundService β { ok: true } atau { ok: false, reason: 'not_running' }. stopBackgroundService / isBackgroundServiceRunning β true / false. Perubahan status datang sebagai appmint:background-service (dan window.onAppMintBackgroundService(detail)): { state: 'running' | 'stopped' | 'failed' | 'not_restarted', reason?, types?, restored?, queued? }. Membutuhkan: centang Keep running in background (langkah Access β Background) dan pilih tipe layanan. Di Android 13+ notifikasi hanya terlihat setelah pengguna mengizinkan notifikasi (notificationShown: false jika tidak - layanan tetap berjalan).
function startWorkout() {
const b = window.WebToApk;
if (!(b && b.startBackgroundService)) return; // browser
const r = JSON.parse(b.startBackgroundService(JSON.stringify({
title: 'Workout in progress',
text: '00:00 elapsed',
stopLabel: 'Stop', // a Stop button on the notification
progress: { value: 0, max: 100 }
})));
if (!r.ok) showMessage('Could not keep running: ' + r.reason);
}
function tick(seconds) {
if (window.WebToApk && WebToApk.isBackgroundServiceRunning()) {
WebToApk.updateBackgroundService(JSON.stringify({
title: 'Workout in progress', text: seconds + ' s elapsed', stopLabel: 'Stop',
progress: { value: Math.min(100, seconds / 18), max: 100 }
}));
}
}
function finishWorkout() {
if (window.WebToApk && WebToApk.stopBackgroundService) WebToApk.stopBackgroundService();
}
window.addEventListener('appmint:background-service', function (e) {
// reason: 'user' (Stop button), 'page', 'timeout' (Android 15 dataSync 6-hour limit),
// 'task_removed' (app swiped away); after a phone restart, state 'not_restarted' with
// 'android_forbids_type_at_boot' | 'background_permission_required' | 'start_not_allowed'
if (e.detail.state === 'stopped') showMessage('Stopped (' + e.detail.reason + ')');
});Tangani jawaban yang berarti build atau ponsel tidak bisa melakukannya:
function startKeepAlive() {
const b = window.WebToApk;
if (!(b && typeof b.startBackgroundService === 'function')) return;
const r = JSON.parse(b.startBackgroundService(JSON.stringify({ title: 'Syncing', text: 'Uploading photos' })));
if (r.ok) return;
if (r.reason === 'not_enabled') showMessage('Keep running in background is not on in this build.');
else if (r.reason === 'type_not_declared') showMessage('This build declares no service type.');
else showMessage('Could not start: ' + r.reason);
}Gabungkan dengan loop unggah: tetap berjalan hanya selama antrean masih punya pekerjaan.
async function uploadAll(files) {
const b = window.WebToApk;
const keep = b && b.startBackgroundService &&
JSON.parse(b.startBackgroundService(JSON.stringify({ title: 'Uploading', text: '0 of ' + files.length }))).ok;
for (let i = 0; i < files.length; i++) {
await upload(files[i]);
if (keep) b.updateBackgroundService(JSON.stringify({ title: 'Uploading', text: (i + 1) + ' of ' + files.length }));
}
if (keep) b.stopBackgroundService();
}Catatan: tipe harus salah satu yang dideklarasikan build (yang dipilih di wizard, ditambah location saat Background location aktif). Menggeser aplikasi hingga tertutup menghentikan layanan keep-running kecuali Anda memberikan keepAfterSwipe: true (halaman itu sendiri sudah hilang saat itu). Play Console meminta deklarasi layanan foreground dengan video singkat untuk setiap tipe yang dideklarasikan.