API del bridge JavaScript
Notifiche sul dispositivo
Pubblicare e programmare senza un server, l'autorizzazione POST_NOTIFICATIONS, le sveglie esatte e i suoni personalizzati.
AppMint.enableNotifications helper#
AppMint.enableNotifications()
Esempio
"Attiva le notifiche" in una sola chiamata, per gli utenti che hanno rifiutato o saltato la richiesta di notifica di Android: la finestra di autorizzazione finché Android può ancora mostrarla, altrimenti le impostazioni di notifica di questa app, e il nuovo stato quando l'utente torna.
Restituisce: AppMint.enableNotifications(): una Promise che si risolve sempre {state, changed, openedSettings}; state è 'granted' | 'prompt' | 'blocked' | 'unavailable'. AppMint.getNotificationState(): una Promise di quello stato. AppMint.openNotificationSettings(): una Promise di true quando la schermata delle impostazioni si è aperta. Richiede: chiama enableNotifications() da un pulsante toccato dall'utente; le notifiche richiedono Notifiche (o Push / Promemoria) nella build.
// A banner that only shows while notifications are off, and turns them on in one tap.
async function setupNotifBanner() {
if (!(window.AppMint && AppMint.enableNotifications)) return; // a browser: no banner
var banner = document.getElementById('notif-banner');
var state = await AppMint.getNotificationState();
banner.hidden = !(state === 'prompt' || state === 'blocked');
document.getElementById('notif-turn-on').onclick = async function () {
var r = await AppMint.enableNotifications();
banner.hidden = r.state === 'granted';
if (r.state === 'blocked') showToast('Switch on "Allow notifications" to get updates.');
};
}
setupNotifBanner();Un semplice link "Impostazioni notifiche" nella tua pagina delle impostazioni:
document.getElementById('notif-settings').onclick = async function () {
var opened = window.AppMint && AppMint.openNotificationSettings && await AppMint.openNotificationSettings();
if (!opened) showToast('Open Settings > Apps > this app > Notifications.');
};Note: un pulsante di un push o di un messaggio in-app il cui link è appmint://notifications/enable esegue lo stesso flusso senza alcun codice nella pagina (la pagina riceve appmint:notifications). Il pubblico push dell'app ("Notifiche attive / disattivate") si aggiorna non appena l'utente le attiva.
AppMint.getNotificationState helper#
window.AppMint.getNotificationState
Esempio
Documentato insieme a AppMint.enableNotifications - l'esempio lì mostra anche questo.
"Attiva le notifiche" in una sola chiamata, per gli utenti che hanno rifiutato o saltato la richiesta di notifica di Android: la finestra di autorizzazione finché Android può ancora mostrarla, altrimenti le impostazioni di notifica di questa app, e il nuovo stato quando l'utente torna.
Restituisce: AppMint.enableNotifications(): una Promise che si risolve sempre {state, changed, openedSettings}; state è 'granted' | 'prompt' | 'blocked' | 'unavailable'. AppMint.getNotificationState(): una Promise di quello stato. AppMint.openNotificationSettings(): una Promise di true quando la schermata delle impostazioni si è aperta. Richiede: chiama enableNotifications() da un pulsante toccato dall'utente; le notifiche richiedono Notifiche (o Push / Promemoria) nella build.
// A banner that only shows while notifications are off, and turns them on in one tap.
async function setupNotifBanner() {
if (!(window.AppMint && AppMint.enableNotifications)) return; // a browser: no banner
var banner = document.getElementById('notif-banner');
var state = await AppMint.getNotificationState();
banner.hidden = !(state === 'prompt' || state === 'blocked');
document.getElementById('notif-turn-on').onclick = async function () {
var r = await AppMint.enableNotifications();
banner.hidden = r.state === 'granted';
if (r.state === 'blocked') showToast('Switch on "Allow notifications" to get updates.');
};
}
setupNotifBanner();Un semplice link "Impostazioni notifiche" nella tua pagina delle impostazioni:
document.getElementById('notif-settings').onclick = async function () {
var opened = window.AppMint && AppMint.openNotificationSettings && await AppMint.openNotificationSettings();
if (!opened) showToast('Open Settings > Apps > this app > Notifications.');
};Note: un pulsante di un push o di un messaggio in-app il cui link è appmint://notifications/enable esegue lo stesso flusso senza alcun codice nella pagina (la pagina riceve appmint:notifications). Il pubblico push dell'app ("Notifiche attive / disattivate") si aggiorna non appena l'utente le attiva.
AppMint.openNotificationSettings helper#
window.AppMint.openNotificationSettings
Esempio
Documentato insieme a AppMint.enableNotifications - l'esempio lì mostra anche questo.
"Attiva le notifiche" in una sola chiamata, per gli utenti che hanno rifiutato o saltato la richiesta di notifica di Android: la finestra di autorizzazione finché Android può ancora mostrarla, altrimenti le impostazioni di notifica di questa app, e il nuovo stato quando l'utente torna.
Restituisce: AppMint.enableNotifications(): una Promise che si risolve sempre {state, changed, openedSettings}; state è 'granted' | 'prompt' | 'blocked' | 'unavailable'. AppMint.getNotificationState(): una Promise di quello stato. AppMint.openNotificationSettings(): una Promise di true quando la schermata delle impostazioni si è aperta. Richiede: chiama enableNotifications() da un pulsante toccato dall'utente; le notifiche richiedono Notifiche (o Push / Promemoria) nella build.
// A banner that only shows while notifications are off, and turns them on in one tap.
async function setupNotifBanner() {
if (!(window.AppMint && AppMint.enableNotifications)) return; // a browser: no banner
var banner = document.getElementById('notif-banner');
var state = await AppMint.getNotificationState();
banner.hidden = !(state === 'prompt' || state === 'blocked');
document.getElementById('notif-turn-on').onclick = async function () {
var r = await AppMint.enableNotifications();
banner.hidden = r.state === 'granted';
if (r.state === 'blocked') showToast('Switch on "Allow notifications" to get updates.');
};
}
setupNotifBanner();Un semplice link "Impostazioni notifiche" nella tua pagina delle impostazioni:
document.getElementById('notif-settings').onclick = async function () {
var opened = window.AppMint && AppMint.openNotificationSettings && await AppMint.openNotificationSettings();
if (!opened) showToast('Open Settings > Apps > this app > Notifications.');
};Note: un pulsante di un push o di un messaggio in-app il cui link è appmint://notifications/enable esegue lo stesso flusso senza alcun codice nella pagina (la pagina riceve appmint:notifications). Il pubblico push dell'app ("Notifiche attive / disattivate") si aggiorna non appena l'utente le attiva.
Notification standard web#
new Notification(title, options) / Notification.requestPermission()
Esempio
L'API Web Notifications standard funziona dentro l'app: new Notification() mostra una vera notifica Android, close() la rimuove e Notification.requestPermission() mostra la finestra di autorizzazione di Android e attende la risposta dell'utente.
Restituisce: Notification.permission è 'granted', 'denied' o 'default', letto in tempo reale dal telefono (una modifica nelle Impostazioni si vede senza ricaricare). requestPermission() restituisce una Promise di 'granted' o 'denied' (funziona anche la forma con callback). Una nuova notifica attiva show quando viene pubblicata, oppure error quando manca l'autorizzazione. Richiede: attiva Notifiche nel passaggio Accesso (Passaggio 4) quando crei l'app.
async function notifyWhenSaved() {
if (!('Notification' in window)) return;
let perm = Notification.permission;
if (perm === 'default') perm = await Notification.requestPermission();
if (perm !== 'granted') {
showMessage('Turn on notifications for this app in Settings to get alerts.');
return;
}
const n = new Notification('Saved', {
body: 'Your note was saved',
icon: 'https://example.com/avatar.png', // shown as the large icon
image: 'https://example.com/note.jpg', // big picture
tag: 'note' // same tag replaces the old one
});
n.onshow = function () { console.log('posted'); };
n.onerror = function () { console.log('not posted'); };
setTimeout(function () { n.close(); }, 60000); // removes it from the shade
}
document.getElementById('save').addEventListener('click', notifyWhenSaved);Forma con callback (codice più vecchio):
Notification.requestPermission(function (result) {
if (result === 'granted') new Notification('Welcome!', { body: 'Alerts are on', silent: true });
});Stile service worker (codice PWA) pubblica anch'esso tramite l'app, ma solo dove la WebView stessa non ha navigator.serviceWorker (per esempio pagine file:// o http://):
if ('serviceWorker' in navigator && Notification.permission === 'granted') {
navigator.serviceWorker.ready.then(function (reg) {
return reg.showNotification('Backup done', { body: '12 files', tag: 'backup' });
});
}Un tocco attiva click sulla notifica: l'app passa in primo piano e la pagina lo riceve. Se l'app era chiusa (il tocco l'ha avviata), l'oggetto non esiste più, quindi la finestra riceve invece un evento notificationclick, con la stessa forma di quello di un service worker - event.notification.tag / title / body / data:
const n = new Notification('Order shipped', { body: '#7', tag: 'order-7', data: { orderId: 7 } });
n.onclick = () => openOrder(7); // the app was running
window.addEventListener('notificationclick', (e) => { // the tap started the app
if (e.notification.data && e.notification.data.orderId) openOrder(e.notification.data.orderId);
});Note: opzioni usate: body, icon, image, tag, silent, data (JSON, sotto i 16 KB). Il tocco raggiunge la pagina attraverso le schermate di avvio e PIN (evento sottostante: appmint:notification-click). Su Android 12 e precedenti non c'è autorizzazione a runtime, quindi è 'granted' a meno che l'utente abbia disattivato le notifiche. Web Push (pushManager.subscribe) non è supportato; usa AppMint Push. Per pulsanti, avanzamento o una notifica fissa usa WebToApk.notify(...). Lo stesso codice funziona in un normale browser.
__badgeSupported bridge#
window.WebToApk.__badgeSupported(): Boolean
Se questo launcher può mostrare un conteggio sul badge (navigator.setAppBadge esiste solo in quel caso).
Esempio
Trasporto interno dietro la presenza di navigator.setAppBadge. Le pagine usano l'API standard; non chiamarlo mai direttamente: i metodi __ possono cambiare senza preavviso.
Restituisce: true quando il launcher di questo telefono mostra i conteggi sul badge. Richiede: nulla da attivare.
Usa l'API pubblica:
if ('setAppBadge' in navigator) navigator.setAppBadge(unreadCount);Mostra l'impostazione "badge sull'icona dell'app" solo sui telefoni il cui launcher può mostrare un conteggio:
function renderBadgeSetting() {
const row = document.getElementById('badge-setting');
// setAppBadge exists only when this launcher shows counts
row.hidden = !('setAppBadge' in navigator);
}
renderBadgeSetting();Azzera il conteggio quando l'utente apre la posta in arrivo, su qualsiasi launcher che ne abbia uno:
function openInbox() {
showInbox();
if ('clearAppBadge' in navigator) {
navigator.clearAppBadge().catch(function (e) {
console.warn('badge not cleared', e.name); // NotAllowedError
});
}
}Note: L'API Badging è installata solo dove il launcher può mostrare un conteggio (Samsung, Huawei, Xiaomi, OPPO, Sony, …); sui launcher in stile Pixel è assente, come in un browser senza badging.
__closeNotification bridge#
window.WebToApk.__closeNotification(tag: String): Boolean
Notification.close(): rimuove una notifica pubblicata dalla pagina, tramite il suo tag.
Esempio
Infrastruttura interna dietro Notification.prototype.close(): le pagine usano new Notification(...) e chiamano close() su di esso. Rimuove una notifica dall'area notifiche tramite il suo tag.
Restituisce: true quando la richiesta di rimozione è stata fatta (anche quando nessuna notifica aveva quel tag); false in caso di errore interno. Richiede: nulla.
Usa l'API pubblica:
let uploadNote = null;
function showUploading() {
if (!('Notification' in window) || Notification.permission !== 'granted') return;
uploadNote = new Notification('Uploading…', { body: 'Keep the app open', tag: 'upload', silent: true });
uploadNote.onclose = function () { uploadNote = null; };
}
function uploadFinished() {
if (uploadNote) uploadNote.close(); // removes it from the notification shade
}Apri la chat giusta quando la notifica viene toccata, poi rimuovila dall'area notifiche:
function notifyNewMessage(msg) {
if (!('Notification' in window) || Notification.permission !== 'granted') return;
const n = new Notification(msg.from, {
body: msg.text,
tag: 'chat-' + msg.threadId, // one notification per chat
data: { threadId: msg.threadId }
});
n.onclick = function () {
openThread(n.data.threadId);
n.close();
};
}Mostra una breve conferma che si rimuove da sola dopo cinque secondi:
function confirmCopied() {
if (!('Notification' in window) || Notification.permission !== 'granted') return;
const n = new Notification('Link copied', { body: 'Paste it anywhere', tag: 'copied', silent: true });
setTimeout(function () { n.close(); }, 5000);
}Note: non chiamare WebToApk.__closeNotification direttamente; i metodi __ possono cambiare senza preavviso. close() attiva l'evento close della notifica.
__setAppBadge bridge#
window.WebToApk.__setAppBadge(contents: Long): Boolean
navigator.setAppBadge(n): n >= 0 è un conteggio (0 lo azzera), -1 il badge a bandierina della specifica.
Esempio
Trasporto interno dietro navigator.setAppBadge(count) / clearAppBadge(). Le pagine usano l'API standard; non chiamarlo mai direttamente: i metodi __ possono cambiare senza preavviso.
Restituisce: true quando il conteggio è stato applicato. Richiede: nulla da attivare.
Usa l'API pubblica:
if ('setAppBadge' in navigator) navigator.setAppBadge(unreadCount);Tieni il conteggio sull'icona allineato al conteggio dei non letti e azzeralo a zero:
async function syncBadge(unread) {
if (!('setAppBadge' in navigator)) return;
try {
if (unread > 0) await navigator.setAppBadge(unread);
else await navigator.clearAppBadge();
} catch (e) {
console.warn('badge not applied', e.name); // NotAllowedError when the launcher refused it
}
}
syncBadge(messages.filter(function (m) { return !m.read; }).length);Metti un badge a bandierina (senza numero) sull'icona finché c'è del lavoro non sincronizzato:
function markPendingSync(hasPending) {
if (!('setAppBadge' in navigator)) return;
const p = hasPending
? navigator.setAppBadge() // no argument = flag badge; a count launcher shows 1
: navigator.clearAppBadge();
p.catch(function () {});
}Note: -1 è il badge a bandierina della specifica (senza numero), che un launcher con conteggio mostra come 1.
cancelAllNotifications bridge#
window.WebToApk.cancelAllNotifications(): Boolean
Lettura e richiesta dell'autorizzazione POST_NOTIFICATIONS, e gestione delle notifiche già programmate dalla pagina. La pubblicazione e la programmazione sono documentate nei rispettivi metodi.
Descritto dal suo gruppo, Autorizzazione di notifica, annullamento ed elenco, anziché da solo.
Esempio
Annulla ogni promemoria programmato da questa app.
Restituisce: true quando è fatto; false solo in caso di errore interno. Richiede: nient'altro.
document.getElementById('reset-reminders').addEventListener('click', function () {
if (!(window.WebToApk && window.WebToApk.cancelAllNotifications)) return;
if (!confirm('Remove all your reminders?')) return;
const ok = WebToApk.cancelAllNotifications();
showMessage(ok ? 'All reminders removed' : 'Could not remove reminders');
});Alla disconnessione, ferma i promemoria dell'utente precedente e azzera il conteggio sull'icona:
async function signOut() {
if (window.WebToApk && window.WebToApk.cancelAllNotifications) {
WebToApk.cancelAllNotifications();
}
if ('clearAppBadge' in navigator) navigator.clearAppBadge().catch(function () {});
await auth.signOut();
showLoginScreen();
}Ricostruisci l'intera programmazione giornaliera dagli orari salvati (annulla tutto, poi aggiungi ciascuno):
function applyMedicineTimes(times) { // e.g. ['08:00', '20:00']
const b = window.WebToApk;
if (!(b && b.cancelAllNotifications)) return;
b.cancelAllNotifications();
times.forEach(function (hhmm, i) {
const parts = hhmm.split(':');
const at = new Date();
at.setHours(Number(parts[0]), Number(parts[1]), 0, 0);
if (at.getTime() <= Date.now()) at.setDate(at.getDate() + 1); // next occurrence
b.scheduleNotification('med-' + i, 'Medicine', 'Time for your ' + hhmm + ' dose',
String(at.getTime()), 'daily');
});
}Note: svuota l'elenco programmato, quindi nulla scatta più tardi e nulla viene reimpostato dopo un riavvio. Le notifiche già visibili nell'area notifiche restano lì.
cancelNotification bridge#
window.WebToApk.cancelNotification(id: String): Boolean
Lettura e richiesta dell'autorizzazione POST_NOTIFICATIONS, e gestione delle notifiche già programmate dalla pagina. La pubblicazione e la programmazione sono documentate nei rispettivi metodi.
Descritto dal suo gruppo, Autorizzazione di notifica, annullamento ed elenco, anziché da solo.
Esempio
Annulla un promemoria programmato tramite il suo id, così non scatterà più.
Restituisce: true (anche quando nessun promemoria aveva quell'id); false solo in caso di errore interno. Richiede: nient'altro (i promemoria richiedono ⏰ Promemoria in fase di build).
function stopWaterReminder() {
if (!(window.WebToApk && window.WebToApk.cancelNotification)) return;
WebToApk.cancelNotification('water'); // the id you gave scheduleNotification / scheduleNotificationEx
// Check it is gone:
const left = JSON.parse(WebToApk.getScheduledNotifications() || '[]');
const stillThere = left.some(function (r) { return r.id === 'water'; });
console.log('water reminder still scheduled?', stillThere); // false
}Un interruttore per i promemoria nelle impostazioni che programma o annulla con lo stesso id:
document.getElementById('water-toggle').addEventListener('change', function (e) {
const b = window.WebToApk;
if (!(b && b.cancelNotification && b.scheduleNotification)) return;
if (e.target.checked) {
b.scheduleNotification('water', 'Drink water', 'Time for a glass of water',
String(Date.now() + 60 * 60 * 1000), 'hourly');
} else {
b.cancelNotification('water');
}
});Quando un'attività viene eliminata, annulla ogni promemoria che le appartiene:
function cancelTaskReminders(taskId) {
const b = window.WebToApk;
if (!(b && b.cancelNotification)) return;
let list = [];
try { list = JSON.parse(b.getScheduledNotifications() || '[]'); } catch (e) { list = []; }
list
.filter(function (r) { return r.id.indexOf('task-' + taskId + '-') === 0; })
.forEach(function (r) { b.cancelNotification(r.id); });
}Note: annulla un promemoria che non è ancora scattato (singolo o ripetuto). Non rimuove una notifica già visibile nell'area notifiche e non riguarda le notifiche pubblicate con notify() / showNotification().
canOpenAppAtTime bridge#
window.WebToApk.canOpenAppAtTime(): String
Se una notifica programmata può portare l'APP STESSA sullo schermo (`openApp`). "granted": verrà mostrato un avviso a schermo intero, sopra la schermata di blocco. "denied": Android 14+ non l'ha concesso; chiama requestOpenAppPermission(). Non esiste una terza risposta in cui l'app si avvia da sola in background: Android blocca l'avvio di attività in background da Android 10, e un intent a schermo intero è tutto ciò che resta.
Esempio
Ti dice se un promemoria con openApp: true può portare l'app stessa sullo schermo (un avviso a schermo intero, anche sopra la schermata di blocco).
Restituisce: una stringa, in modo sincrono: 'granted' o 'denied'. Sotto Android 14 è sempre 'granted'. Richiede: attiva ⏰ Promemoria nel passaggio Accesso (Passaggio 4) quando crei l'app.
function prepareAlarm() {
const b = window.WebToApk;
if (!(b && b.canOpenAppAtTime)) return;
if (b.canOpenAppAtTime() === 'denied') {
showMessage('To open the app at alarm time, allow "full-screen notifications" for this app.');
b.requestOpenAppPermission();
return;
}
const t = new Date();
t.setDate(t.getDate() + 1);
t.setHours(7, 0, 0, 0); // tomorrow 07:00
b.scheduleNotificationEx('wake-up', JSON.stringify({
at: t.getTime(), repeat: 'daily',
title: 'Wake up', body: 'Good morning!',
openApp: true
}));
}
window.addEventListener('appmint:reminder', function (e) {
// e.detail.overLockScreen is true when the app was shown as a full-screen alert
if (e.detail.overLockScreen) showBigAlarmScreen(e.detail.id);
});Una schermata delle impostazioni che mostra entrambi gli interruttori delle sveglie con il loro stato attuale:
function renderAlarmStatus() {
const b = window.WebToApk;
if (!(b && b.canOpenAppAtTime && b.getAlarmPrecision)) return;
const openApp = b.canOpenAppAtTime(); // 'granted' | 'denied'
const precision = b.getAlarmPrecision(); // 'exact' | 'inexact' | 'unavailable'
document.getElementById('open-app-state').textContent =
openApp === 'granted' ? 'Opens over the lock screen' : 'Notification only';
document.getElementById('open-app-fix').hidden = openApp === 'granted';
document.getElementById('timing-state').textContent =
precision === 'exact' ? 'On the minute' : 'May be late';
}
renderAlarmStatus();
document.addEventListener('visibilitychange', function () {
if (!document.hidden) renderAlarmStatus(); // back from Settings
});Avvisa quando le sveglie salvate sono state impostate per aprire l'app ma Android non lo permette in questo momento:
function checkSavedAlarms() {
const b = window.WebToApk;
if (!(b && b.canOpenAppAtTime && b.getScheduledNotifications)) return;
if (b.canOpenAppAtTime() === 'granted') return;
// [{ id, title, body, trigger, repeat, options }] - options is the JSON string you scheduled
const items = JSON.parse(b.getScheduledNotifications());
const affected = items.filter(function (r) {
try { return JSON.parse(r.options || '{}').openApp === true; } catch (e) { return false; }
});
if (affected.length) {
showMessage(affected.length + ' alarm(s) will only show a notification. Tap "Allow" to let them open the app.');
}
}Note: quando è 'denied', un promemoria openApp pubblica comunque una notifica in primo piano, ma l'app non si apre da sola. Android non permette ad altre app di avviarsi da sole in background in nessun altro modo.
clearNotificationSounds bridge#
window.WebToApk.clearNotificationSounds(): Int
Elimina i file audio copiati e restituisce quanti ne sono stati eliminati. Un file viene copiato di nuovo quando una notifica (o un promemoria programmato, quando scatta) usa quel suono la volta successiva, anche su un canale già esistente, che continua a puntare allo stesso nome di file (NotificationBridge.restoreBundleSound).
Esempio
Elimina le copie dei tuoi suoni di notifica personalizzati che l'app ha creato dal tuo bundle.
Restituisce: un numero, in modo sincrono: quanti file sono stati eliminati. Richiede: nulla.
Svuota, poi rimetti i suoni che usi ancora:
document.getElementById('reset-sounds').addEventListener('click', function () {
const b = window.WebToApk;
if (!(b && b.clearNotificationSounds)) return;
const removed = b.clearNotificationSounds();
// Sounds still in use must be copied again, or they play the default sound:
['/audio/alarm.mp3', '/audio/chime.mp3'].forEach(function (path) {
if (!b.prepareNotificationSound(path)) console.warn('missing sound', path);
});
showMessage(removed + ' sound file(s) refreshed');
});Un pulsante nella schermata di archiviazione che libera i file audio copiati e indica quanti ne sono stati rimossi:
document.getElementById('free-space').addEventListener('click', function () {
const b = window.WebToApk;
if (!(b && b.clearNotificationSounds)) return;
const removed = b.clearNotificationSounds();
showMessage(removed === 0 ? 'No sound files to remove.' : 'Removed ' + removed + ' sound file(s).');
});Alla disconnessione, annulla ogni promemoria ed elimina le copie dei suoni appartenute a questo utente:
function signOutAndReset() {
const b = window.WebToApk;
if (b && b.cancelAllNotifications) b.cancelAllNotifications();
if (b && b.clearNotificationSounds) b.clearNotificationSounds();
localStorage.removeItem('alarmSound');
goToLoginScreen();
}Note: raramente ti serve; le copie sono piccole. Un suono viene copiato di nuovo la prossima volta che qualcosa lo usa: notify(), un promemoria quando scatta, scheduleNotificationEx o prepareNotificationSound(path), anche su un canale di notifica già esistente, così il suono personalizzato continua a suonare.
enableNotifications bridge#
window.WebToApk.enableNotifications(callbackId: String)
Riporta un utente alle notifiche: la finestra di sistema finché può ancora essere mostrata, altrimenti le impostazioni di notifica dell'app. Risolve `window.__appmintReplies[callbackId]` con {state, changed, openedSettings} (AppMint.enableNotifications() è il wrapper a promessa).
Esempio
Riporta alle notifiche un utente che le ha rifiutate o saltate: mostra la finestra di autorizzazione di Android finché può ancora essere mostrata, altrimenti apre le impostazioni di notifica di questa app e risponde quando l'utente torna.
Restituisce: niente direttamente. La risposta {state, changed, openedSettings} viene consegnata a window.__appmintReplies[callbackId]; state è 'granted' | 'prompt' | 'blocked' | 'unavailable', changed è true quando è diverso da prima della chiamata, openedSettings è true quando è stata usata la schermata delle impostazioni. Se già 'granted' (o 'unavailable') risponde subito. Richiede: chiamalo da un pulsante toccato dall'utente; le notifiche richiedono Notifiche (o Push / Promemoria) nella build.
Preferisci il wrapper a promessa AppMint.enableNotifications(). La chiamata grezza, per il codice che gestisce da sé le risposte:
function enableNotificationsRaw() {
return new Promise(function (resolve) {
if (!(window.WebToApk && WebToApk.enableNotifications)) return resolve({ state: 'unavailable', changed: false, openedSettings: false });
var replies = window.__appmintReplies = window.__appmintReplies || {};
var id = 'my_notif_' + Date.now();
replies[id] = resolve;
WebToApk.enableNotifications(id);
});
}
document.getElementById('turn-on-btn').onclick = async function () {
var r = await enableNotificationsRaw();
if (r.state === 'granted') document.getElementById('notif-banner').hidden = true;
};Ogni flusso completato viene annunciato, anche quello avviato da un pulsante push (appmint://notifications/enable):
window.addEventListener('appmint:notifications', function (e) {
// e.detail = { state, changed, openedSettings }
if (e.detail.state === 'granted') document.getElementById('notif-banner').hidden = true;
});Note: un pulsante di un push o di un messaggio in-app il cui link è appmint://notifications/enable esegue lo stesso flusso; appmint://notifications/settings apre la schermata delle impostazioni. Il pubblico push dell'app vede subito il nuovo stato.
getAlarmPrecision bridge#
window.WebToApk.getAlarmPrecision(): String
"exact": i promemoria scattano al minuto. "inexact": l'utente (o il produttore) ha disattivato le sveglie esatte per questa app, quindi la modalità Doze può raggrupparli con scarti di minuti. Chiedi a [requestExactAlarms] di correggerlo. "unavailable": Android 12+ e non è stato possibile raggiungere il servizio di sveglie del sistema, quindi la precisione non può essere letta (anche un promemoria programmato ora potrebbe non scattare). Una pagina che deve essere puntuale dovrebbe controllare questo valore invece di darlo per scontato. @return `"exact"`, `"inexact"` o `"unavailable"`.
Esempio
Ti dice se i promemoria scatteranno al minuto esatto, oppure potranno arrivare in ritardo perché l'utente (o il produttore del telefono) ha disattivato le sveglie esatte per questa app.
Restituisce: una stringa, in modo sincrono: 'exact', 'inexact' (può essere raggruppata dal risparmio energetico, spesso di qualche minuto) oppure 'unavailable' (il telefono non ha un servizio di sveglie). Richiede: attiva ⏰ Promemoria nel passaggio Accesso (Passaggio 4) quando crei l'app.
function checkReminderTiming() {
if (!(window.WebToApk && window.WebToApk.getAlarmPrecision)) return;
const precision = WebToApk.getAlarmPrecision();
const warn = document.getElementById('timing-warning');
warn.hidden = precision === 'exact';
if (precision === 'inexact') {
warn.textContent = 'Reminders may be a few minutes late. Tap to allow exact alarms.';
warn.onclick = function () { WebToApk.requestExactAlarms(); };
}
}
checkReminderTiming();
// Re-check when the user returns from Settings:
document.addEventListener('visibilitychange', function () {
if (!document.hidden) checkReminderTiming();
});Controlla prima di impostare una sveglia del mattino e avvisa l'utente se potrebbe arrivare in ritardo:
function setWakeUp(atMs) {
const b = window.WebToApk;
if (!(b && b.getAlarmPrecision && b.scheduleNotificationEx)) return;
const precision = b.getAlarmPrecision();
if (precision === 'unavailable') { showMessage('Alarms cannot be set on this phone right now.'); return; }
b.scheduleNotificationEx('wake', JSON.stringify({ at: atMs, title: 'Wake up', body: 'Good morning', openApp: true }));
if (precision === 'inexact') {
showMessage('Alarm set, but it may ring a few minutes late. Allow exact alarms for on-time alarms.');
}
}Mostra la puntualità dei promemoria come una riga in una schermata delle impostazioni:
function renderTimingRow() {
if (!(window.WebToApk && window.WebToApk.getAlarmPrecision)) return;
const labels = {
exact: 'Reminders arrive on time',
inexact: 'Reminders may be a few minutes late',
unavailable: 'Reminders are not available on this phone'
};
document.getElementById('timing-row').textContent = labels[WebToApk.getAlarmPrecision()];
}
renderTimingRow();Note: Android 11 e precedenti rispondono sempre 'exact'. Un promemoria 'inexact' scatta comunque, solo non al minuto.
getAlarmSupport bridge#
window.WebToApk.getAlarmSupport(): String
Se `scheduleNotificationEx(id, {alarm: true, ...})` può essere programmata ora: "ready" | "not_enabled" (la sveglia è disattivata in questa build) | "needs_exact_alarm" (chiama requestExactAlarms) | "needs_notification_permission".
Esempio
Ti dice se una sveglia (scheduleNotificationEx(id, { alarm: true, ... })) può essere impostata su questo telefono in questo momento e, in caso contrario, che cosa deve consentire prima l'utente.
Restituisce: una stringa, in modo sincrono: 'ready', 'not_enabled' (l'app è stata creata senza 🔔 Sveglia), 'needs_exact_alarm' (Android 12+: le sveglie esatte sono disattivate per questa app: chiama requestExactAlarms()) oppure 'needs_notification_permission' (Android 13+: nessuna autorizzazione di notifica, quindi non ci sarebbe il pulsante Chiudi: chiama requestNotificationPermission()). Richiede: attiva 🔔 Sveglia nel passaggio Accesso (Passaggio 4) quando crei l'app.
function prepareAlarms() {
const b = window.WebToApk;
if (!(b && b.getAlarmSupport)) { showMessage('Alarms work in the installed app only.'); return false; }
switch (b.getAlarmSupport()) {
case 'ready': return true;
case 'needs_exact_alarm':
showMessage('Allow "Alarms & reminders" for this app, then come back.');
b.requestExactAlarms();
return false;
case 'needs_notification_permission':
b.requestNotificationPermission();
return false;
default:
showMessage('This app was built without alarm clocks.');
return false;
}
}Ricontrolla quando l'utente torna dalle Impostazioni:
document.addEventListener('visibilitychange', function () {
if (document.hidden || !(window.WebToApk && window.WebToApk.getAlarmSupport)) return;
document.getElementById('alarm-setup').hidden = WebToApk.getAlarmSupport() === 'ready';
});Crea una sveglia solo quando il telefono è pronto:
function setAlarmIn(hours) {
const b = window.WebToApk;
if (!(b && b.getAlarmSupport)) return false;
if (b.getAlarmSupport() !== 'ready') { prepareAlarms(); return false; } // asks for what is missing
return b.scheduleNotificationEx('wake-up', JSON.stringify({
at: Date.now() + hours * 3600 * 1000,
alarm: true,
title: 'Wake up',
body: 'Good morning'
}));
}Note: scheduleNotificationEx con alarm: true restituisce false ogni volta che questo non è 'ready': una sveglia che non potrebbe mai suonare non viene mai salvata.
getNotificationPermission bridge#
window.WebToApk.getNotificationPermission(): String
L'autorizzazione di notifica ATTUALE, letta in tempo reale dal sistema operativo. Il polyfill una volta impostava `Notification.permission = 'default'` a ogni caricamento di pagina, quindi il pattern di pagina più comune if (Notification.permission === 'granted') new Notification(...) non scattava mai, nemmeno per un utente che l'aveva già concessa, e nemmeno su Android 12 e precedenti dove le notifiche non richiedono alcuna autorizzazione a runtime.
Esempio
Legge, in questo momento, se questa app può pubblicare notifiche.
Restituisce: una stringa, in modo sincrono: 'granted'; 'denied' (l'utente ha rifiutato in modo definitivo, oppure ha disattivato le notifiche di questa app nelle Impostazioni: una notifica non verrebbe mostrata); oppure 'default' (non ancora deciso, l'app può ancora chiedere). Richiede: nulla per chiamarlo; per pubblicare serve Notifiche attivato nel passaggio Accesso (Passaggio 4) quando crei l'app.
L'API web standard legge lo stesso valore in tempo reale:
if ('Notification' in window && Notification.permission === 'granted') {
document.getElementById('alerts-on').hidden = false;
}La chiamata grezza, per esempio dopo che l'utente torna dalle Impostazioni:
function refreshAlertSetting() {
if (!(window.WebToApk && window.WebToApk.getNotificationPermission)) return;
const perm = WebToApk.getNotificationPermission(); // 'granted' | 'denied' | 'default'
document.getElementById('enable-alerts').hidden = perm !== 'default'; // can still ask
document.getElementById('open-settings-hint').hidden = perm !== 'denied';
}
document.addEventListener('visibilitychange', function () {
if (!document.hidden) refreshAlertSetting();
});
refreshAlertSetting();Decidi prima di programmare se chiedere, spiegare o procedere:
async function ensureAlerts() {
const b = window.WebToApk;
if (!(b && b.getNotificationPermission)) return false;
const perm = b.getNotificationPermission();
if (perm === 'granted') return true;
if (perm === 'denied') {
showMessage('Notifications are off for this app. Turn them on in Settings.');
return false;
}
// 'default': the app can still ask
return (await Notification.requestPermission()) === 'granted';
}Note: dà la stessa risposta di navigator.permissions.query({ name: 'notifications' }). Per chiedere all'utente, usa Notification.requestPermission().
getNotificationState bridge#
window.WebToApk.getNotificationState(): String
'granted' | 'prompt' (Android può ancora chiedere) | 'blocked' (rifiutato in modo definitivo o disattivato nelle Impostazioni: solo le Impostazioni possono risolverlo) | 'unavailable' (Android 13+ e questa build non dichiara l'autorizzazione per le notifiche). Vedi NotificationOptIn.
Esempio
Legge, in questo momento, se le notifiche di questa app sono attive e, in caso contrario, se l'app può ancora chiedere o solo le Impostazioni possono riattivarle.
Restituisce: una stringa, in modo sincrono: 'granted' (le notifiche arrivano al telefono); 'prompt' (Android può ancora mostrare la sua finestra di autorizzazione); 'blocked' (l'utente ha rifiutato in modo definitivo, oppure ha disattivato le notifiche di questa app nelle Impostazioni di sistema: solo le Impostazioni possono risolverlo); oppure 'unavailable' (Android 13+ e l'app è stata creata senza Notifiche / Promemoria / Push, quindi nulla può attivarle). Richiede: nulla per chiamarlo.
La chiamata grezza, per decidere se mostrare un banner "Attiva le notifiche":
function refreshNotifBanner() {
if (!(window.WebToApk && WebToApk.getNotificationState)) return;
var state = WebToApk.getNotificationState(); // 'granted' | 'prompt' | 'blocked' | 'unavailable'
var banner = document.getElementById('notif-banner');
banner.hidden = !(state === 'prompt' || state === 'blocked');
banner.querySelector('.hint').textContent = state === 'blocked'
? 'Notifications are off. Tap to open Settings and switch them on.'
: 'Get order updates. Tap to turn on notifications.';
}
document.addEventListener('visibilitychange', function () {
if (!document.hidden) refreshNotifBanner();
});
refreshNotifBanner();Note: getNotificationPermission() mantiene le sue parole ('granted' / 'default' / 'denied') per le pagine più vecchie. Per riportare l'utente qui, chiama AppMint.enableNotifications() (sceglie lui la finestra o le Impostazioni).
getScheduledNotifications bridge#
window.WebToApk.getScheduledNotifications(): String
Lettura e richiesta dell'autorizzazione POST_NOTIFICATIONS, e gestione delle notifiche già programmate dalla pagina. La pubblicazione e la programmazione sono documentate nei rispettivi metodi.
Descritto dal suo gruppo, Autorizzazione di notifica, annullamento ed elenco, anziché da solo.
Esempio
Elenca i promemoria ancora programmati.
Restituisce: una stringa JSON, in modo sincrono. Analizzala. Ogni elemento: { id, title, body, trigger, repeat, options? } - trigger è il prossimo orario di scatto in epoch ms, repeat è none|minutely|hourly|daily|weekly e options (solo per scheduleNotificationEx) sono le opzioni come stringa JSON. I campi live indicano come verrà davvero consegnata, letti in tempo reale: precision ("exact"; "inexact" = "Sveglie e promemoria" è disattivato per l'app, quindi Android la consegna entro una finestra di 10 minuti mentre il telefono è attivo e può trattenerla più a lungo mentre dorme; "alarm_clock" per alarm: true), windowMs + latestAt (la finestra data ad Android: 0 / trigger quando esatta, 600000 / trigger + 600000 quando non esatta) e notificationsEnabled (false = scatta ma Android non mostra nulla, perché le notifiche dell'app sono disattivate). '[]' quando non ce ne sono. Richiede: nient'altro.
function renderReminders() {
if (!(window.WebToApk && window.WebToApk.getScheduledNotifications)) return;
let list = [];
try { list = JSON.parse(WebToApk.getScheduledNotifications() || '[]'); } catch (e) { list = []; }
const ul = document.getElementById('reminders');
ul.innerHTML = '';
list.sort(function (a, b) { return a.trigger - b.trigger; }).forEach(function (r) {
const li = document.createElement('li');
li.textContent = r.title + ' — ' + new Date(r.trigger).toLocaleString() +
(r.repeat !== 'none' ? ' (' + r.repeat + ')' : '');
ul.appendChild(li);
});
}Mostra se un promemoria è attivo e quando scatta la prossima volta:
function describeReminder(id) {
if (!(window.WebToApk && window.WebToApk.getScheduledNotifications)) return 'Not available';
let list = [];
try { list = JSON.parse(WebToApk.getScheduledNotifications() || '[]'); } catch (e) { list = []; }
const r = list.find(function (x) { return x.id === id; });
return r ? 'Next: ' + new Date(r.trigger).toLocaleString() : 'Off';
}
document.getElementById('water-status').textContent = describeReminder('water');Leggi le opzioni aggiuntive dei promemoria creati con scheduleNotificationEx:
function listAlarmStyleReminders() {
if (!(window.WebToApk && window.WebToApk.getScheduledNotifications)) return [];
let list = [];
try { list = JSON.parse(WebToApk.getScheduledNotifications() || '[]'); } catch (e) { list = []; }
return list.filter(function (r) {
if (!r.options) return false; // made with scheduleNotification
let o = {};
try { o = JSON.parse(r.options); } catch (e) { return false; }
return o.openApp === true; // puts the app on screen when it fires
}).map(function (r) { return r.id; });
}Note: un promemoria singolo esce dall'elenco quando scatta. Uno ripetuto resta, con trigger spostato al prossimo orario. Un promemoria il cui orario è passato mentre il telefono era spento o l'app era stata forzata a chiudersi viene mostrato una volta, in ritardo, al prossimo avvio dell'app o del telefono; un alarm: true in ritardo viene segnalato come missed invece di suonare. Un promemoria giornaliero, settimanale, mensile o annuale mantiene l'orario locale quando il telefono cambia fuso orario.
Avvisa quando i promemoria non arriveranno puntuali:
function reminderHealth() {
if (!(window.WebToApk && window.WebToApk.getScheduledNotifications)) return '';
let list = [];
try { list = JSON.parse(WebToApk.getScheduledNotifications() || '[]'); } catch (e) { list = []; }
if (!list.length) return '';
if (list.some(function (r) { return r.notificationsEnabled === false; })) return 'Notifications are off for this app: reminders will not appear.';
if (list.some(function (r) { return r.precision === 'inexact'; })) return 'Reminders may arrive late. Turn on Alarms & reminders.';
return '';
}isAlarmRinging bridge#
window.WebToApk.isAlarmRinging(): Boolean
True mentre una sveglia sta suonando.
Esempio
Ti dice se una delle sveglie dell'app sta suonando in questo momento, così la pagina può mostrare la propria schermata per fermarla o rimandarla.
Restituisce: true mentre una sveglia suona, altrimenti false (in modo sincrono). Richiede: 🔔 Sveglia nel passaggio Accesso (Passaggio 4) quando crei l'app.
function showRingScreenIfNeeded() {
const b = window.WebToApk;
const ringing = !!(b && b.isAlarmRinging && b.isAlarmRinging());
document.getElementById('ring-screen').hidden = !ringing;
}
showRingScreenIfNeeded();
document.addEventListener('visibilitychange', showRingScreenIfNeeded);Ferma la sveglia che suona dalla tua schermata con le chiamate corrispondenti.
document.getElementById('stop').addEventListener('click', function () {
const b = window.WebToApk;
if (b && b.isAlarmRinging && b.isAlarmRinging()) b.stopAlarm(''); // '' = whichever is ringing
});
document.getElementById('snooze').addEventListener('click', function () {
const b = window.WebToApk;
if (b && b.snoozeAlarm && !b.snoozeAlarm('', 10)) showMessage('Nothing is ringing');
});Reagisci all'app aperta da una sveglia che suona.
window.addEventListener('appmint:reminder', function (e) {
if (e.detail.action === 'open' && e.detail.ringing) {
document.getElementById('ring-screen').hidden = false;
}
});Note: quando la sveglia che suona apre l'app, arriva anche appmint:reminder con { action: 'open', ringing: true }.
notify bridge#
window.WebToApk.notify(optionsJson: String): Boolean
Notifica ricca. Vedi NotificationBridge.show per l'elenco completo delle opzioni: channel (urgent|default|quiet|ongoing), image, largeIcon, bigText, ongoing, actions, progress, sound, silent, group, color. Il download e la decodifica delle immagini avvengono fuori dal thread principale, quindi un'immagine remota non può mai bloccare la pagina.
Esempio
Pubblica subito una notifica, con qualsiasi combinazione di opzioni: immagine, testo esteso, pulsanti, barra di avanzamento, fissa (ongoing), canale, suono, colore e tag.
Restituisce: true quando le opzioni erano JSON valido e la notifica è stata consegnata al sistema (viene creata su un thread in background, quindi un URL immagine errato non blocca la pagina); false per JSON non valido. Richiede: attiva Notifiche nel passaggio Accesso (Passaggio 4) quando crei l'app, e l'autorizzazione dell'utente su Android 13+ (chiedila con Notification.requestPermission()).
Notifica semplice. tag è un ID: pubblicare di nuovo con lo stesso tag sostituisce la vecchia.
async function notifyOrderReady() {
if (!(window.WebToApk && window.WebToApk.notify)) return;
if (window.Notification && Notification.permission !== 'granted') {
const p = await Notification.requestPermission();
if (p !== 'granted') { showMessage('Notifications are off for this app.'); return; }
}
WebToApk.notify(JSON.stringify({
title: 'Order ready',
body: 'Your order is ready to collect',
channel: 'default', // urgent | default | quiet | ongoing
tag: 'order-42'
}));
}Immagine, icona grande e testo lungo. image ha la precedenza su bigText quando sono indicati entrambi.
WebToApk.notify(JSON.stringify({
title: 'New photo',
body: 'Tap to see it',
image: 'https://example.com/photo.jpg', // expanded big picture
largeIcon: 'https://example.com/avatar.png', // round icon on the right
color: '#00C6FF',
tag: 'photo-7'
}));
WebToApk.notify(JSON.stringify({
title: 'Weekly summary',
body: '3 tasks done, 2 left',
bigText: 'Done: pay rent, call bank, water plants. Left: tax form, dentist.',
channel: 'quiet', // no sound, low priority
group: 'summaries'
}));Pulsanti (al massimo 3). Il tocco torna come evento appmint:notification-action.
WebToApk.notify(JSON.stringify({
title: 'Ali sent you a message',
body: 'Are we still on for 6pm?',
channel: 'urgent', // heads-up banner
tag: 'chat-ali',
actions: [
{ id: 'open', label: 'Open chat' },
{ id: 'done', label: 'Mark read' }
]
}));
window.addEventListener('appmint:notification-action', function (e) {
// e.detail = { actionId: 'done', tag: 'chat-ali' }
if (e.detail.actionId === 'open') openChat(e.detail.tag);
if (e.detail.actionId === 'done') markRead(e.detail.tag);
});Avanzamento fisso (ongoing). Ripubblica con lo stesso tag per aggiornarlo. Quando il lavoro finisce, pubblica lo stato finale con ongoing: false così l'utente può eliminarla scorrendo.
function showUpload(percent) {
WebToApk.notify(JSON.stringify({
title: 'Uploading', body: percent + '%',
ongoing: true, // cannot be swiped away
progress: { current: percent, max: 100 }, // or { indeterminate: true }
silent: true,
tag: 'upload'
}));
}
showUpload(40);
// finished:
WebToApk.notify(JSON.stringify({ title: 'Upload complete', body: '3 photos saved', tag: 'upload' }));Altre opzioni: sound (un file nel tuo bundle come '/audio/ding.mp3', un URL data:audio/... o 'silent'), smallIcon (il nome di un drawable), when (epoch in ms mostrato come orario), openApp: true (avviso a schermo intero; vedi scheduleNotificationEx).
Note: i pulsanti non hanno una casella di risposta integrata e il tocco su un pulsante raggiunge la pagina solo mentre l'app è in esecuzione (non apre l'app); l'evento chiama anche window.onAppMintNotificationAction(detail) se lo definisci. image e largeIcon accettano un URL https:// o data:, oppure un'immagine inclusa nella tua app indicata come la indica la tua pagina ('img/logo.png', '/img/logo.png' o il suo indirizzo completo https://appassets.androidplatform.net/assets/…). Un'immagine non valida viene saltata, la notifica viene comunque mostrata. ongoing: true usa sempre il canale silenzioso "Ongoing". notify() non ha un'operazione "rimuovi" pubblica: cancelNotification annulla solo i promemoria programmati. Una notifica che vuoi rimuovere più tardi dalla pagina va pubblicata con new Notification(...) e rimossa con il suo close(); una scheda di avanzamento fissa con Capacitor.AppwrightLiveProgress (end). Android fissa il suono di un canale quando il canale viene creato, quindi un nuovo valore di sound crea un nuovo canale.
openNotificationSettings bridge#
window.WebToApk.openNotificationSettings(): Boolean
Apre le impostazioni di notifica di questa app; true quando la schermata ha potuto essere aperta.
Esempio
Apre la schermata delle impostazioni di notifica di questa app, dove l'utente può attivare o disattivare le notifiche (e ogni canale).
Restituisce: true quando la schermata è stata aperta, in modo sincrono; false quando non può esserlo (Android 13+ e la build non ha notifiche). Su Android 8+ è la pagina delle notifiche dell'app; sulle versioni precedenti, la schermata Info app. Richiede: nulla da attivare.
document.getElementById('notif-settings-link').onclick = function () {
if (!(window.WebToApk && WebToApk.openNotificationSettings && WebToApk.openNotificationSettings())) {
showMessage('Open Settings > Apps > this app > Notifications.');
}
};Note: per riportare un utente qui con un solo tocco, usa invece AppMint.enableNotifications(): mostra la finestra di autorizzazione quando Android lo permette ancora e apre questa schermata solo quando non lo permette.
prepareNotificationSound bridge#
window.WebToApk.prepareNotificationSound(spec: String): Boolean
Copia in anticipo un file audio incluso nell'app e segnala se è utilizzabile come suono di notifica. Facoltativo: `notify()` e `scheduleNotificationEx()` lo fanno da sole, ma permette a una schermata delle impostazioni di verificare un suono nel momento in cui l'utente lo sceglie.
Esempio
Verifica che un file audio della tua app possa essere usato come suono di notifica e lo copia subito al suo posto. Facoltativo: notify() e scheduleNotificationEx() lo fanno da sole; questo permette a una schermata delle impostazioni di controllare un suono nel momento in cui l'utente lo sceglie.
Restituisce: true se il suono è utilizzabile; false se il file non esiste o non è un tipo audio supportato. Richiede: nulla.
function chooseAlarmSound(path) { // e.g. '/audio/chime.mp3'
if (!(window.WebToApk && window.WebToApk.prepareNotificationSound)) return;
if (!WebToApk.prepareNotificationSound(path)) {
showMessage('This sound file is missing from the app: ' + path);
return;
}
localStorage.setItem('alarmSound', path);
// Use it:
WebToApk.notify(JSON.stringify({ title: 'Sound test', body: 'This is your alarm sound', sound: path, tag: 'sound-test' }));
}Riempi un selettore di suoni solo con i suoni davvero utilizzabili:
const SOUNDS = [
{ label: 'Chime', path: '/audio/chime.mp3' },
{ label: 'Bell', path: '/audio/bell.ogg' },
{ label: 'Beep', path: '/audio/beep.wav' }
];
function renderSoundPicker(select) {
const b = window.WebToApk;
if (!(b && b.prepareNotificationSound)) return;
select.innerHTML = '';
SOUNDS.forEach(function (s) {
if (!b.prepareNotificationSound(s.path)) return; // missing or unsupported file
const opt = document.createElement('option');
opt.value = s.path; opt.textContent = s.label;
select.appendChild(opt);
});
}Lascia che l'utente scelga il proprio file audio e usalo per un promemoria giornaliero, passato come URL data::
document.getElementById('own-sound').addEventListener('change', function (e) {
const file = e.target.files[0];
const b = window.WebToApk;
if (!file || !(b && b.prepareNotificationSound)) return;
const reader = new FileReader();
reader.onload = function () {
const dataUrl = reader.result; // 'data:audio/mpeg;base64,...'
if (!b.prepareNotificationSound(dataUrl)) {
showMessage('That file cannot be used as a notification sound.');
return;
}
b.scheduleNotificationEx('daily-walk', JSON.stringify({
at: nextEvening(), repeat: 'daily',
title: 'Walk time', body: 'Time for your evening walk', sound: dataUrl
}));
};
reader.readAsDataURL(file);
});Valori accettati: un percorso nel tuo bundle web ('/audio/chime.mp3', 'audio/chime.mp3') o un URL data:audio/...;base64,... creato dalla tua pagina. Tipi: mp3, wav, ogg, oga, m4a, aac, flac, opus, mid, midi.
Note: un nome semplice senza cartella né estensione (un suono res/raw) non viene controllato qui e restituisce false, anche se notify({sound: 'name'}) può usarlo. Android mantiene un solo suono per canale, quindi cambiare il suono crea un nuovo canale e reimposta le impostazioni dell'utente per quel canale.
requestExactAlarms bridge#
window.WebToApk.requestExactAlarms(): Boolean
Apre la schermata di sistema dove si concedono le sveglie esatte. Android 12+.
Esempio
Apre la schermata di sistema di Android 12+ dove l'utente consente a questa app di usare le sveglie esatte, così i promemoria scattano al minuto.
Restituisce: true quando la schermata delle impostazioni è stata aperta (e su Android 11 e precedenti, dove non serve nulla); false se la schermata non ha potuto essere aperta. Non ti dice la scelta dell'utente. Richiede: attiva ⏰ Promemoria nel passaggio Accesso (Passaggio 4) quando crei l'app.
document.getElementById('allow-exact').addEventListener('click', function () {
if (!(window.WebToApk && window.WebToApk.requestExactAlarms)) return;
if (WebToApk.getAlarmPrecision() === 'exact') return; // already fine
WebToApk.requestExactAlarms();
});
// The user comes back from Settings: read the real answer.
document.addEventListener('visibilitychange', function () {
if (document.hidden || !window.WebToApk) return;
const exact = WebToApk.getAlarmPrecision() === 'exact';
document.getElementById('allow-exact').hidden = exact;
});Prima di salvare un promemoria critico per l'orario, offri la schermata delle impostazioni solo quando la puntualità è davvero disattivata:
function saveMedicineReminder(at) {
const b = window.WebToApk;
if (!(b && b.scheduleNotificationEx && b.getAlarmPrecision)) return;
b.scheduleNotificationEx('medicine', JSON.stringify({
at: at, repeat: 'daily', title: 'Medicine', body: 'Time for your tablet'
}));
const precision = b.getAlarmPrecision(); // 'exact' | 'inexact' | 'unavailable'
if (precision === 'inexact') {
showBanner('Reminders may arrive a few minutes late.', 'Fix timing', function () {
b.requestExactAlarms(); // runs from the banner button tap
});
} else if (precision === 'unavailable') {
showBanner('The phone\'s alarm service is not answering; this reminder may not fire.');
}
}Quando la schermata delle impostazioni non può essere aperta (false), indica all'utente dove trovare l'interruttore:
document.getElementById('fix-timing').addEventListener('click', function () {
const b = window.WebToApk;
if (!(b && b.requestExactAlarms)) return;
const opened = b.requestExactAlarms();
if (!opened) {
showMessage('Open Settings > Apps > this app > "Alarms & reminders" and turn it on.');
}
// When it did open, read the answer on return with getAlarmPrecision().
});Note: chiamalo da un tocco su un pulsante e spiega prima il perché: porta fuori dalla tua app. I promemoria già programmati continuano a funzionare in entrambi i casi; cambia solo la loro puntualità.
requestNotificationPermission bridge#
window.WebToApk.requestNotificationPermission(): String
Lettura e richiesta dell'autorizzazione POST_NOTIFICATIONS, e gestione delle notifiche già programmate dalla pagina. La pubblicazione e la programmazione sono documentate nei rispettivi metodi.
Descritto dal suo gruppo, Autorizzazione di notifica, annullamento ed elenco, anziché da solo.
Esempio
Mostra la finestra "Consentire le notifiche?" di Android 13+. Le pagine normalmente usano Notification.requestPermission(), che la chiama e attende la risposta dell'utente.
Restituisce: una stringa, in modo sincrono: 'granted' se già consentito (o su Android 12 e precedenti), altrimenti 'default' mentre la finestra si apre. Non può restituire la risposta dell'utente. Richiede: attiva Notifiche nel passaggio Accesso (Passaggio 4) quando crei l'app.
Usa l'API Promise: si risolve con la risposta reale ('granted' o 'denied'):
document.getElementById('enable-alerts').addEventListener('click', async function () {
if (!('Notification' in window)) return;
const perm = await Notification.requestPermission();
if (perm === 'granted') {
showMessage('Alerts are on');
} else {
showMessage('Alerts are off. You can turn them on in Settings.');
}
});La chiamata grezza, solo per aprire la finestra senza aspettare:
if (window.WebToApk && window.WebToApk.requestNotificationPermission) {
const now = WebToApk.requestNotificationPermission(); // 'granted' or 'default'
if (now === 'granted') enableAlertFeatures();
// otherwise re-check later with WebToApk.getNotificationPermission()
// ('granted' | 'denied' | 'default')
}Il codice più vecchio che passa un callback a Notification.requestPermission ottiene la stessa risposta finale:
document.getElementById('turn-on-reminders').addEventListener('click', function () {
if (!('Notification' in window)) return;
if (Notification.permission !== 'default') { updateReminderUi(Notification.permission); return; }
Notification.requestPermission(function (perm) {
updateReminderUi(perm); // 'granted' or 'denied', once the user answers
});
});Note: chiedi da un tocco su un pulsante con un motivo chiaro. Dopo che l'utente rifiuta due volte, Android smette di mostrare la finestra e la risposta è subito 'denied'; l'utente deve allora consentirla nelle Impostazioni dell'app.
requestOpenAppPermission bridge#
window.WebToApk.requestOpenAppPermission(): Boolean
Apre la schermata di sistema dove si concede l'avviso a schermo intero. Android 14+.
Esempio
Apre la schermata di sistema di Android 14+ dove l'utente consente gli avvisi a schermo intero per questa app, così un promemoria openApp: true può portare l'app sullo schermo.
Restituisce: true quando la schermata delle impostazioni è stata aperta (e sotto Android 14, dove non serve nulla); false se non è stato possibile aprirla. Non ti dice la scelta dell'utente. Richiede: attiva ⏰ Promemoria nel passaggio Accesso (Passaggio 4) quando crei l'app.
document.getElementById('allow-open-app').addEventListener('click', function () {
const b = window.WebToApk;
if (!(b && b.requestOpenAppPermission)) return;
if (b.canOpenAppAtTime() === 'granted') return;
b.requestOpenAppPermission();
});
// Read the real answer when the user comes back:
document.addEventListener('visibilitychange', function () {
if (document.hidden || !window.WebToApk) return;
const ok = WebToApk.canOpenAppAtTime() === 'granted';
document.getElementById('allow-open-app').hidden = ok;
});Ricorda la sveglia che l'utente stava impostando, mandalo alle Impostazioni e completala quando torna:
let pendingAlarm = null;
function setWakeAlarm(at) {
const b = window.WebToApk;
if (!(b && b.requestOpenAppPermission)) return;
if (b.canOpenAppAtTime() === 'denied') {
pendingAlarm = at;
b.requestOpenAppPermission();
return;
}
b.scheduleNotificationEx('wake', JSON.stringify({ at: at, title: 'Alarm', body: 'Wake up', openApp: true }));
}
document.addEventListener('visibilitychange', function () {
if (document.hidden || pendingAlarm === null || !window.WebToApk) return;
if (WebToApk.canOpenAppAtTime() === 'granted') setWakeAlarm(pendingAlarm);
else showMessage('Without that setting the alarm cannot open the app by itself.');
pendingAlarm = null;
});Quando la schermata delle impostazioni non può essere aperta (false), indica dove si trova l'interruttore:
document.getElementById('allow-fullscreen').addEventListener('click', function () {
const b = window.WebToApk;
if (!(b && b.requestOpenAppPermission)) return;
if (!b.requestOpenAppPermission()) {
showMessage('Open Settings > Apps > this app > Notifications and allow full-screen notifications.');
}
});Note: chiamalo da un tocco su un pulsante dopo aver spiegato il perché: porta fuori dalla tua app.
scheduleNotification bridge#
window.WebToApk.scheduleNotification(id: String, title: String, body: String, triggerAtMillis: String, repeat: String): Boolean
Lettura e richiesta dell'autorizzazione POST_NOTIFICATIONS, e gestione delle notifiche già programmate dalla pagina. La pubblicazione e la programmazione sono documentate nei rispettivi metodi.
Descritto dal suo gruppo, Autorizzazione di notifica, annullamento ed elenco, anziché da solo.
Esempio
Programma un semplice promemoria (titolo e testo) per un orario futuro. Scatta anche quando l'app è chiusa e viene reimpostato dopo il riavvio del telefono.
Restituisce: true quando è stato programmato; false quando id è vuoto o l'orario non è un numero. Richiede: attiva ⏰ Promemoria nel passaggio Accesso (Passaggio 4) quando crei l'app (attiva anche le Notifiche), e l'autorizzazione di notifica dell'utente su Android 13+.
function remindToDrinkWater() {
if (!(window.WebToApk && window.WebToApk.scheduleNotification)) {
showMessage('Reminders work in the installed app only.');
return;
}
const ok = WebToApk.scheduleNotification(
'water', // your own id; same id replaces the old reminder
'Drink water', // title
'Time for a glass of water', // body
String(Date.now() + 60 * 60 * 1000), // epoch milliseconds, AS A STRING
'daily' // none | minutely | hourly | daily | weekly
);
if (!ok) showMessage('Could not schedule the reminder');
}Sappi quando un promemoria ha aperto l'app (l'utente lo ha toccato):
window.addEventListener('appmint:reminder', function (e) {
// e.detail = { id: 'water', overLockScreen: false }
if (e.detail.id === 'water') openWaterLog();
});Un promemoria singolo alle 8:00 del giorno di scadenza di un'attività:
function remindTask(task) {
if (!(window.WebToApk && window.WebToApk.scheduleNotification)) return false;
const at = new Date(task.dueDate);
at.setHours(8, 0, 0, 0);
if (at.getTime() <= Date.now()) return false; // that morning has passed
return WebToApk.scheduleNotification(
'task-' + task.id,
'Due today',
task.title,
String(at.getTime()), // epoch ms as a string
'none'
);
}Note: il promemoria usa lo stile "urgent" (in primo piano) e il suo tag è l'id. Un promemoria ripetuto perso mentre il telefono era spento scatta al passo successivo. Per un'immagine, pulsanti, un tuo suono o per aprire l'app sopra la schermata di blocco, usa scheduleNotificationEx. Se le sveglie esatte sono disattivate per l'app, l'orario può slittare di qualche minuto; controlla getAlarmPrecision().
scheduleNotificationEx bridge#
window.WebToApk.scheduleNotificationEx(id: String, optionsJson: String): Boolean
La forma completa di [scheduleNotification]: tutto ciò che `notify()` accetta, fatto scattare in un orario futuro con l'app chiusa. WebToApk.scheduleNotificationEx('dose-1', JSON.stringify({ at: Date.now() + 3600000, // epoch millis (alias: triggerAt) repeat: 'daily', // none|minutely|hourly|daily|weekly|weekdays|monthly|yearly // days: [1, 3, 5], // with 'weekdays': ISO Mon=1..Sun=7 (default Mon-Fri) // alarm: true, // ring like an alarm clock (getAlarmSupport()) title: 'Time for your dose', body: 'Vitamin D - 1 tablet', sound: '/audio/chime.mp3', // a file in YOUR bundle; 'silent' for none openApp: true // open the app itself, over the lock screen })); Un suono incluso nell'app viene copiato al suo posto durante questa chiamata, quindi un nome di file sbagliato viene segnalato subito (false) invece di trasformarsi giorni dopo nel suono predefinito.
Esempio
Programma un promemoria con tutte le opzioni di notify() (immagine, pulsanti, suono, canale, apri l'app), per un orario futuro. Scatta anche quando l'app è chiusa e sopravvive a un riavvio.
Restituisce: true quando è programmato. false quando non è indicato alcun orario (at, triggerAt, triggerAtMillis o inSeconds), l'id è vuoto, il JSON non è valido, oppure sound indica un file che non è nella tua app. Richiede: attiva ⏰ Promemoria nel passaggio Accesso (Passaggio 4) quando crei l'app, e l'autorizzazione di notifica dell'utente su Android 13+.
Un promemoria giornaliero con un tuo suono che apre l'app (sopra la schermata di blocco):
function scheduleStandup(tomorrowAt9am) {
const b = window.WebToApk;
if (!(b && b.scheduleNotificationEx)) { showMessage('Reminders work in the installed app only.'); return; }
// Both are user settings: check, and ask if needed.
if (b.getAlarmPrecision() === 'inexact') b.requestExactAlarms();
if (b.canOpenAppAtTime() === 'denied') b.requestOpenAppPermission();
const ok = b.scheduleNotificationEx('standup', JSON.stringify({
at: tomorrowAt9am, // epoch ms (or triggerAt, or inSeconds: 3600)
repeat: 'daily', // none | minutely | hourly | daily | weekly | weekdays | monthly | yearly
title: 'Stand-up',
body: 'Daily sync starts now',
sound: '/audio/alarm.mp3', // a file in YOUR app; 'silent' for none
openApp: true // full-screen alert that puts the app on screen
}));
if (!ok) showMessage('Check the sound file path — nothing was scheduled.');
}
window.addEventListener('appmint:reminder', function (e) {
// e.detail = { id: 'standup', overLockScreen: true, action: 'open', ringing: false }
openMeetingScreen(e.detail.id);
});Solo nei giorni di palestra: lunedì, mercoledì e venerdì alle 18:00 (days sono ISO: lunedì = 1 … domenica = 7; senza days, 'weekdays' significa lunedì-venerdì):
WebToApk.scheduleNotificationEx('gym', JSON.stringify({
at: nextAt(18, 0), // epoch ms of the first time; moved to the next listed day if needed
repeat: 'weekdays',
days: [1, 3, 5],
title: 'Gym time',
body: 'Leg day'
}));
// Rent on the 31st: 'monthly' rings on the last day of shorter months (28/29/30) and on the 31st again when there is one.
WebToApk.scheduleNotificationEx('rent', JSON.stringify({ at: rentDueAt, repeat: 'monthly', title: 'Rent is due' }));
// A birthday: same date every year (29 February rings on the 28th in other years).
WebToApk.scheduleNotificationEx('bday-ana', JSON.stringify({ at: anaBirthdayAt9am, repeat: 'yearly', title: 'Ana\'s birthday' }));Una vera sveglia (alarm: true): suona al volume SVEGLIA del telefono, anche in modalità silenziosa e anche con Non disturbare quando l'utente consente le sveglie, e continua a suonare finché non si tocca Chiudi / Rimanda o scade ringSeconds. Mostra l'icona della sveglia nella barra di stato e compare sullo schermo sopra la schermata di blocco:
function setWakeAlarm(atMs) {
const b = window.WebToApk;
if (!(b && b.getAlarmSupport)) { showMessage('Alarms work in the installed app only.'); return; }
const support = b.getAlarmSupport(); // 'ready' | 'not_enabled' | 'needs_exact_alarm' | 'needs_notification_permission'
if (support === 'needs_exact_alarm') { b.requestExactAlarms(); return; }
if (support !== 'ready') { showMessage('Alarms are not available: ' + support); return; }
const ok = b.scheduleNotificationEx('wake', JSON.stringify({
at: atMs,
repeat: 'weekdays', // daily/weekly/weekdays/monthly/yearly keep 07:00 across clock changes
title: 'Wake up',
body: 'Good morning',
alarm: true,
sound: '', // '' = the phone's alarm tone; or '/audio/rooster.mp3'; 'silent' = vibrate only
vibrate: true, // needs Vibration on in the build
ringSeconds: 300, // stop and count as missed after 5 minutes (default 600, max 3600)
snoozeMinutes: 9, // 0 hides the Snooze button (default 10)
snoozeLabel: 'Snooze', dismissLabel: 'Stop'
}));
if (!ok) showMessage('The alarm was not set.');
}
window.addEventListener('appmint:reminder', function (e) {
const d = e.detail;
// Opened by the ringing alarm: { id: 'wake', action: 'open', ringing: true, overLockScreen: true }
// How a ring ended (also delivered later if the app was closed):
// { id: 'wake', action: 'dismiss' | 'snooze' | 'missed' | 'error', alarm: true,
// source: 'notification' | 'page' | 'timeout' | 'replaced' | 'system',
// snoozeMinutes?, snoozedUntil?, error?, soundError? }
if (d.action === 'open' && d.ringing) showRingScreen(d.id); // your Stop / Snooze buttons call stopAlarm / snoozeAlarm
if (d.action === 'missed') logMissedAlarm(d.id);
});Un promemoria con pulsanti, tra 30 minuti:
WebToApk.scheduleNotificationEx('dose-1', JSON.stringify({
inSeconds: 30 * 60,
title: 'Time for your dose',
body: 'Vitamin D — 1 tablet',
actions: [{ id: 'taken', label: 'Taken' }, { id: 'snooze', label: 'Snooze' }]
}));
window.addEventListener('appmint:notification-action', function (e) {
// e.detail = { actionId: 'taken', tag: 'dose-1' }
if (e.detail.actionId === 'snooze') {
WebToApk.scheduleNotificationEx(e.detail.tag, JSON.stringify({ inSeconds: 600, title: 'Time for your dose', body: 'Snoozed reminder' }));
}
});Un promemoria singolo con un'immagine quando inizia una promozione, sul canale normale:
function remindSale(sale) { // sale.startsAt = epoch ms
if (!(window.WebToApk && window.WebToApk.scheduleNotificationEx)) return false;
return WebToApk.scheduleNotificationEx('sale-' + sale.id, JSON.stringify({
at: sale.startsAt,
title: 'The sale starts now',
body: sale.name,
image: 'https://example.com/banners/' + sale.id + '.jpg', // expanded picture
channel: 'default' // not the heads-up style reminders use by default
}));
}Note: lo stesso id sostituisce un promemoria precedente. Valori predefiniti: tag = l'id, canale = urgent, bigText = il testo. Il tocco su un pulsante raggiunge la pagina solo mentre l'app è in esecuzione. Il file audio viene copiato quando programmi, quindi un percorso sbagliato fallisce subito e non giorni dopo; funzionano mp3, wav, ogg, m4a, aac, flac e opus. openApp è l'unico modo in cui un'app può comparire da sola sullo schermo a un orario stabilito; su Android 14+ l'utente deve consentirlo (canOpenAppAtTime). repeat: 'weekdays' con days fuori da 1-7 restituisce false. alarm: true richiede 🔔 Sveglia nel passaggio Accesso (Passaggio 4) e restituisce false a meno che getAlarmSupport() sia 'ready'; suona una sola sveglia alla volta (una nuova termina la precedente come missed). Se il file audio di una sveglia è sparito quando suona (lo ha rimosso un Remote Update), suona con il tono di sveglia del telefono e l'evento riporta soundError: true.
showNotification bridge#
window.WebToApk.showNotification(title: String, body: String, icon: String, tag: String): Boolean
La forma ORIGINALE a quattro argomenti, mantenuta così com'è come adattatore affinché ogni app già in circolazione e ogni esempio delle guide continuino a funzionare. Ora passa al costruttore completo, il che significa che l'argomento `icon`, ignorato in silenzio dalla vecchia implementazione, finalmente fa qualcosa.
Esempio
La chiamata di notifica originale a quattro argomenti. Mostra una notifica con un titolo, un testo, un'icona grande facoltativa e un tag. Il nuovo codice dovrebbe usare notify(optionsJson) o new Notification(...), che fanno di più.
Restituisce: true quando la notifica è stata consegnata al sistema. Richiede: attiva Notifiche nel passaggio Accesso (Passaggio 4) quando crei l'app, e l'autorizzazione dell'utente su Android 13+.
L'API web standard (chiama questo metodo per te):
async function tellUser() {
if (!('Notification' in window)) return;
const p = Notification.permission === 'granted' ? 'granted' : await Notification.requestPermission();
if (p === 'granted') new Notification('Saved', { body: 'Your note was saved', tag: 'note' });
}La chiamata grezza. Argomenti: titolo, testo, icona, tag. Passa '' per nessuna icona o nessun tag.
if (window.WebToApk && window.WebToApk.showNotification) {
WebToApk.showNotification(
'Saved', // title
'Your note was saved', // body
'https://example.com/avatar.png', // large icon (https://, data:, or 'img/x.png' in your app), or ''
'note' // tag: same tag replaces the old notification
);
}Aggiorna una notifica di stato sul posto riutilizzando il suo tag:
function showSyncStatus(done, total) {
const b = window.WebToApk;
if (!(b && b.showNotification)) return;
if (b.getNotificationPermission() !== 'granted') return;
b.showNotification(
'Syncing photos',
done + ' of ' + total + ' uploaded',
'', // no large icon
'sync' // same tag every time: the text updates, no new notification
);
}Note: passa a notify({title, body, largeIcon: icon, tag}) sul canale predefinito. Senza un tag ogni chiamata aggiunge una nuova notifica. Per immagini, pulsanti, avanzamento o una notifica fissa usa notify.
snoozeAlarm bridge#
window.WebToApk.snoozeAlarm(id: String, minutes: Int): Boolean
Ferma la sveglia che suona [id] ("" = quella che sta suonando) e la fa suonare di nuovo tra [minutes] (1-1440; 0 = lo snoozeMinutes della sveglia stessa). False quando non sta suonando.
Esempio
Ferma una sveglia che sta suonando e la fa suonare di nuovo dopo qualche minuto, come il suo pulsante Rimanda. Si sposta solo questa suoneria: una sveglia giornaliera suona comunque al solito orario domani.
Restituisce: true quando la sveglia stava suonando ed è stata rimandata; false quando non stava suonando. id '' = quella che sta suonando; minutes 1-1440, oppure 0 per il snoozeMinutes della sveglia stessa (predefinito 10). Richiede: 🔔 Sveglia nel passaggio Accesso (Passaggio 4) quando crei l'app.
document.getElementById('snooze').onclick = function () {
if (!(window.WebToApk && window.WebToApk.snoozeAlarm)) return;
if (WebToApk.snoozeAlarm('', 5)) showMessage('Ringing again in 5 minutes');
hideRingScreen();
};
window.addEventListener('appmint:reminder', function (e) {
// { id: 'wake', action: 'snooze', alarm: true, source: 'page', snoozeMinutes: 5, snoozedUntil: 1767340800000 }
if (e.detail.action === 'snooze') updateNextAlarmLabel(e.detail.snoozedUntil);
});Programma una sveglia, poi collega un pulsante per chiuderla:
const b = window.WebToApk;
if (b && b.snoozeAlarm && b.getAlarmSupport() === 'ready') {
b.scheduleNotificationEx('wake', JSON.stringify({
at: Date.now() + 8 * 3600000, repeat: 'daily', alarm: true,
title: 'Wake up', body: 'Good morning'
}));
}
document.getElementById('dismiss').onclick = () => {
if (WebToApk.isAlarmRinging()) WebToApk.stopAlarm('');
};Rimanda di quanto dura la sveglia stessa e gestisci il caso "non sta suonando niente":
document.getElementById('snooze').onclick = () => {
if (!(window.WebToApk && WebToApk.snoozeAlarm)) return;
const ok = WebToApk.snoozeAlarm('', 0); // 0 = the alarm's own snoozeMinutes (default 10)
if (!ok) showMessage('No alarm is ringing right now.');
};Note: la suoneria rimandata è elencata da getScheduledNotifications() come <id>#snooze; anche cancelNotification(id) la rimuove.
stopAlarm bridge#
window.WebToApk.stopAlarm(id: String): Boolean
Ferma la sveglia che suona [id] ("" = quella che sta suonando), come il suo pulsante Chiudi. Una sveglia ripetuta resta programmata per il prossimo orario. False quando non sta suonando.
Esempio
Ferma una sveglia che sta suonando, esattamente come il suo pulsante Chiudi. Una sveglia ripetuta resta impostata per il prossimo orario; usa cancelNotification(id) per rimuoverla.
Restituisce: true quando quella sveglia stava suonando e ora è ferma; false quando non stava suonando. Passa '' per fermare qualunque sveglia stia suonando. Richiede: 🔔 Sveglia nel passaggio Accesso (Passaggio 4) quando crei l'app.
window.addEventListener('appmint:reminder', function (e) {
const d = e.detail; // { id, action: 'open', ringing: true, overLockScreen }
if (d.action === 'open' && d.ringing) showRingScreen(d.id);
});
document.getElementById('stop').onclick = function () {
if (window.WebToApk && window.WebToApk.stopAlarm) WebToApk.stopAlarm(currentAlarmId);
hideRingScreen();
};Offri il pulsante di stop solo dove esiste il bridge e leggi la risposta:
const stopBtn = document.getElementById('stop');
if (window.WebToApk && typeof WebToApk.stopAlarm === 'function') {
stopBtn.onclick = function () {
const wasRinging = WebToApk.stopAlarm(''); // '' = whichever alarm is ringing
if (!wasRinging) showMessage('Nothing was ringing.');
};
} else {
stopBtn.hidden = true; // plain browser: no alarm clock
}Abbinalo a isAlarmRinging() così la pagina può mostrare la schermata della sveglia per una suoneria partita mentre era assente:
document.addEventListener('visibilitychange', function () {
if (document.hidden || !window.WebToApk) return;
if (WebToApk.isAlarmRinging && WebToApk.isAlarmRinging()) showRingScreen();
else hideRingScreen();
});Note: la pagina riceve quindi anche appmint:reminder con { id, action: 'dismiss', alarm: true, source: 'page' }.