Notificaciones
Notificaciones locales y recordatorios
Muestra notificaciones instantáneas o programa recordatorios que se disparan incluso con la app cerrada: en el dispositivo, sin servidor
1Qué añade esto#
Tu app puede mostrar notificaciones de Android desde su propio código, en dos niveles:
- Instantánea (Nivel 1): una notificación que aparece ahora mismo, mientras la app está abierta. Útil para 'descarga completada', 'temporizador terminado', etc.
- Recordatorios programados (Nivel 2): una notificación que se dispara en un momento futuro incluso con la app CERRADA y que sobrevive a un reinicio. Es lo que necesitan las apps de recordatorios, hábitos, alarmas y medicación.
Son 100 % en el dispositivo y sin conexión: sin servidor, sin cuenta de OneSignal. (El push de OneSignal es una función aparte para mensajes que TÚ envías desde un servidor.)
2Actívalo en el asistente de compilación#
En el Paso 4 (Acceso), marca:
- 🔔 Notificaciones: permite que la app publique notificaciones (añade POST_NOTIFICATIONS).
- ⏰ Recordatorios: añade notificaciones programadas que se disparan con la app cerrada (añade la infraestructura de alarma exacta y reprogramación al arrancar). Marcar Recordatorios activa automáticamente Notificaciones.
Deja ambos desactivados en apps que no necesitan notificaciones: no se añade nada extra a tu APK.
3Llama al puente desde tu código web#
AppMint expone un puente JavaScript en window.WebToApk. Detecta siempre primero si existe: solo existe dentro de la app instalada, así que tu sitio sigue funcionando en un navegador.
const b = window.WebToApk || null;
// Ask once (Android 13+):
b?.requestNotificationPermission();
// Tier 1 — instant (app open):
b?.showNotification('Saved', 'Your note was saved', '', 'note');
// Tier 2 — scheduled reminder in 1 hour:
b?.scheduleNotification(
'water-1',
'Drink water',
'Time for a glass of water',
String(Date.now() + 60*60*1000),
'daily' // none | minutely | hourly | daily | weekly
);
b?.cancelNotification('water-1');
b?.cancelAllNotifications();
const pending = JSON.parse(b?.getScheduledNotifications() || '[]');4Deja que la IA lo conecte por ti#
En AI App Studio, solo describe lo que quieres, por ejemplo: 'un recordatorio de agua que me avise cada 2 horas' o 'un seguimiento de medicación que me recuerde a las 8 a. m. todos los días'. Cuando tu solicitud menciona recordatorios, alarmas o notificaciones, AppMint enseña automáticamente a la IA sobre este puente para que la app generada lo use correctamente (con una alternativa elegante cuando no esté disponible).
5Tu propio sonido en lugar del predeterminado de Android#
Pon un archivo de audio en tu paquete web (mp3, wav, ogg, m4a, flac u opus) e indica su ruta como sonido. Funciona igual en una notificación instantánea y en un recordatorio que se dispara días después con la app cerrada.
El archivo se copia a su sitio al programar, así que un nombre de archivo incorrecto devuelve false de inmediato en lugar de convertirse en el sonido predeterminado a las 7 a. m.
Una regla de Android que conviene conocer: el sonido de un canal de notificaciones se fija cuando se crea el canal, así que AppMint crea un canal distinto por cada sonido. Por eso, cambiar un sonido restablece los ajustes propios de ese canal en la pantalla de notificaciones de Android: es inevitable y es el comportamiento honesto.
const b = window.WebToApk || null;
// Instant, with your sound:
b?.notify(JSON.stringify({
title: 'Order confirmed',
body: 'Arriving Tuesday',
sound: '/audio/chime.mp3' // a file in YOUR bundle
}));
// Check a sound before you save it in a settings screen:
const ok = b?.prepareNotificationSound('/audio/chime.mp3');
// 'silent' for no sound at all; leave it out for the Android default.6Recordatorios con sonido, imágenes y botones#
scheduleNotificationEx() acepta todo lo que acepta notify(), más cuándo dispararla. Úsala en lugar de la antigua scheduleNotification() de cinco argumentos cuando quieras algo más que un título y un cuerpo.
const b = window.WebToApk || null;
b?.scheduleNotificationEx('dose-1', JSON.stringify({
at: Date.now() + 60*60*1000, // epoch millis
repeat: 'daily', // none|minutely|hourly|daily|weekly
title: 'Time for your dose',
body: 'Vitamin D — 1 tablet',
sound: '/audio/chime.mp3',
actions: [{ id: 'taken', label: 'Taken' }]
}));
// Returns false if the sound file does not exist — check it.7Abrir la propia app a una hora fijada#
Añade openApp: true y el recordatorio se convierte en una alerta a pantalla completa: en un teléfono bloqueado la app se abre sobre la pantalla de bloqueo; en uno desbloqueado aparece como un aviso emergente.
Esto es todo lo que Android permite. Una app no puede iniciarse sola en segundo plano sin avisar (está bloqueado desde Android 10), así que cualquier página que prometa 'la app se abre sola a las 7 a. m.' tiene que pasar por esto. En Android 14+ el usuario concede la alerta por app; consulta canOpenAppAtTime() y envíalo a la pantalla de ajustes si responde denied.
Cuando la app se abre de esta forma, tu página recibe un evento appmint:reminder, así que puede ejecutar el trabajo que no pudo hacer mientras estaba cerrada.
const b = window.WebToApk || null;
if (b?.canOpenAppAtTime() === 'denied') b?.requestOpenAppPermission();
b?.scheduleNotificationEx('standup', JSON.stringify({
at: tomorrowAt9am, repeat: 'daily',
title: 'Stand-up', body: 'Daily sync starts now',
sound: '/audio/alarm.mp3',
openApp: true
}));
window.addEventListener('appmint:reminder', e => {
// e.detail = { id: 'standup', overLockScreen: true }
showReminderScreen(e.detail.id);
});8Fiabilidad en dispositivos reales#
Los recordatorios programados son tan fiables como Android permite:
- En Android 12+, la precisión exacta necesita SCHEDULE_EXACT_ALARM. Si está desactivado para tu app, el recordatorio se arma en una ventana de 10 minutos (más tarde mientras el teléfono duerme), y la app se lo explica una vez al usuario. Consulta getAlarmPrecision(), que responde 'exact' o 'inexact', y llama a requestExactAlarms() para llevar al usuario al ajuste. Una app de despertador o calendario puede marcar "My app is an alarm clock or calendar app" en el asistente: entonces las alarmas exactas están siempre activas (Google Play exige la declaración de Alarma exacta en Play Console).
- Algunos teléfonos (Xiaomi, Samsung, Oppo, etc.) retienen o detienen las alarmas en segundo plano para ahorrar batería. La app lo explica una vez (con la ruta de Límites de uso en segundo plano de Samsung) y abre la lista de optimización de batería.
- Los recordatorios se reprograman automáticamente después de un reinicio o de una actualización de la app.
9Recupera a los usuarios que desactivaron las notificaciones#
Muchas personas tocan 'No permitir' en el aviso de notificaciones de Android 13, o lo omiten, y Android muestra ese aviso solo un número limitado de veces. Después, solo los ajustes de notificaciones de la app pueden volver a activarlas.
AppMint.enableNotifications() hace lo correcto desde un botón que el usuario tocó: el aviso de permiso mientras Android aún pueda mostrarlo y, si no, los ajustes de notificaciones de la app, y te informa del nuevo estado cuando el usuario vuelve. getNotificationState() responde 'granted', 'prompt' (aún se puede preguntar), 'blocked' (solo los Ajustes pueden arreglarlo) o 'unavailable' (la compilación no tiene notificaciones). Muestra tu banner solo para 'prompt' y 'blocked', y nunca preguntes al iniciar.
Un botón de notificación push o de mensaje dentro de la app con el enlace appmint://notifications/enable hace lo mismo sin ningún código en la página.
const A = window.AppMint;
if (A?.enableNotifications) {
const state = await A.getNotificationState();
// 'granted' | 'prompt' | 'blocked' | 'unavailable'
banner.hidden = !(state === 'prompt' || state === 'blocked');
turnOnButton.onclick = async () => {
const r = await A.enableNotifications();
// r = { state, changed, openedSettings }
banner.hidden = r.state === 'granted';
};
}
// Just the settings screen:
A?.openNotificationSettings?.();