JavaScript ब्रिज API
बैकग्राउंड में चलना
एक फ़ोरग्राउंड सर्विस जिसे पेज शुरू और बंद करता है, ऐप बैकग्राउंड में होने पर भी आता रहने वाला लोकेशन, ऐप बंद होने पर चलने वाले जियोफ़ेंस, और रीस्टार्ट के बाद समय-समय पर चलने वाला आपका अपना कोड। हर एक के लिए बिल्ड में उसका स्विच और Play Console घोषणा चाहिए।
AppMint.background हेल्पर#
AppMint.background.register(name, options) / unregister / list / runNow / done / isBackgroundRun / currentRun / onRun
उदाहरण
ऐप बंद होने पर भी आपके पेज का अपना कोड समय-समय पर चलाता है - डेटा रिफ़्रेश करें, कोई कीमत जाँचें, नोटिफ़िकेशन भेजें। हर रन आपके पेज को अदृश्य रूप से लोड करता है (वही origin, वही localStorage/IndexedDB, कोई स्क्रीन नहीं, कोई विज्ञापन नहीं) ?appmint_background=1&appmint_task=<name>&appmint_run=<runId> के साथ, लोड होने पर एक बार appmint:background { name, runId } भेजता है, और done(runId, { ok }) का इंतज़ार करता है। रन लगभग 9 मिनट बाद काट दिया जाता है।
लौटाता है: हर मेथड Promise लौटाता है। register → { ok: true, name, intervalMinutes } या { 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 } (शर्तें पूरी होते ही एक रन - टेस्ट के लिए)। done → रन खत्म होने पर true। isBackgroundRun() और currentRun() सिंक्रोनस हैं। ज़रूरी: बंद होने पर पेज का कोड चलाएँ टिक करें (Access चरण → Background)। वेबसाइट और ऑफ़लाइन/ZIP ऐप; दस्तावेज़ और मीडिया ऐप में चलाने के लिए कोई पेज कोड नहीं होता।
एक पेज, दो भूमिकाएँ:
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();देर से माउंट होने वाले पेज (React, lazy route) onRun इस्तेमाल करें, जो तब भी चलता है जब रन पहले ही शुरू हो चुका हो, या पेज हुक:
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()); };मैनेज करें:
AppMint.background.list().then(function (tasks) { console.table(tasks); });
AppMint.background.runNow('prices');
AppMint.background.unregister('prices');ध्यान दें: सही समय Android तय करता है; 15 मिनट सबसे छोटा अंतराल है और बैटरी सेविंग रन में देरी कर सकती है। फ़ोन रीस्टार्ट के बाद शुरू करें के साथ हर टास्क रीस्टार्ट के बाद भी एक बार चलता है। रन के WebToApk में सिर्फ़ notify, showNotification, लोकेशन बफ़र, जियोफ़ेंस, workEnqueueOnline, isBackgroundServiceRunning और ये टास्क मेथड होते हैं; बाकी सब गायब रहता है (फ़ीचर की जाँच करें)।
addGeofence ब्रिज#
window.WebToApk.addGeofence(json: String): String
जियोफ़ेंस जोड़ता है {id, lat, lng, radiusM, events, dwellMs?, notify?} → JSON {ok, status:'adding'} या {ok:false, reason}; नतीजा है appmint:geofence-added.
उदाहरण
एक घेरा जो ऐप बंद होने पर enter, exit और/या dwell चलाता है, चाहें तो नोटिफ़िकेशन भी भेजता है। जियोफ़ेंस फ़ोन रीस्टार्ट के बाद भी बने रहते हैं (वे अपने आप दोबारा जुड़ जाते हैं)।
लौटाता है: addGeofence → JSON स्ट्रिंग { ok: true, status: 'adding', id } या { 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। Play services का जवाब appmint:geofence-added (window.onAppMintGeofenceAdded) = { id, ok, reason? } (location_off, too_many_geofences - हर ऐप के लिए 100, play_services_unavailable) के रूप में आता है। ट्रांज़िशन appmint:geofence (window.onAppMintGeofence) = { id, event: 'enter' | 'exit' | 'dwell', time, lat, lng, queued? } के रूप में आता है - ऐप बंद होने के दौरान हुआ हो तो queued: true, और अगले स्टार्ट पर सौंप दिया जाता है। removeGeofence → मौजूद होने पर true; getGeofences → आपके जोड़े हुए की JSON ऐरे। ज़रूरी: बिल्ड में जियोफ़ेंस टिक करें, और "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');फ़ीचर की जाँच करें और हर इनकार की सूचना दें:
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;
}जो रजिस्टर है उसे देखें और एक हटाएँ:
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 ब्रिज#
window.WebToApk.backgroundDone(runId: String, resultJson: String): Boolean
AppMint.background.done(runId, result): बैकग्राउंड रन को खत्म करता है; ऐप में खुद हमेशा false रहता है।
उदाहरण
WebToApk.backgroundRegister के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
AppMint.background के पीछे के कच्चे मेथड - AppMint.background.register(...) इस्तेमाल करें (यह promise लौटाता है और रन इवेंट संभालता है)। यहाँ इसलिए दिए गए हैं ताकि हर ब्रिज मेथड का एक उदाहरण हो।
लौटाता है: backgroundRegister → JSON { ok: true, name, intervalMinutes } या { ok: false, reason } (not_enabled, invalid_name - अक्षर, अंक, _, -, 64 तक - interval_below_15_minutes, invalid_interval, schedule_failed)। backgroundUnregister → मौजूद होने पर true। backgroundList → JSON ऐरे। backgroundRunNow → JSON { ok, name } या { ok: false, reason: 'not_registered' }। backgroundDone(runId, resultJson) → बैकग्राउंड रन में true, ऐप में हमेशा false। isBackgroundRun() → ऐप में false, बैकग्राउंड रन में true। ज़रूरी: बंद होने पर पेज का कोड चलाएँ टिक करें.
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 }))
}फ़ीचर की जाँच करें और ऐप के रन को बैकग्राउंड रन से अलग पहचानें:
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'
}किसी टास्क को टेस्ट करें और साफ़-सफ़ाई करें:
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 ब्रिज#
window.WebToApk.backgroundList(): String
AppMint.background.list(): JSON ऐरे {name, intervalMinutes, requiresNetwork, requiresCharging, registeredAt, lastRunAt, lastResult}।
उदाहरण
WebToApk.backgroundRegister के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
AppMint.background के पीछे के कच्चे मेथड - AppMint.background.register(...) इस्तेमाल करें (यह promise लौटाता है और रन इवेंट संभालता है)। यहाँ इसलिए दिए गए हैं ताकि हर ब्रिज मेथड का एक उदाहरण हो।
लौटाता है: backgroundRegister → JSON { ok: true, name, intervalMinutes } या { ok: false, reason } (not_enabled, invalid_name - अक्षर, अंक, _, -, 64 तक - interval_below_15_minutes, invalid_interval, schedule_failed)। backgroundUnregister → मौजूद होने पर true। backgroundList → JSON ऐरे। backgroundRunNow → JSON { ok, name } या { ok: false, reason: 'not_registered' }। backgroundDone(runId, resultJson) → बैकग्राउंड रन में true, ऐप में हमेशा false। isBackgroundRun() → ऐप में false, बैकग्राउंड रन में true। ज़रूरी: बंद होने पर पेज का कोड चलाएँ टिक करें.
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 }))
}फ़ीचर की जाँच करें और ऐप के रन को बैकग्राउंड रन से अलग पहचानें:
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'
}किसी टास्क को टेस्ट करें और साफ़-सफ़ाई करें:
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 ब्रिज#
window.WebToApk.backgroundRegister(name: String, optionsJson: String): String
AppMint.background.register(name, {intervalMinutes >= 15, requiresNetwork, requiresCharging}) → JSON {ok, name, intervalMinutes} या {ok:false, reason}।
उदाहरण
AppMint.background के पीछे के कच्चे मेथड - AppMint.background.register(...) इस्तेमाल करें (यह promise लौटाता है और रन इवेंट संभालता है)। यहाँ इसलिए दिए गए हैं ताकि हर ब्रिज मेथड का एक उदाहरण हो।
लौटाता है: backgroundRegister → JSON { ok: true, name, intervalMinutes } या { ok: false, reason } (not_enabled, invalid_name - अक्षर, अंक, _, -, 64 तक - interval_below_15_minutes, invalid_interval, schedule_failed)। backgroundUnregister → मौजूद होने पर true। backgroundList → JSON ऐरे। backgroundRunNow → JSON { ok, name } या { ok: false, reason: 'not_registered' }। backgroundDone(runId, resultJson) → बैकग्राउंड रन में true, ऐप में हमेशा false। isBackgroundRun() → ऐप में false, बैकग्राउंड रन में true। ज़रूरी: बंद होने पर पेज का कोड चलाएँ टिक करें.
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 }))
}फ़ीचर की जाँच करें और ऐप के रन को बैकग्राउंड रन से अलग पहचानें:
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'
}किसी टास्क को टेस्ट करें और साफ़-सफ़ाई करें:
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 ब्रिज#
window.WebToApk.backgroundRunNow(name: String): String
AppMint.background.runNow(name): शर्तें पूरी होते ही एक बैकग्राउंड रन।
उदाहरण
WebToApk.backgroundRegister के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
AppMint.background के पीछे के कच्चे मेथड - AppMint.background.register(...) इस्तेमाल करें (यह promise लौटाता है और रन इवेंट संभालता है)। यहाँ इसलिए दिए गए हैं ताकि हर ब्रिज मेथड का एक उदाहरण हो।
लौटाता है: backgroundRegister → JSON { ok: true, name, intervalMinutes } या { ok: false, reason } (not_enabled, invalid_name - अक्षर, अंक, _, -, 64 तक - interval_below_15_minutes, invalid_interval, schedule_failed)। backgroundUnregister → मौजूद होने पर true। backgroundList → JSON ऐरे। backgroundRunNow → JSON { ok, name } या { ok: false, reason: 'not_registered' }। backgroundDone(runId, resultJson) → बैकग्राउंड रन में true, ऐप में हमेशा false। isBackgroundRun() → ऐप में false, बैकग्राउंड रन में true। ज़रूरी: बंद होने पर पेज का कोड चलाएँ टिक करें.
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 }))
}फ़ीचर की जाँच करें और ऐप के रन को बैकग्राउंड रन से अलग पहचानें:
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'
}किसी टास्क को टेस्ट करें और साफ़-सफ़ाई करें:
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 ब्रिज#
window.WebToApk.backgroundUnregister(name: String): Boolean
AppMint.background.unregister(name); जब उस नाम का कोई टास्क नहीं था तो false।
उदाहरण
WebToApk.backgroundRegister के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
AppMint.background के पीछे के कच्चे मेथड - AppMint.background.register(...) इस्तेमाल करें (यह promise लौटाता है और रन इवेंट संभालता है)। यहाँ इसलिए दिए गए हैं ताकि हर ब्रिज मेथड का एक उदाहरण हो।
लौटाता है: backgroundRegister → JSON { ok: true, name, intervalMinutes } या { ok: false, reason } (not_enabled, invalid_name - अक्षर, अंक, _, -, 64 तक - interval_below_15_minutes, invalid_interval, schedule_failed)। backgroundUnregister → मौजूद होने पर true। backgroundList → JSON ऐरे। backgroundRunNow → JSON { ok, name } या { ok: false, reason: 'not_registered' }। backgroundDone(runId, resultJson) → बैकग्राउंड रन में true, ऐप में हमेशा false। isBackgroundRun() → ऐप में false, बैकग्राउंड रन में true। ज़रूरी: बंद होने पर पेज का कोड चलाएँ टिक करें.
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 }))
}फ़ीचर की जाँच करें और ऐप के रन को बैकग्राउंड रन से अलग पहचानें:
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'
}किसी टास्क को टेस्ट करें और साफ़-सफ़ाई करें:
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 ब्रिज#
window.WebToApk.clearBufferedLocations(): Boolean
getBufferedLocations जो बफ़र पढ़ता है उसे खाली करता है (पॉइंट सेव करने के बाद इसे कॉल करें)।
उदाहरण
WebToApk.getBufferedLocations के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
पेज के दूर रहने (ऐप बैकग्राउंड में या बंद) के दौरान दर्ज हुए फ़िक्स, सबसे पुराना पहले, 10,000 तक।
लौटाता है: getBufferedLocations() → { type: 'fix', lat, lng, accuracy, time, …, background: true } की JSON स्ट्रिंग ऐरे; बैकग्राउंड लोकेशन बंद होने पर '[]'। clearBufferedLocations() → खाली होने पर true। ज़रूरी: बिल्ड में बैकग्राउंड लोकेशन।
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(); });ट्रैकिंग शुरू करें, फिर इनकार को संभालें। स्टार्ट कॉल 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, ...
}पेज खुला होने पर लाइव फ़िक्स appmint:location के रूप में आते हैं; बाकी बफ़र में रहते हैं।
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 ब्रिज#
window.WebToApk.clearGeofenceEvents(): Boolean
getGeofenceEvents जो ट्रांज़िशन इतिहास पढ़ता है उसे खाली करता है।
उदाहरण
WebToApk.getGeofenceEvents के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
पिछले 100 जियोफ़ेंस ट्रांज़िशन, सबसे पुराना पहले - उन सहित जो ऐप बंद होने पर हुए। अगर आपका पेज देर से माउंट होता है और कतार में लगे appmint:geofence इवेंट छूट सकते हैं, तो शुरू में इसे पढ़ें।
लौटाता है: getGeofenceEvents() → { id, event, time, lat, lng } की JSON स्ट्रिंग ऐरे; clearGeofenceEvents() → true। ज़रूरी: बिल्ड में जियोफ़ेंस।
if (window.WebToApk && WebToApk.getGeofenceEvents) {
JSON.parse(WebToApk.getGeofenceEvents()).forEach(function (ev) {
logVisit(ev.id, ev.event, ev.time);
});
WebToApk.clearGeofenceEvents();
}जियोफ़ेंस जोड़ें, फिर ट्रांज़िशन पर नज़र रखें जब तक पेज खुला है।
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);
});जो रजिस्टर है उसे देखें और एक हटाएँ जब यूज़र किसी फ़ीचर से बाहर जाए।
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 ब्रिज#
window.WebToApk.getBufferedLocations(): String
पेज के दूर रहने के दौरान दर्ज हुए फ़िक्स की JSON ऐरे, सबसे पुराना पहले (10,000 तक)।
उदाहरण
पेज के दूर रहने (ऐप बैकग्राउंड में या बंद) के दौरान दर्ज हुए फ़िक्स, सबसे पुराना पहले, 10,000 तक।
लौटाता है: getBufferedLocations() → { type: 'fix', lat, lng, accuracy, time, …, background: true } की JSON स्ट्रिंग ऐरे; बैकग्राउंड लोकेशन बंद होने पर '[]'। clearBufferedLocations() → खाली होने पर true। ज़रूरी: बिल्ड में बैकग्राउंड लोकेशन।
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(); });ट्रैकिंग शुरू करें, फिर इनकार को संभालें। स्टार्ट कॉल 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, ...
}पेज खुला होने पर लाइव फ़िक्स appmint:location के रूप में आते हैं; बाकी बफ़र में रहते हैं।
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 ब्रिज#
window.WebToApk.getGeofenceEvents(): String
पिछले 100 जियोफ़ेंस ट्रांज़िशन {id, event, time, lat, lng} की JSON ऐरे, सबसे पुराना पहले।
उदाहरण
पिछले 100 जियोफ़ेंस ट्रांज़िशन, सबसे पुराना पहले - उन सहित जो ऐप बंद होने पर हुए। अगर आपका पेज देर से माउंट होता है और कतार में लगे appmint:geofence इवेंट छूट सकते हैं, तो शुरू में इसे पढ़ें।
लौटाता है: getGeofenceEvents() → { id, event, time, lat, lng } की JSON स्ट्रिंग ऐरे; clearGeofenceEvents() → true। ज़रूरी: बिल्ड में जियोफ़ेंस।
if (window.WebToApk && WebToApk.getGeofenceEvents) {
JSON.parse(WebToApk.getGeofenceEvents()).forEach(function (ev) {
logVisit(ev.id, ev.event, ev.time);
});
WebToApk.clearGeofenceEvents();
}जियोफ़ेंस जोड़ें, फिर ट्रांज़िशन पर नज़र रखें जब तक पेज खुला है।
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);
});जो रजिस्टर है उसे देखें और एक हटाएँ जब यूज़र किसी फ़ीचर से बाहर जाए।
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 ब्रिज#
window.WebToApk.getGeofences(): String
इस ऐप के जोड़े हुए जियोफ़ेंस की JSON ऐरे (वे रीस्टार्ट के बाद भी बने रहते हैं)।
उदाहरण
WebToApk.addGeofence के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
एक घेरा जो ऐप बंद होने पर enter, exit और/या dwell चलाता है, चाहें तो नोटिफ़िकेशन भी भेजता है। जियोफ़ेंस फ़ोन रीस्टार्ट के बाद भी बने रहते हैं (वे अपने आप दोबारा जुड़ जाते हैं)।
लौटाता है: addGeofence → JSON स्ट्रिंग { ok: true, status: 'adding', id } या { 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। Play services का जवाब appmint:geofence-added (window.onAppMintGeofenceAdded) = { id, ok, reason? } (location_off, too_many_geofences - हर ऐप के लिए 100, play_services_unavailable) के रूप में आता है। ट्रांज़िशन appmint:geofence (window.onAppMintGeofence) = { id, event: 'enter' | 'exit' | 'dwell', time, lat, lng, queued? } के रूप में आता है - ऐप बंद होने के दौरान हुआ हो तो queued: true, और अगले स्टार्ट पर सौंप दिया जाता है। removeGeofence → मौजूद होने पर true; getGeofences → आपके जोड़े हुए की JSON ऐरे। ज़रूरी: बिल्ड में जियोफ़ेंस टिक करें, और "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');फ़ीचर की जाँच करें और हर इनकार की सूचना दें:
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;
}जो रजिस्टर है उसे देखें और एक हटाएँ:
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 ब्रिज#
window.WebToApk.getLocationPermissionState(): String
JSON {foreground:'granted'|'denied', background:'granted'|'denied', precise: boolean}।
उदाहरण
WebToApk.requestBackgroundLocation के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
लोकेशन माँगता है, फिर "Allow all the time" के लिए (Android 10+ दोनों अलग-अलग माँगता है; Android 11+ पर दूसरा चरण ऐप का लोकेशन सेटिंग्स पेज खोलता है)। जियोफ़ेंस को यह चाहिए; फ़ोन रीस्टार्ट के बाद लोकेशन ट्रैकिंग दोबारा शुरू करने के लिए भी।
लौटाता है: सीधे कुछ नहीं; जवाब appmint:location-permission (और window.onAppMintLocationPermission(detail)) = { foreground: 'granted' | 'denied', background: 'granted' | 'denied', precise: boolean, error?: 'not_enabled' } के रूप में आता है। getLocationPermissionState() → वही ऑब्जेक्ट JSON स्ट्रिंग के रूप में, बिना पूछे। ज़रूरी: बिल्ड में बैकग्राउंड लोकेशन या जियोफ़ेंस।
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.');
});पहले स्थिति जाँचें और बताएँ कि यूज़र को क्या टैप करना है:
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.');
}अनुमति माँगें, फिर मिलने के बाद जियोफ़ेंस जोड़ें:
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 ब्रिज#
window.WebToApk.isBackgroundRun(): Boolean
यहाँ false: ऐप का अपना पेज कभी बैकग्राउंड रन नहीं होता (हेडलेस रन true लौटाता है)।
उदाहरण
WebToApk.backgroundRegister के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
AppMint.background के पीछे के कच्चे मेथड - AppMint.background.register(...) इस्तेमाल करें (यह promise लौटाता है और रन इवेंट संभालता है)। यहाँ इसलिए दिए गए हैं ताकि हर ब्रिज मेथड का एक उदाहरण हो।
लौटाता है: backgroundRegister → JSON { ok: true, name, intervalMinutes } या { ok: false, reason } (not_enabled, invalid_name - अक्षर, अंक, _, -, 64 तक - interval_below_15_minutes, invalid_interval, schedule_failed)। backgroundUnregister → मौजूद होने पर true। backgroundList → JSON ऐरे। backgroundRunNow → JSON { ok, name } या { ok: false, reason: 'not_registered' }। backgroundDone(runId, resultJson) → बैकग्राउंड रन में true, ऐप में हमेशा false। isBackgroundRun() → ऐप में false, बैकग्राउंड रन में true। ज़रूरी: बंद होने पर पेज का कोड चलाएँ टिक करें.
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 }))
}फ़ीचर की जाँच करें और ऐप के रन को बैकग्राउंड रन से अलग पहचानें:
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'
}किसी टास्क को टेस्ट करें और साफ़-सफ़ाई करें:
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 ब्रिज#
window.WebToApk.isBackgroundServiceRunning(): Boolean
क्या ऐप की फ़ोरग्राउंड सर्विस चल रही है (keep-running या बैकग्राउंड लोकेशन, किसी के लिए भी)।
उदाहरण
WebToApk.startBackgroundService के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
यूज़र के दूर रहने पर भी आपका ऐप चलता रखता है: नोटिफ़िकेशन वाली असली Android फ़ोरग्राउंड सर्विस। इसके चलने तक पेज पॉज़ नहीं होता, इसलिए उसका JavaScript, <audio> और ऐप का बैकग्राउंड म्यूज़िक चलते रहते हैं (जिस पेज को कोई देख नहीं सकता उसके टाइमर Android फिर भी धीमे कर देता है)।
लौटाता है: startBackgroundService → JSON स्ट्रिंग { ok: true, status: 'starting', type, notificationShown } या { ok: false, reason } - कारण not_enabled, invalid_options, type_not_declared, invalid_progress, location_permission_required, start_not_allowed। updateBackgroundService → { ok: true } या { ok: false, reason: 'not_running' }। stopBackgroundService / isBackgroundServiceRunning → true / false। स्थिति बदलाव appmint:background-service (और window.onAppMintBackgroundService(detail)) के रूप में आते हैं: { state: 'running' | 'stopped' | 'failed' | 'not_restarted', reason?, types?, restored?, queued? }। ज़रूरी: बैकग्राउंड में चलते रहें टिक करें (Access चरण → Background) और सर्विस टाइप चुनें। Android 13+ पर नोटिफ़िकेशन तभी दिखता है जब यूज़र ने नोटिफ़िकेशन की अनुमति दी हो (वरना notificationShown: false - सर्विस फिर भी चलती है)।
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 + ')');
});उन जवाबों को संभालें जिनका मतलब है कि बिल्ड या फ़ोन यह नहीं कर सकता:
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);
}इसे अपलोड लूप के साथ जोड़ें: सिर्फ़ तब चलते रहें जब कतार में काम हो।
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();
}ध्यान दें: टाइप वही होना चाहिए जो बिल्ड ने घोषित किया हो (विज़ार्ड में चुना गया, और बैकग्राउंड लोकेशन चालू होने पर location)। ऐप को स्वाइप करके हटाने पर keep-running सर्विस रुक जाती है, जब तक आप keepAfterSwipe: true न दें (तब पेज खुद चला जाता है)। Play Console हर घोषित टाइप के लिए छोटे वीडियो के साथ फ़ोरग्राउंड-सर्विस घोषणा माँगता है।
isIgnoringBatteryOptimizations ब्रिज#
window.WebToApk.isIgnoringBatteryOptimizations(): Boolean
क्या यूज़र ने इस ऐप को बैटरी ऑप्टिमाइज़ेशन (Doze ऐप स्टैंडबाय) से छूट दी है।
उदाहरण
बैटरी-ऑप्टिमाइज़ेशन की छूट जाँचता और माँगता है, ताकि Doze आपका बैकग्राउंड काम टाल न दे।
लौटाता है: isIgnoringBatteryOptimizations() → true / false। requestIgnoreBatteryOptimizations() → 'already_ignoring', 'dialog_opened' (सिस्टम का Allow/Deny डायलॉग - सिर्फ़ तब जब बिल्ड में Ask to skip battery optimisation directly टिक किया गया हो), 'settings_opened' (बैटरी-ऑप्टिमाइज़ेशन की सूची; कोई अनुमति नहीं, कोई Play घोषणा नहीं) या 'unavailable'। ज़रूरी: सेटिंग्स की सूची के लिए कुछ नहीं। सीधा डायलॉग REQUEST_IGNORE_BATTERY_OPTIMIZATIONS घोषित करता है, जिसे Play तभी मानता है जब वह ऐप का मुख्य काम हो।
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".');
});बताएँ कि क्या हुआ हर जवाब के लिए।
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);
}इसे बैकग्राउंड ट्रैकिंग के साथ जोड़ें, क्योंकि Doze इसे रोक देगा।
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 ब्रिज#
window.WebToApk.removeGeofence(id: String): Boolean
इस id वाला जियोफ़ेंस हटाता है; कोई नहीं था तो false।
उदाहरण
WebToApk.addGeofence के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
एक घेरा जो ऐप बंद होने पर enter, exit और/या dwell चलाता है, चाहें तो नोटिफ़िकेशन भी भेजता है। जियोफ़ेंस फ़ोन रीस्टार्ट के बाद भी बने रहते हैं (वे अपने आप दोबारा जुड़ जाते हैं)।
लौटाता है: addGeofence → JSON स्ट्रिंग { ok: true, status: 'adding', id } या { 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। Play services का जवाब appmint:geofence-added (window.onAppMintGeofenceAdded) = { id, ok, reason? } (location_off, too_many_geofences - हर ऐप के लिए 100, play_services_unavailable) के रूप में आता है। ट्रांज़िशन appmint:geofence (window.onAppMintGeofence) = { id, event: 'enter' | 'exit' | 'dwell', time, lat, lng, queued? } के रूप में आता है - ऐप बंद होने के दौरान हुआ हो तो queued: true, और अगले स्टार्ट पर सौंप दिया जाता है। removeGeofence → मौजूद होने पर true; getGeofences → आपके जोड़े हुए की JSON ऐरे। ज़रूरी: बिल्ड में जियोफ़ेंस टिक करें, और "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');फ़ीचर की जाँच करें और हर इनकार की सूचना दें:
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;
}जो रजिस्टर है उसे देखें और एक हटाएँ:
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 ब्रिज#
window.WebToApk.requestBackgroundLocation()
लोकेशन की अनुमति माँगता है, फिर "Allow all the time"; नतीजा इस रूप में आता है appmint:location-permission.
उदाहरण
लोकेशन माँगता है, फिर "Allow all the time" के लिए (Android 10+ दोनों अलग-अलग माँगता है; Android 11+ पर दूसरा चरण ऐप का लोकेशन सेटिंग्स पेज खोलता है)। जियोफ़ेंस को यह चाहिए; फ़ोन रीस्टार्ट के बाद लोकेशन ट्रैकिंग दोबारा शुरू करने के लिए भी।
लौटाता है: सीधे कुछ नहीं; जवाब appmint:location-permission (और window.onAppMintLocationPermission(detail)) = { foreground: 'granted' | 'denied', background: 'granted' | 'denied', precise: boolean, error?: 'not_enabled' } के रूप में आता है। getLocationPermissionState() → वही ऑब्जेक्ट JSON स्ट्रिंग के रूप में, बिना पूछे। ज़रूरी: बिल्ड में बैकग्राउंड लोकेशन या जियोफ़ेंस।
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.');
});पहले स्थिति जाँचें और बताएँ कि यूज़र को क्या टैप करना है:
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.');
}अनुमति माँगें, फिर मिलने के बाद जियोफ़ेंस जोड़ें:
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 ब्रिज#
window.WebToApk.requestIgnoreBatteryOptimizations(): String
बैटरी की छूट माँगता है: 'already_ignoring' | 'dialog_opened' | 'settings_opened' | 'unavailable'।
उदाहरण
WebToApk.isIgnoringBatteryOptimizations के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
बैटरी-ऑप्टिमाइज़ेशन की छूट जाँचता और माँगता है, ताकि Doze आपका बैकग्राउंड काम टाल न दे।
लौटाता है: isIgnoringBatteryOptimizations() → true / false। requestIgnoreBatteryOptimizations() → 'already_ignoring', 'dialog_opened' (सिस्टम का Allow/Deny डायलॉग - सिर्फ़ तब जब बिल्ड में Ask to skip battery optimisation directly टिक किया गया हो), 'settings_opened' (बैटरी-ऑप्टिमाइज़ेशन की सूची; कोई अनुमति नहीं, कोई Play घोषणा नहीं) या 'unavailable'। ज़रूरी: सेटिंग्स की सूची के लिए कुछ नहीं। सीधा डायलॉग REQUEST_IGNORE_BATTERY_OPTIMIZATIONS घोषित करता है, जिसे Play तभी मानता है जब वह ऐप का मुख्य काम हो।
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".');
});बताएँ कि क्या हुआ हर जवाब के लिए।
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);
}इसे बैकग्राउंड ट्रैकिंग के साथ जोड़ें, क्योंकि Doze इसे रोक देगा।
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 ब्रिज#
window.WebToApk.startBackgroundService(optionsJson: String): String
ऐप की फ़ोरग्राउंड सर्विस शुरू करता है: {title, text, type?, progress?, stopLabel?, keepAfterSwipe?} → JSON {ok, status, type, notificationShown} या {ok:false, reason}।
उदाहरण
यूज़र के दूर रहने पर भी आपका ऐप चलता रखता है: नोटिफ़िकेशन वाली असली Android फ़ोरग्राउंड सर्विस। इसके चलने तक पेज पॉज़ नहीं होता, इसलिए उसका JavaScript, <audio> और ऐप का बैकग्राउंड म्यूज़िक चलते रहते हैं (जिस पेज को कोई देख नहीं सकता उसके टाइमर Android फिर भी धीमे कर देता है)।
लौटाता है: startBackgroundService → JSON स्ट्रिंग { ok: true, status: 'starting', type, notificationShown } या { ok: false, reason } - कारण not_enabled, invalid_options, type_not_declared, invalid_progress, location_permission_required, start_not_allowed। updateBackgroundService → { ok: true } या { ok: false, reason: 'not_running' }। stopBackgroundService / isBackgroundServiceRunning → true / false। स्थिति बदलाव appmint:background-service (और window.onAppMintBackgroundService(detail)) के रूप में आते हैं: { state: 'running' | 'stopped' | 'failed' | 'not_restarted', reason?, types?, restored?, queued? }। ज़रूरी: बैकग्राउंड में चलते रहें टिक करें (Access चरण → Background) और सर्विस टाइप चुनें। Android 13+ पर नोटिफ़िकेशन तभी दिखता है जब यूज़र ने नोटिफ़िकेशन की अनुमति दी हो (वरना notificationShown: false - सर्विस फिर भी चलती है)।
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 + ')');
});उन जवाबों को संभालें जिनका मतलब है कि बिल्ड या फ़ोन यह नहीं कर सकता:
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);
}इसे अपलोड लूप के साथ जोड़ें: सिर्फ़ तब चलते रहें जब कतार में काम हो।
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();
}ध्यान दें: टाइप वही होना चाहिए जो बिल्ड ने घोषित किया हो (विज़ार्ड में चुना गया, और बैकग्राउंड लोकेशन चालू होने पर location)। ऐप को स्वाइप करके हटाने पर keep-running सर्विस रुक जाती है, जब तक आप keepAfterSwipe: true न दें (तब पेज खुद चला जाता है)। Play Console हर घोषित टाइप के लिए छोटे वीडियो के साथ फ़ोरग्राउंड-सर्विस घोषणा माँगता है।
startLocationUpdates ब्रिज#
window.WebToApk.startLocationUpdates(optionsJson: String): String
लोकेशन अपडेट {intervalMs, minDistanceM, accuracy, background, uploadUrl?, headers?} → JSON {ok, background, backgroundPermission, precise} या {ok:false, reason}; फ़िक्स इस रूप में आते हैं appmint:location.
उदाहरण
लोकेशन अपडेट जो ऐप के बैकग्राउंड में होने पर भी आते रहते हैं (रन ट्रैकर, डिलीवरी ऐप)। background: true (डिफ़ॉल्ट) के साथ वे ऐप की फ़ोरग्राउंड सर्विस के अंदर चलते हैं। हर फ़िक्स पेज मौजूद होने पर उसे appmint:location के रूप में जाता है, पेज न होने पर बफ़र (getBufferedLocations()) में, और - जब आप uploadUrl देते हैं - नेटिव कोड से आपके सर्वर पर JSON POST के रूप में, इसलिए पेज के न रहने पर भी ट्रैकिंग चलती है।
लौटाता है: JSON स्ट्रिंग { ok: true, background, backgroundPermission, precise } या { ok: false, reason } - not_enabled, invalid_options, invalid_interval (1 s … 24 h), invalid_distance, invalid_accuracy, invalid_upload_url, location_permission_required, start_not_allowed, foreign_origin। stopLocationUpdates() → कुछ चल रहा था तो true। फ़िक्स: appmint:location / window.onAppMintLocation(detail) = { type: 'fix', lat, lng, accuracy, altitude?, speed?, bearing?, time, provider, background }, या { type: 'error', reason: 'play_services_unavailable' | 'location_unavailable' | 'location_permission_required' }। ज़रूरी: बैकग्राउंड लोकेशन टिक करें (Access चरण → Background) और पहले यूज़र की लोकेशन अनुमति।
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(); }गलत विकल्प या गायब अनुमति की सूचना जवाब के इस हिस्से से दें 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.');
}बफ़र के साथ एक अच्छी जोड़ी: शिफ़्ट के अंत में रुकें और पेज के दूर रहने के दौरान जो रिकॉर्ड हुआ उसे अपलोड करें।
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();
}
}ध्यान दें: ऐप से शुरू की गई लोकेशन सर्विस "Allow all the time" के बिना भी बैकग्राउंड में फ़िक्स पाती रहती है; फ़ोन रीस्टार्ट के बाद उसे दोबारा शुरू करने के लिए यह चाहिए (requestBackgroundLocation())। जो POST फ़ेल हो जाता है वह WorkManager को सौंपा जाता है और नेटवर्क लौटने पर भेजा जाता है। Google Play services के बिना फ़ोन play_services_unavailable से जवाब देते हैं। Play Console को बैकग्राउंड-लोकेशन घोषणा चाहिए।
stopBackgroundService ब्रिज#
window.WebToApk.stopBackgroundService(): Boolean
startBackgroundService से शुरू की गई सर्विस को रोकता है (बैकग्राउंड लोकेशन, अगर चल रहा हो, चलता रहता है)।
उदाहरण
WebToApk.startBackgroundService के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
यूज़र के दूर रहने पर भी आपका ऐप चलता रखता है: नोटिफ़िकेशन वाली असली Android फ़ोरग्राउंड सर्विस। इसके चलने तक पेज पॉज़ नहीं होता, इसलिए उसका JavaScript, <audio> और ऐप का बैकग्राउंड म्यूज़िक चलते रहते हैं (जिस पेज को कोई देख नहीं सकता उसके टाइमर Android फिर भी धीमे कर देता है)।
लौटाता है: startBackgroundService → JSON स्ट्रिंग { ok: true, status: 'starting', type, notificationShown } या { ok: false, reason } - कारण not_enabled, invalid_options, type_not_declared, invalid_progress, location_permission_required, start_not_allowed। updateBackgroundService → { ok: true } या { ok: false, reason: 'not_running' }। stopBackgroundService / isBackgroundServiceRunning → true / false। स्थिति बदलाव appmint:background-service (और window.onAppMintBackgroundService(detail)) के रूप में आते हैं: { state: 'running' | 'stopped' | 'failed' | 'not_restarted', reason?, types?, restored?, queued? }। ज़रूरी: बैकग्राउंड में चलते रहें टिक करें (Access चरण → Background) और सर्विस टाइप चुनें। Android 13+ पर नोटिफ़िकेशन तभी दिखता है जब यूज़र ने नोटिफ़िकेशन की अनुमति दी हो (वरना notificationShown: false - सर्विस फिर भी चलती है)।
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 + ')');
});उन जवाबों को संभालें जिनका मतलब है कि बिल्ड या फ़ोन यह नहीं कर सकता:
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);
}इसे अपलोड लूप के साथ जोड़ें: सिर्फ़ तब चलते रहें जब कतार में काम हो।
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();
}ध्यान दें: टाइप वही होना चाहिए जो बिल्ड ने घोषित किया हो (विज़ार्ड में चुना गया, और बैकग्राउंड लोकेशन चालू होने पर location)। ऐप को स्वाइप करके हटाने पर keep-running सर्विस रुक जाती है, जब तक आप keepAfterSwipe: true न दें (तब पेज खुद चला जाता है)। Play Console हर घोषित टाइप के लिए छोटे वीडियो के साथ फ़ोरग्राउंड-सर्विस घोषणा माँगता है।
stopLocationUpdates ब्रिज#
window.WebToApk.stopLocationUpdates(): Boolean
startLocationUpdates से शुरू किए गए लोकेशन अपडेट रोकता है; अगर कोई नहीं चल रहा था तो false।
उदाहरण
WebToApk.startLocationUpdates के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
लोकेशन अपडेट जो ऐप के बैकग्राउंड में होने पर भी आते रहते हैं (रन ट्रैकर, डिलीवरी ऐप)। background: true (डिफ़ॉल्ट) के साथ वे ऐप की फ़ोरग्राउंड सर्विस के अंदर चलते हैं। हर फ़िक्स पेज मौजूद होने पर उसे appmint:location के रूप में जाता है, पेज न होने पर बफ़र (getBufferedLocations()) में, और - जब आप uploadUrl देते हैं - नेटिव कोड से आपके सर्वर पर JSON POST के रूप में, इसलिए पेज के न रहने पर भी ट्रैकिंग चलती है।
लौटाता है: JSON स्ट्रिंग { ok: true, background, backgroundPermission, precise } या { ok: false, reason } - not_enabled, invalid_options, invalid_interval (1 s … 24 h), invalid_distance, invalid_accuracy, invalid_upload_url, location_permission_required, start_not_allowed, foreign_origin। stopLocationUpdates() → कुछ चल रहा था तो true। फ़िक्स: appmint:location / window.onAppMintLocation(detail) = { type: 'fix', lat, lng, accuracy, altitude?, speed?, bearing?, time, provider, background }, या { type: 'error', reason: 'play_services_unavailable' | 'location_unavailable' | 'location_permission_required' }। ज़रूरी: बैकग्राउंड लोकेशन टिक करें (Access चरण → Background) और पहले यूज़र की लोकेशन अनुमति।
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(); }गलत विकल्प या गायब अनुमति की सूचना जवाब के इस हिस्से से दें 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.');
}बफ़र के साथ एक अच्छी जोड़ी: शिफ़्ट के अंत में रुकें और पेज के दूर रहने के दौरान जो रिकॉर्ड हुआ उसे अपलोड करें।
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();
}
}ध्यान दें: ऐप से शुरू की गई लोकेशन सर्विस "Allow all the time" के बिना भी बैकग्राउंड में फ़िक्स पाती रहती है; फ़ोन रीस्टार्ट के बाद उसे दोबारा शुरू करने के लिए यह चाहिए (requestBackgroundLocation())। जो POST फ़ेल हो जाता है वह WorkManager को सौंपा जाता है और नेटवर्क लौटने पर भेजा जाता है। Google Play services के बिना फ़ोन play_services_unavailable से जवाब देते हैं। Play Console को बैकग्राउंड-लोकेशन घोषणा चाहिए।
updateBackgroundService ब्रिज#
window.WebToApk.updateBackgroundService(optionsJson: String): String
चल रही सर्विस का नोटिफ़िकेशन बदलता है (विकल्प वही जो startBackgroundService में) → JSON {ok} या {ok:false, reason:'not_running'}।
उदाहरण
WebToApk.startBackgroundService के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।
यूज़र के दूर रहने पर भी आपका ऐप चलता रखता है: नोटिफ़िकेशन वाली असली Android फ़ोरग्राउंड सर्विस। इसके चलने तक पेज पॉज़ नहीं होता, इसलिए उसका JavaScript, <audio> और ऐप का बैकग्राउंड म्यूज़िक चलते रहते हैं (जिस पेज को कोई देख नहीं सकता उसके टाइमर Android फिर भी धीमे कर देता है)।
लौटाता है: startBackgroundService → JSON स्ट्रिंग { ok: true, status: 'starting', type, notificationShown } या { ok: false, reason } - कारण not_enabled, invalid_options, type_not_declared, invalid_progress, location_permission_required, start_not_allowed। updateBackgroundService → { ok: true } या { ok: false, reason: 'not_running' }। stopBackgroundService / isBackgroundServiceRunning → true / false। स्थिति बदलाव appmint:background-service (और window.onAppMintBackgroundService(detail)) के रूप में आते हैं: { state: 'running' | 'stopped' | 'failed' | 'not_restarted', reason?, types?, restored?, queued? }। ज़रूरी: बैकग्राउंड में चलते रहें टिक करें (Access चरण → Background) और सर्विस टाइप चुनें। Android 13+ पर नोटिफ़िकेशन तभी दिखता है जब यूज़र ने नोटिफ़िकेशन की अनुमति दी हो (वरना notificationShown: false - सर्विस फिर भी चलती है)।
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 + ')');
});उन जवाबों को संभालें जिनका मतलब है कि बिल्ड या फ़ोन यह नहीं कर सकता:
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);
}इसे अपलोड लूप के साथ जोड़ें: सिर्फ़ तब चलते रहें जब कतार में काम हो।
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();
}ध्यान दें: टाइप वही होना चाहिए जो बिल्ड ने घोषित किया हो (विज़ार्ड में चुना गया, और बैकग्राउंड लोकेशन चालू होने पर location)। ऐप को स्वाइप करके हटाने पर keep-running सर्विस रुक जाती है, जब तक आप keepAfterSwipe: true न दें (तब पेज खुद चला जाता है)। Play Console हर घोषित टाइप के लिए छोटे वीडियो के साथ फ़ोरग्राउंड-सर्विस घोषणा माँगता है।