API du pont JavaScript
Notifications sur l'appareil
Publication et programmation sans serveur, autorisation POST_NOTIFICATIONS, alarmes exactes et sons personnalisés.
AppMint.enableNotifications assistant#
AppMint.enableNotifications()
Exemple
« Activer les notifications » en un seul appel, pour les utilisateurs qui ont refusé ou ignoré l'invite de notification d'Android : la boîte de dialogue d'autorisation tant qu'Android peut encore l'afficher, sinon les paramètres de notification de cette application - et le nouvel état quand l'utilisateur revient.
Retourne : AppMint.enableNotifications() - une Promise qui se résout toujours {state, changed, openedSettings} ; state vaut 'granted' | 'prompt' | 'blocked' | 'unavailable'. AppMint.getNotificationState() - une Promise de cet état. AppMint.openNotificationSettings() - une Promise de true quand l'écran des paramètres s'est ouvert. Nécessite : appelez enableNotifications() depuis un bouton touché par l'utilisateur ; les notifications nécessitent Notifications (ou Push / Reminders) dans la compilation.
// 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 simple lien « Paramètres de notification » dans votre propre page de paramètres :
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.');
};Remarques : un bouton de push ou de message in-app dont le lien est appmint://notifications/enable exécute le même flux sans aucun code de page (la page entend appmint:notifications). L'audience push de l'application (« Notifications activées / désactivées ») se met à jour dès que l'utilisateur les active.
AppMint.getNotificationState assistant#
window.AppMint.getNotificationState
Exemple
Documenté avec AppMint.enableNotifications : l'exemple qui s'y trouve illustre aussi celui-ci.
« Activer les notifications » en un seul appel, pour les utilisateurs qui ont refusé ou ignoré l'invite de notification d'Android : la boîte de dialogue d'autorisation tant qu'Android peut encore l'afficher, sinon les paramètres de notification de cette application - et le nouvel état quand l'utilisateur revient.
Retourne : AppMint.enableNotifications() - une Promise qui se résout toujours {state, changed, openedSettings} ; state vaut 'granted' | 'prompt' | 'blocked' | 'unavailable'. AppMint.getNotificationState() - une Promise de cet état. AppMint.openNotificationSettings() - une Promise de true quand l'écran des paramètres s'est ouvert. Nécessite : appelez enableNotifications() depuis un bouton touché par l'utilisateur ; les notifications nécessitent Notifications (ou Push / Reminders) dans la compilation.
// 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 simple lien « Paramètres de notification » dans votre propre page de paramètres :
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.');
};Remarques : un bouton de push ou de message in-app dont le lien est appmint://notifications/enable exécute le même flux sans aucun code de page (la page entend appmint:notifications). L'audience push de l'application (« Notifications activées / désactivées ») se met à jour dès que l'utilisateur les active.
AppMint.openNotificationSettings assistant#
window.AppMint.openNotificationSettings
Exemple
Documenté avec AppMint.enableNotifications : l'exemple qui s'y trouve illustre aussi celui-ci.
« Activer les notifications » en un seul appel, pour les utilisateurs qui ont refusé ou ignoré l'invite de notification d'Android : la boîte de dialogue d'autorisation tant qu'Android peut encore l'afficher, sinon les paramètres de notification de cette application - et le nouvel état quand l'utilisateur revient.
Retourne : AppMint.enableNotifications() - une Promise qui se résout toujours {state, changed, openedSettings} ; state vaut 'granted' | 'prompt' | 'blocked' | 'unavailable'. AppMint.getNotificationState() - une Promise de cet état. AppMint.openNotificationSettings() - une Promise de true quand l'écran des paramètres s'est ouvert. Nécessite : appelez enableNotifications() depuis un bouton touché par l'utilisateur ; les notifications nécessitent Notifications (ou Push / Reminders) dans la compilation.
// 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 simple lien « Paramètres de notification » dans votre propre page de paramètres :
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.');
};Remarques : un bouton de push ou de message in-app dont le lien est appmint://notifications/enable exécute le même flux sans aucun code de page (la page entend appmint:notifications). L'audience push de l'application (« Notifications activées / désactivées ») se met à jour dès que l'utilisateur les active.
Notification standard web#
new Notification(title, options) / Notification.requestPermission()
Exemple
L'API web Notifications standard fonctionne dans l'application : new Notification() affiche une vraie notification Android, close() la retire, et Notification.requestPermission() affiche la boîte de dialogue d'autorisation Android et attend la réponse de l'utilisateur.
Retourne : Notification.permission vaut 'granted', 'denied' ou 'default', lu en direct depuis le téléphone (un changement dans les Paramètres apparaît sans rechargement). requestPermission() retourne une Promise de 'granted' ou 'denied' (la forme avec callback fonctionne aussi). Une nouvelle notification déclenche show quand elle est publiée, ou error quand l'autorisation manque. Nécessite : activez Notifications à l'étape Accès (étape 4) lors de la compilation.
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);Forme avec callback (ancien code) :
Notification.requestPermission(function (result) {
if (result === 'granted') new Notification('Welcome!', { body: 'Alerts are on', silent: true });
});Style service worker (code PWA) publie aussi via l'application, mais seulement là où le WebView lui-même n'a pas de navigator.serviceWorker (par exemple les pages file:// ou 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 appui déclenche click sur la notification - l'application passe au premier plan et la page le reçoit. Si l'application était fermée (l'appui l'a démarrée), l'objet n'existe plus, donc la fenêtre reçoit à la place un événement notificationclick, de la même forme que celui d'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);
});Remarques : options utilisées : body, icon, image, tag, silent, data (JSON, moins de 16 Ko). L'appui atteint la page à travers l'écran de démarrage et l'écran PIN (événement associé : appmint:notification-click). Sur Android 12 et antérieur, il n'y a pas d'autorisation à l'exécution, donc c'est 'granted' sauf si l'utilisateur a désactivé les notifications. Web Push (pushManager.subscribe) n'est pas pris en charge ; utilisez AppMint Push. Pour des boutons, une progression ou une notification persistante, utilisez WebToApk.notify(...). Le même code fonctionne dans un navigateur normal.
__badgeSupported pont#
window.WebToApk.__badgeSupported(): Boolean
Indique si ce lanceur peut afficher un compteur de pastille (navigator.setAppBadge n'existe que dans ce cas).
Exemple
Mécanisme interne derrière la présence de navigator.setAppBadge. Les pages utilisent l'API standard ; ne l'appelez jamais directement - les méthodes __ peuvent changer sans préavis.
Retourne : true quand le lanceur de ce téléphone affiche des compteurs de pastille. Nécessite : rien à activer.
Utilisez l'API publique :
if ('setAppBadge' in navigator) navigator.setAppBadge(unreadCount);N'affichez le réglage « pastille sur l'icône de l'application » que sur les téléphones dont le lanceur peut afficher un compteur :
function renderBadgeSetting() {
const row = document.getElementById('badge-setting');
// setAppBadge exists only when this launcher shows counts
row.hidden = !('setAppBadge' in navigator);
}
renderBadgeSetting();Effacez le compteur quand l'utilisateur ouvre la boîte de réception, sur tout lanceur qui en a un :
function openInbox() {
showInbox();
if ('clearAppBadge' in navigator) {
navigator.clearAppBadge().catch(function (e) {
console.warn('badge not cleared', e.name); // NotAllowedError
});
}
}Remarques : L'API Badging n'est installée que là où le lanceur peut afficher un compteur (Samsung, Huawei, Xiaomi, OPPO, Sony, …) ; sur les lanceurs de type Pixel, elle est absente, comme dans un navigateur sans badging.
__closeNotification pont#
window.WebToApk.__closeNotification(tag: String): Boolean
Notification.close() : retire une notification publiée par la page, par son tag.
Exemple
Mécanisme interne derrière Notification.prototype.close() - les pages utilisent new Notification(...) et appellent close() dessus. Il retire une notification du volet par son tag.
Retourne : true quand la demande de suppression a été faite (aussi quand rien n'avait ce tag) ; false en cas d'erreur interne. Nécessite : rien.
Utilisez l'API publique :
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
}Ouvrez la bonne conversation quand la notification est touchée, puis retirez-la du volet :
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();
};
}Affichez une courte confirmation qui se retire d'elle-même après cinq secondes :
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);
}Remarques : n'appelez pas WebToApk.__closeNotification directement ; les méthodes __ peuvent changer sans préavis. close() déclenche l'événement close de la notification.
__setAppBadge pont#
window.WebToApk.__setAppBadge(contents: Long): Boolean
navigator.setAppBadge(n) : n >= 0 est un compteur (0 l'efface), -1 la pastille drapeau de la spécification.
Exemple
Mécanisme interne derrière navigator.setAppBadge(count) / clearAppBadge(). Les pages utilisent l'API standard ; ne l'appelez jamais directement - les méthodes __ peuvent changer sans préavis.
Retourne : true quand le compteur a été appliqué. Nécessite : rien à activer.
Utilisez l'API publique :
if ('setAppBadge' in navigator) navigator.setAppBadge(unreadCount);Gardez le compteur de l'icône aligné sur le nombre de non lus, et effacez-le à zéro :
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);Mettez une pastille drapeau (sans nombre) sur l'icône tant qu'il y a du travail non synchronisé :
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 () {});
}Remarques : -1 est la pastille drapeau de la spécification (sans nombre), qu'un lanceur à compteur affiche comme 1.
cancelAllNotifications pont#
window.WebToApk.cancelAllNotifications(): Boolean
Lecture et demande de l'autorisation POST_NOTIFICATIONS, et gestion des notifications déjà programmées par la page. La publication et la programmation sont documentées dans leurs propres méthodes.
Décrit par son groupe, Autorisation de notification, annulation et liste, plutôt que séparément.
Exemple
Annule tous les rappels programmés par cette application.
Retourne : true quand c'est fait ; false uniquement en cas d'erreur interne. Nécessite : rien de plus.
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');
});À la déconnexion, arrêtez les rappels de l'utilisateur précédent et effacez le compteur de l'icône :
async function signOut() {
if (window.WebToApk && window.WebToApk.cancelAllNotifications) {
WebToApk.cancelAllNotifications();
}
if ('clearAppBadge' in navigator) navigator.clearAppBadge().catch(function () {});
await auth.signOut();
showLoginScreen();
}Reconstruisez tout le planning quotidien à partir des heures enregistrées (tout annuler, puis ajouter chacune) :
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');
});
}Remarques : cela vide la liste programmée, donc rien ne se déclenchera plus tard et rien n'est reprogrammé après un redémarrage. Les notifications déjà affichées dans le volet y restent.
cancelNotification pont#
window.WebToApk.cancelNotification(id: String): Boolean
Lecture et demande de l'autorisation POST_NOTIFICATIONS, et gestion des notifications déjà programmées par la page. La publication et la programmation sont documentées dans leurs propres méthodes.
Décrit par son groupe, Autorisation de notification, annulation et liste, plutôt que séparément.
Exemple
Annule un rappel programmé par son id, pour qu'il ne se déclenche plus.
Retourne : true (aussi quand aucun rappel n'avait cet id) ; false uniquement en cas d'erreur interne. Nécessite : rien de plus (les rappels nécessitent ⏰ Reminders à la compilation).
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 interrupteur de rappel dans les paramètres qui programme ou annule avec le même 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');
}
});Quand une tâche est supprimée, annulez tous les rappels qui lui appartiennent :
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); });
}Remarques : cela annule un rappel qui ne s'est pas encore déclenché (unique ou récurrent). Cela ne retire pas une notification déjà affichée dans le volet, et n'affecte pas les notifications publiées avec notify() / showNotification().
canOpenAppAtTime pont#
window.WebToApk.canOpenAppAtTime(): String
Indique si une notification programmée peut afficher L'APPLICATION ELLE-MÊME à l'écran (`openApp`). "granted" - une alerte plein écran s'affichera, même sur l'écran de verrouillage. "denied" - Android 14+ l'a refusée ; appelez requestOpenAppPermission(). Il n'existe pas de troisième réponse où l'application se lance silencieusement en arrière-plan : Android bloque les démarrages d'activité en arrière-plan depuis Android 10, et un intent plein écran est tout ce qui reste.
Exemple
Indique si un rappel avec openApp: true peut afficher l'application elle-même à l'écran (une alerte plein écran, même sur l'écran de verrouillage).
Retourne : une chaîne, de façon synchrone : 'granted' ou 'denied'. En dessous d'Android 14, c'est toujours 'granted'. Nécessite : activez ⏰ Reminders à l'étape Accès (étape 4) lors de la compilation.
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);
});Un écran de paramètres qui affiche les deux interrupteurs d'alarme avec leur état actuel :
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
});Avertissez quand des alarmes enregistrées étaient réglées pour ouvrir l'application mais qu'Android ne l'autorise pas en ce moment :
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.');
}
}Remarques : quand c'est 'denied', un rappel openApp publie quand même une notification flottante, mais l'application ne s'ouvre pas toute seule. Android n'autorise aucun autre moyen pour une application de se lancer elle-même en arrière-plan.
clearNotificationSounds pont#
window.WebToApk.clearNotificationSounds(): Int
Supprime les fichiers son copiés et retourne combien ont été supprimés. Un fichier est recopié quand une notification (ou un rappel programmé, quand il se déclenche) utilise ensuite ce son - y compris sur un canal déjà existant, qui continue de pointer vers le même nom de fichier (NotificationBridge.restoreBundleSound).
Exemple
Supprime les copies de vos sons de notification personnalisés que l'application a créées à partir de votre bundle.
Retourne : un nombre, de façon synchrone : combien de fichiers ont été supprimés. Nécessite : rien.
Effacez, puis remettez les sons que vous utilisez encore :
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 bouton d'écran de stockage qui libère les fichiers son copiés et indique combien ont été supprimés :
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).');
});À la déconnexion, annulez tous les rappels et supprimez les copies de sons appartenant à cet utilisateur :
function signOutAndReset() {
const b = window.WebToApk;
if (b && b.cancelAllNotifications) b.cancelAllNotifications();
if (b && b.clearNotificationSounds) b.clearNotificationSounds();
localStorage.removeItem('alarmSound');
goToLoginScreen();
}Remarques : vous en aurez rarement besoin ; les copies sont petites. Un son est recopié la prochaine fois que quelque chose l'utilise - notify(), un rappel quand il se déclenche, scheduleNotificationEx, ou prepareNotificationSound(path) - y compris sur un canal de notification déjà existant, de sorte que le son personnalisé continue de jouer.
enableNotifications pont#
window.WebToApk.enableNotifications(callbackId: String)
Ramène un utilisateur vers les notifications : la boîte de dialogue système tant qu'elle peut encore être affichée, sinon les paramètres de notification de l'application. Résout `window.__appmintReplies[callbackId]` avec {state, changed, openedSettings} (AppMint.enableNotifications() est l'enveloppe Promise).
Exemple
Ramène un utilisateur qui a refusé ou ignoré les notifications : affiche la boîte de dialogue d'autorisation d'Android tant qu'elle peut encore l'être, sinon ouvre les paramètres de notification de cette application et répond quand l'utilisateur revient.
Retourne : rien directement. La réponse {state, changed, openedSettings} est transmise à window.__appmintReplies[callbackId] ; state vaut 'granted' | 'prompt' | 'blocked' | 'unavailable', changed vaut true quand elle diffère d'avant l'appel, openedSettings vaut true quand l'écran des paramètres a été utilisé. Déjà 'granted' (ou 'unavailable') répond aussitôt. Nécessite : appelez-le depuis un bouton touché par l'utilisateur ; les notifications nécessitent Notifications (ou Push / Reminders) dans la compilation.
Préférez l'enveloppe Promise AppMint.enableNotifications(). L'appel brut, pour le code qui gère ses propres réponses :
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;
};Chaque flux terminé est aussi annoncé, y compris celui démarré par un bouton de 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;
});Remarques : un bouton de push ou de message in-app dont le lien est appmint://notifications/enable exécute ce même flux ; appmint://notifications/settings ouvre l'écran des paramètres. L'audience push de l'application voit le nouvel état aussitôt.
getAlarmPrecision pont#
window.WebToApk.getAlarmPrecision(): String
"exact" - les rappels se déclenchent à la minute. "inexact" - l'utilisateur (ou le fabricant) a désactivé les alarmes exactes pour cette application, donc Doze peut les regrouper de quelques minutes. Appelez [requestExactAlarms] pour y remédier. "unavailable" - Android 12+ et le service d'alarmes du système était inaccessible, donc la précision ne peut pas être lue (un rappel programmé maintenant risque aussi de ne pas se déclencher). Une page qui doit être à l'heure devrait vérifier cela plutôt que le supposer. @return `"exact"`, `"inexact"` ou `"unavailable"`.
Exemple
Indique si les rappels se déclencheront à la minute près, ou pourront être en retard parce que l'utilisateur (ou le fabricant du téléphone) a désactivé les alarmes exactes pour cette application.
Retourne : une chaîne, de façon synchrone : 'exact', 'inexact' (peut être regroupé par l'économie de batterie, souvent de quelques minutes), ou 'unavailable' (le téléphone n'a pas de service d'alarmes). Nécessite : activez ⏰ Reminders à l'étape Accès (étape 4) lors de la compilation.
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();
});Vérifiez avant de régler un réveil du matin, et prévenez l'utilisateur s'il risque d'être en retard :
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.');
}
}Affichez la précision des rappels sous forme de ligne dans un écran de paramètres :
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();Remarques : Android 11 et antérieur répondent toujours 'exact'. Un rappel 'inexact' se déclenche quand même, mais pas à la minute.
getAlarmSupport pont#
window.WebToApk.getAlarmSupport(): String
Indique si `scheduleNotificationEx(id, {alarm: true, ...})` peut être programmé maintenant : "ready" | "not_enabled" (Alarm clock est désactivé dans cette compilation) | "needs_exact_alarm" (appelez requestExactAlarms) | "needs_notification_permission".
Exemple
Indique si un réveil (scheduleNotificationEx(id, { alarm: true, ... })) peut être réglé sur ce téléphone maintenant, et sinon, ce que l'utilisateur doit d'abord autoriser.
Retourne : une chaîne, de façon synchrone : 'ready', 'not_enabled' (l'application a été compilée sans 🔔 Alarm clock), 'needs_exact_alarm' (Android 12+ : les alarmes exactes sont désactivées pour cette application - appelez requestExactAlarms()), ou 'needs_notification_permission' (Android 13+ : pas d'autorisation de notification, donc il n'y aurait pas de bouton Dismiss - appelez requestNotificationPermission()). Nécessite : activez 🔔 Alarm clock à l'étape Accès (étape 4) lors de la compilation.
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;
}
}Revérifiez quand l'utilisateur revient des Paramètres :
document.addEventListener('visibilitychange', function () {
if (document.hidden || !(window.WebToApk && window.WebToApk.getAlarmSupport)) return;
document.getElementById('alarm-setup').hidden = WebToApk.getAlarmSupport() === 'ready';
});Créez un réveil seulement quand le téléphone est prêt :
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'
}));
}Remarques : scheduleNotificationEx avec alarm: true retourne false chaque fois que ce n'est pas 'ready' - un réveil qui ne pourrait jamais sonner n'est jamais enregistré.
getNotificationPermission pont#
window.WebToApk.getNotificationPermission(): String
L'autorisation de notification ACTUELLE, lue en direct depuis le système. Le polyfill codait en dur `Notification.permission = 'default'` à chaque chargement de page, si bien que le schéma de page ultra courant if (Notification.permission === 'granted') new Notification(...) ne se déclenchait jamais - pas même pour un utilisateur qui l'avait déjà accordée, ni sur Android 12 et antérieur où les notifications n'exigent aucune autorisation à l'exécution.
Exemple
Lit, à l'instant, si cette application peut publier des notifications.
Retourne : une chaîne, de façon synchrone : 'granted' ; 'denied' (l'utilisateur a refusé définitivement, ou a désactivé les notifications de cette application dans les Paramètres - une publication ne s'afficherait pas) ; ou 'default' (pas encore décidé, l'application peut encore demander). Nécessite : rien pour l'appeler ; la publication nécessite Notifications activées à l'étape Accès (étape 4) lors de la compilation.
L'API web standard lit la même valeur en direct :
if ('Notification' in window && Notification.permission === 'granted') {
document.getElementById('alerts-on').hidden = false;
}L'appel brut, par exemple quand l'utilisateur revient des Paramètres :
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();Décidez avant de programmer s'il faut demander, expliquer ou continuer :
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';
}Remarques : elle donne la même réponse que navigator.permissions.query({ name: 'notifications' }). Pour demander à l'utilisateur, utilisez Notification.requestPermission().
getNotificationState pont#
window.WebToApk.getNotificationState(): String
'granted' | 'prompt' (Android peut encore demander) | 'blocked' (refusé définitivement ou désactivé dans les Paramètres - seuls les Paramètres peuvent y remédier) | 'unavailable' (Android 13+ et cette compilation ne déclare pas l'autorisation de notification). Voir NotificationOptIn.
Exemple
Lit, à l'instant, si les notifications de cette application sont activées - et sinon, si l'application peut encore demander ou si seuls les Paramètres peuvent les réactiver.
Retourne : une chaîne, de façon synchrone : 'granted' (les notifications parviennent au téléphone) ; 'prompt' (Android peut encore afficher sa boîte de dialogue d'autorisation) ; 'blocked' (l'utilisateur a refusé définitivement, ou a désactivé les notifications de cette application dans les Paramètres système - seuls les Paramètres peuvent y remédier) ; ou 'unavailable' (Android 13+ et l'application a été compilée sans Notifications / Reminders / Push, donc rien ne peut les activer). Nécessite : rien pour l'appeler.
L'appel brut, pour décider d'afficher ou non une bannière « Activer les notifications » :
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();Remarques : getNotificationPermission() garde ses propres termes ('granted' / 'default' / 'denied') pour les anciennes pages. Pour ramener l'utilisateur, appelez AppMint.enableNotifications() (il choisit pour vous entre la boîte de dialogue et les Paramètres).
getScheduledNotifications pont#
window.WebToApk.getScheduledNotifications(): String
Lecture et demande de l'autorisation POST_NOTIFICATIONS, et gestion des notifications déjà programmées par la page. La publication et la programmation sont documentées dans leurs propres méthodes.
Décrit par son groupe, Autorisation de notification, annulation et liste, plutôt que séparément.
Exemple
Liste les rappels encore programmés.
Retourne : une chaîne JSON, de façon synchrone. Analysez-la. Chaque élément : { id, title, body, trigger, repeat, options? } - trigger est la prochaine heure de déclenchement en ms epoch, repeat vaut none|minutely|hourly|daily|weekly, et options (uniquement pour scheduleNotificationEx) est le JSON des options sous forme de chaîne. Les champs live indiquent comment elle sera réellement livrée, lus en direct : precision ("exact" ; "inexact" = « Alarmes et rappels » est désactivé pour l'application, donc Android la livre dans une fenêtre de 10 minutes quand le téléphone est actif, et peut la retenir plus longtemps pendant la veille ; "alarm_clock" pour alarm: true), windowMs + latestAt (la fenêtre accordée par Android : 0 / trigger quand exacte, 600000 / trigger + 600000 quand inexacte) et notificationsEnabled (false = elle se déclenche mais Android n'affiche rien, car les notifications de l'application sont désactivées). '[]' quand il n'y en a aucune. Nécessite : rien de plus.
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);
});
}Affichez si un rappel est activé, et quand il se déclenche ensuite :
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');Lisez les options supplémentaires des rappels créés avec 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; });
}Remarques : un rappel unique quitte la liste quand il se déclenche. Un rappel récurrent y reste, avec trigger avancé à l'occurrence suivante. Un rappel dont l'heure est passée pendant que le téléphone était éteint ou l'application arrêtée de force est affiché une fois, en retard, au prochain démarrage de l'application ou du téléphone ; un alarm: true en retard est signalé comme missed au lieu de sonner. Un rappel quotidien, hebdomadaire, mensuel ou annuel conserve son heure locale quand le téléphone change de fuseau horaire.
Avertissez quand les rappels n'arriveront pas à l'heure :
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 pont#
window.WebToApk.isAlarmRinging(): Boolean
True tant qu'un réveil sonne.
Exemple
Indique si l'un des réveils de l'application sonne en ce moment, pour que la page puisse afficher son propre écran d'arrêt / de répétition.
Retourne : true tant qu'un réveil sonne, sinon false (de façon synchrone). Nécessite : 🔔 Alarm clock à l'étape Accès (étape 4) lors de la compilation.
function showRingScreenIfNeeded() {
const b = window.WebToApk;
const ringing = !!(b && b.isAlarmRinging && b.isAlarmRinging());
document.getElementById('ring-screen').hidden = !ringing;
}
showRingScreenIfNeeded();
document.addEventListener('visibilitychange', showRingScreenIfNeeded);Arrêtez le réveil qui sonne depuis votre propre écran avec les appels correspondants.
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');
});Réagissez à l'ouverture de l'application par un réveil qui sonne.
window.addEventListener('appmint:reminder', function (e) {
if (e.detail.action === 'open' && e.detail.ringing) {
document.getElementById('ring-screen').hidden = false;
}
});Remarques : quand le réveil qui sonne ouvre l'application, appmint:reminder arrive aussi avec { action: 'open', ringing: true }.
notify pont#
window.WebToApk.notify(optionsJson: String): Boolean
Notification riche. Voir NotificationBridge.show pour la liste complète des options : channel (urgent|default|quiet|ongoing), image, largeIcon, bigText, ongoing, actions, progress, sound, silent, group, color. La récupération et le décodage des images se font hors du thread principal, donc une image distante ne peut jamais bloquer la page.
Exemple
Publie une notification immédiatement, avec n'importe quelle combinaison d'options : image, texte long, boutons, barre de progression, persistante (ongoing), canal, son, couleur et tag.
Retourne : true quand les options étaient du JSON valide et que la notification a été transmise au système (elle est construite sur un thread d'arrière-plan, donc une mauvaise URL d'image ne bloque pas la page) ; false pour un JSON invalide. Nécessite : activez Notifications à l'étape Accès (étape 4) lors de la compilation, et l'autorisation de l'utilisateur sur Android 13+ (demandez avec Notification.requestPermission()).
Notification simple. tag est un identifiant : publier de nouveau avec le même tag remplace l'ancienne.
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'
}));
}Image, grande icône et texte long. image l'emporte sur bigText quand les deux sont fournis.
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'
}));Boutons (3 au maximum). L'appui revient sous forme d'événement 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);
});Progression persistante (ongoing). Republiez avec le même tag pour la mettre à jour. Quand la tâche se termine, publiez l'état final avec ongoing: false pour que l'utilisateur puisse la balayer.
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' }));Autres options : sound (un fichier de votre bundle comme '/audio/ding.mp3', une URL data:audio/..., ou 'silent'), smallIcon (un nom de drawable), when (époque en ms affichée comme l'heure), openApp: true (alerte plein écran ; voir scheduleNotificationEx).
Remarques : les boutons n'ont pas de zone de réponse intégrée, et l'appui sur un bouton n'atteint la page que pendant que l'application tourne (il n'ouvre pas l'application) ; l'événement appelle aussi window.onAppMintNotificationAction(detail) si vous la définissez. image et largeIcon acceptent une URL https:// ou data:, ou une image incluse dans votre application nommée comme votre page la nomme ('img/logo.png', '/img/logo.png', ou son adresse complète https://appassets.androidplatform.net/assets/…). Une mauvaise image est ignorée, la notification s'affiche quand même. ongoing: true utilise toujours le canal discret « Ongoing ». notify() n'a pas de pendant public « remove » : cancelNotification n'annule que les rappels programmés. Une notification que vous voulez retirer plus tard depuis la page doit être publiée avec new Notification(...) et retirée avec son close() ; une carte de progression persistante avec Capacitor.AppwrightLiveProgress (end). Android fixe le son d'un canal à la création du canal, donc une nouvelle valeur de sound crée un nouveau canal.
openNotificationSettings pont#
window.WebToApk.openNotificationSettings(): Boolean
Ouvre les paramètres de notification de cette application ; true quand l'écran a pu être ouvert.
Exemple
Ouvre l'écran de paramètres de notification propre à cette application, où l'utilisateur peut activer ou désactiver les notifications (et chaque canal).
Retourne : true quand l'écran a été ouvert, de façon synchrone ; false quand il ne peut pas l'être (Android 13+ et la compilation n'a pas de notifications). Sur Android 8+, c'est la page de notification de l'application ; sur les Android plus anciens, l'écran Infos sur l'application. Nécessite : rien à activer.
document.getElementById('notif-settings-link').onclick = function () {
if (!(window.WebToApk && WebToApk.openNotificationSettings && WebToApk.openNotificationSettings())) {
showMessage('Open Settings > Apps > this app > Notifications.');
}
};Remarques : pour ramener un utilisateur en un appui, utilisez plutôt AppMint.enableNotifications() : il affiche la boîte de dialogue d'autorisation quand Android l'autorise encore et n'ouvre cet écran que dans le cas contraire.
prepareNotificationSound pont#
window.WebToApk.prepareNotificationSound(spec: String): Boolean
Copie à l'avance un fichier audio inclus et indique s'il est utilisable comme son de notification. Facultatif - `notify()` et `scheduleNotificationEx()` le font eux-mêmes - mais cela permet à un écran de paramètres de vérifier un son dès que l'utilisateur le choisit.
Exemple
Vérifie qu'un fichier audio de votre application peut servir de son de notification, et le copie en place maintenant. Facultatif : notify() et scheduleNotificationEx() le font d'eux-mêmes ; cela permet à un écran de paramètres de vérifier un son dès que l'utilisateur le choisit.
Retourne : true si le son est utilisable ; false si le fichier n'existe pas ou n'est pas d'un type audio pris en charge. Nécessite : rien.
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' }));
}Remplissez un sélecteur de sons avec uniquement les sons réellement utilisables :
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);
});
}Laissez l'utilisateur choisir son propre fichier audio et utilisez-le pour un rappel quotidien, passé comme 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);
});Valeurs acceptées : un chemin dans votre bundle web ('/audio/chime.mp3', 'audio/chime.mp3') ou une URL data:audio/...;base64,... créée par votre page. Types : mp3, wav, ogg, oga, m4a, aac, flac, opus, mid, midi.
Remarques : un simple nom sans dossier ni extension (un son res/raw) n'est pas vérifié ici et retourne false, même si notify({sound: 'name'}) peut l'utiliser. Android garde un seul son par canal, donc changer le son crée un nouveau canal et réinitialise les réglages de l'utilisateur pour ce canal.
requestExactAlarms pont#
window.WebToApk.requestExactAlarms(): Boolean
Ouvre l'écran système où les alarmes exactes sont accordées. Android 12+.
Exemple
Ouvre l'écran système d'Android 12+ où l'utilisateur autorise cette application à utiliser les alarmes exactes, pour que les rappels se déclenchent à la minute.
Retourne : true quand l'écran des paramètres a été ouvert (et sur Android 11 et antérieur, où rien n'est nécessaire) ; false si l'écran n'a pas pu être ouvert. Il ne vous dit pas le choix de l'utilisateur. Nécessite : activez ⏰ Reminders à l'étape Accès (étape 4) lors de la compilation.
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;
});Avant d'enregistrer un rappel critique en temps, ne proposez l'écran de paramètres que si la précision est réellement dégradée :
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.');
}
}Quand l'écran des paramètres ne peut pas être ouvert (false), indiquez à l'utilisateur où trouver l'interrupteur :
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().
});Remarques : appelez-le depuis un appui sur un bouton et expliquez d'abord pourquoi - il quitte votre application. Les rappels déjà programmés continuent de fonctionner dans tous les cas ; seule leur précision change.
requestNotificationPermission pont#
window.WebToApk.requestNotificationPermission(): String
Lecture et demande de l'autorisation POST_NOTIFICATIONS, et gestion des notifications déjà programmées par la page. La publication et la programmation sont documentées dans leurs propres méthodes.
Décrit par son groupe, Autorisation de notification, annulation et liste, plutôt que séparément.
Exemple
Affiche la boîte de dialogue « Autoriser les notifications ? » d'Android 13+. Les pages utilisent normalement Notification.requestPermission(), qui l'appelle et attend la réponse de l'utilisateur.
Retourne : une chaîne, de façon synchrone : 'granted' si déjà autorisé (ou sur Android 12 et antérieur), sinon 'default' pendant que la boîte de dialogue s'ouvre. Elle ne peut pas retourner la réponse de l'utilisateur. Nécessite : activez Notifications à l'étape Accès (étape 4) lors de la compilation.
Utilisez l'API Promise - elle se résout avec la vraie réponse ('granted' ou '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.');
}
});L'appel brut, uniquement pour ouvrir la boîte de dialogue sans attendre :
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')
}L'ancien code qui passe un callback à Notification.requestPermission obtient la même réponse 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
});
});Remarques : demandez depuis un appui sur un bouton avec une raison claire. Après deux refus, Android n'affiche plus la boîte de dialogue et la réponse est aussitôt 'denied' ; l'utilisateur doit alors l'autoriser dans les Paramètres de l'application.
requestOpenAppPermission pont#
window.WebToApk.requestOpenAppPermission(): Boolean
Ouvre l'écran système où l'alerte plein écran est accordée. Android 14+.
Exemple
Ouvre l'écran système d'Android 14+ où l'utilisateur autorise les alertes plein écran pour cette application, pour qu'un rappel openApp: true puisse afficher l'application à l'écran.
Retourne : true quand l'écran des paramètres a été ouvert (et en dessous d'Android 14, où rien n'est nécessaire) ; false s'il n'a pas pu être ouvert. Il ne vous dit pas le choix de l'utilisateur. Nécessite : activez ⏰ Reminders à l'étape Accès (étape 4) lors de la compilation.
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;
});Mémorisez le réveil que l'utilisateur était en train de régler, envoyez-le dans les Paramètres, et terminez quand il revient :
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;
});Quand l'écran des paramètres ne peut pas être ouvert (false), indiquez où se trouve l'interrupteur :
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.');
}
});Remarques : appelez-le depuis un appui sur un bouton après avoir expliqué pourquoi - il quitte votre application.
scheduleNotification pont#
window.WebToApk.scheduleNotification(id: String, title: String, body: String, triggerAtMillis: String, repeat: String): Boolean
Lecture et demande de l'autorisation POST_NOTIFICATIONS, et gestion des notifications déjà programmées par la page. La publication et la programmation sont documentées dans leurs propres méthodes.
Décrit par son groupe, Autorisation de notification, annulation et liste, plutôt que séparément.
Exemple
Programme un rappel simple (titre et texte) pour une heure future. Il se déclenche même quand l'application est fermée et est reprogrammé après le redémarrage du téléphone.
Retourne : true quand il a été programmé ; false quand id est vide ou que l'heure n'est pas un nombre. Nécessite : activez ⏰ Reminders à l'étape Accès (étape 4) lors de la compilation (cela active aussi Notifications), et l'autorisation de notification de l'utilisateur sur 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');
}Sachez quand un rappel a ouvert l'application (l'utilisateur l'a touché) :
window.addEventListener('appmint:reminder', function (e) {
// e.detail = { id: 'water', overLockScreen: false }
if (e.detail.id === 'water') openWaterLog();
});Un rappel unique à 8 h le jour d'échéance d'une tâche :
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'
);
}Remarques : le rappel utilise le style « urgent » (flottant) et son tag est l'id. Un rappel récurrent manqué pendant que le téléphone était éteint se déclenche à l'occurrence suivante. Pour une image, des boutons, votre propre son ou l'ouverture de l'application sur l'écran de verrouillage, utilisez scheduleNotificationEx. Si les alarmes exactes sont désactivées pour l'application, l'heure peut dériver de quelques minutes ; vérifiez getAlarmPrecision().
scheduleNotificationEx pont#
window.WebToApk.scheduleNotificationEx(id: String, optionsJson: String): Boolean
La forme complète de [scheduleNotification] : tout ce que `notify()` accepte, déclenché à une heure future application fermée. 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 son inclus est copié en place pendant cet appel, donc un mauvais nom de fichier est signalé tout de suite (false) plutôt que de devenir le son par défaut des jours plus tard.
Exemple
Programme un rappel avec toutes les options de notify() (image, boutons, son, canal, ouverture de l'application), pour une heure future. Il se déclenche quand l'application est fermée et survit à un redémarrage.
Retourne : true quand programmé. false quand aucune heure n'est donnée (at, triggerAt, triggerAtMillis ou inSeconds), que l'id est vide, que le JSON est invalide, ou que sound désigne un fichier absent de votre application. Nécessite : activez ⏰ Reminders à l'étape Accès (étape 4) lors de la compilation, et l'autorisation de notification de l'utilisateur sur Android 13+.
Un rappel quotidien avec votre propre son qui ouvre l'application (sur l'écran de verrouillage) :
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);
});Jours de sport uniquement - lundi, mercredi et vendredi à 18 h 00 (days suit l'ISO : lundi = 1 … dimanche = 7 ; sans days, 'weekdays' signifie lundi-vendredi) :
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' }));Un vrai réveil (alarm: true) : sonne sur le volume ALARME du téléphone - même en mode silencieux, et même en Ne pas déranger quand l'utilisateur autorise les alarmes - et continue de sonner jusqu'à Dismiss / Snooze ou ringSeconds. Il affiche l'icône d'alarme dans la barre d'état et s'affiche à l'écran par-dessus l'écran de verrouillage :
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 rappel avec boutons, dans 30 minutes :
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 rappel unique avec image au début d'une promotion, sur le canal normal :
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
}));
}Remarques : le même id remplace un ancien rappel. Valeurs par défaut : tag = l'id, canal = urgent, bigText = le corps. L'appui sur un bouton n'atteint la page que pendant que l'application tourne. Le fichier son est copié à la programmation, donc un mauvais chemin échoue tout de suite et non des jours plus tard ; mp3, wav, ogg, m4a, aac, flac et opus fonctionnent. openApp est le seul moyen pour une application d'apparaître à l'écran d'elle-même à une heure donnée ; sur Android 14+, l'utilisateur doit l'autoriser (canOpenAppAtTime). repeat: 'weekdays' avec days hors de 1-7 retourne false. alarm: true nécessite 🔔 Alarm clock à l'étape Accès (étape 4) et retourne false sauf si getAlarmSupport() est 'ready' ; un seul réveil sonne à la fois (un nouveau termine le précédent comme missed). Si le fichier son d'un réveil a disparu au moment où il sonne (une mise à jour à distance l'a supprimé), il sonne avec la sonnerie d'alarme du téléphone et l'événement porte soundError: true.
showNotification pont#
window.WebToApk.showNotification(title: String, body: String, icon: String, tag: String): Boolean
La forme ORIGINALE à quatre arguments, conservée telle quelle comme adaptateur pour que toutes les applications déjà en circulation et tous les extraits de guide continuent de fonctionner. Elle transmet désormais au constructeur riche - ce qui signifie que l'argument `icon`, ignoré en silence par l'ancienne implémentation, fait enfin quelque chose.
Exemple
L'appel de notification d'origine à quatre arguments. Il affiche une notification avec un titre, un texte, une grande icône facultative et un tag. Le nouveau code devrait utiliser notify(optionsJson) ou new Notification(...), qui font plus.
Retourne : true quand la notification a été transmise au système. Nécessite : activez Notifications à l'étape Accès (étape 4) lors de la compilation, et l'autorisation de l'utilisateur sur Android 13+.
L'API web standard (elle appelle cette méthode pour vous) :
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' });
}L'appel brut. Arguments : titre, corps, icône, tag. Passez '' pour aucune icône ou aucun 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
);
}Mettez à jour une notification d'état sur place en réutilisant son 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
);
}Remarques : elle transmet à notify({title, body, largeIcon: icon, tag}) sur le canal par défaut. Sans tag, chaque appel ajoute une nouvelle notification. Pour des images, des boutons, une progression ou une notification persistante, utilisez notify.
snoozeAlarm pont#
window.WebToApk.snoozeAlarm(id: String, minutes: Int): Boolean
Arrête le réveil [id] qui sonne ("" = celui qui sonne) et le fait resonner dans [minutes] (1-1440 ; 0 = le snoozeMinutes propre au réveil). False quand il ne sonne pas.
Exemple
Arrête un réveil qui sonne et le fait resonner quelques minutes plus tard, comme son bouton Snooze. Seule cette sonnerie est décalée : un réveil quotidien sonne toujours à son heure habituelle demain.
Retourne : true quand le réveil sonnait et est répété ; false quand il ne sonnait pas. id '' = celui qui sonne ; minutes 1-1440, ou 0 pour le snoozeMinutes propre au réveil (10 par défaut). Nécessite : 🔔 Alarm clock à l'étape Accès (étape 4) lors de la compilation.
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);
});Programmez un réveil, puis branchez un bouton d'arrêt :
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('');
};Répétez selon la durée propre du réveil, et gérez le cas « rien ne sonne » :
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.');
};Remarques : la sonnerie répétée est listée par getScheduledNotifications() sous la forme <id>#snooze ; cancelNotification(id) la supprime aussi.
stopAlarm pont#
window.WebToApk.stopAlarm(id: String): Boolean
Arrête le réveil [id] qui sonne ("" = celui qui sonne), comme son bouton Dismiss. Un réveil récurrent reste programmé pour sa prochaine heure. False quand il ne sonne pas.
Exemple
Arrête un réveil qui sonne, exactement comme son bouton Dismiss. Un réveil récurrent reste programmé pour sa prochaine heure ; utilisez cancelNotification(id) pour le supprimer.
Retourne : true quand ce réveil sonnait et est maintenant arrêté ; false quand il ne sonnait pas. Passez '' pour arrêter celui qui sonne. Nécessite : 🔔 Alarm clock à l'étape Accès (étape 4) lors de la compilation.
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();
};Ne proposez le bouton d'arrêt que là où le pont existe, et lisez la réponse :
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
}Associez-le à isAlarmRinging() pour que la page puisse afficher l'écran de sonnerie pour une sonnerie démarrée pendant son absence :
document.addEventListener('visibilitychange', function () {
if (document.hidden || !window.WebToApk) return;
if (WebToApk.isAlarmRinging && WebToApk.isAlarmRinging()) showRingScreen();
else hideRingScreen();
});Remarques : la page reçoit alors aussi appmint:reminder avec { id, action: 'dismiss', alarm: true, source: 'page' }.