# Local Notifications & Reminders

> Schedule reminders on the device - no server, no internet, exact alarms included.

- **Applies to:** AppMint and Appwright
- **Source:** the Integration Guide shipped inside the app; this page is generated from it.
- **HTML:** https://freewebtoapk.com/docs/local-notifications-and-reminders
- **Using AppMint:** wherever the text below says "Appwright", read "AppMint". The two builders share this feature and only the name changes. Steps where the instructions genuinely differ are given separately and labelled.

Show instant notifications, or schedule reminders that fire even when the app is closed - on-device, no server

### 1. What this adds

Your app can show Android notifications from its own code - two levels:

- Instant (Tier 1): a notification that appears right now, while the app is open. Good for 'download complete', 'timer finished', etc.

- Scheduled reminders (Tier 2): a notification that fires at a future time even when the app is CLOSED, and survives a reboot. This is what reminder, habit, alarm and medication apps need.

These are 100% on-device and offline - no server, no OneSignal account. (OneSignal push is a separate feature for messages YOU send from a server.)

### 2. Turn it on in the build wizard

In Step 3 (Permissions), tick:

- 🔔 Notifications - lets the app post notifications (adds POST_NOTIFICATIONS).
- ⏰ Reminders - adds scheduled notifications that fire when the app is closed (adds the exact-alarm + reschedule-on-boot plumbing). Ticking Reminders auto-enables Notifications.

Leave both off for apps that don't need notifications - nothing extra is added to your APK.

### 3. Call the bridge from your web code

Appwright exposes a JavaScript bridge at window.WebToApk. Always feature-detect it first - it only exists inside the installed app, so your site still works in a browser.

```
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() || '[]');
```

### 4. Let the AI wire it for you

In AI App Studio, just describe what you want - e.g. 'a water reminder that pings me every 2 hours' or 'a medication tracker that reminds me at 8am daily'. When your request mentions reminders/alarms/notifications, Appwright automatically teaches the AI about this bridge so the generated app uses it correctly (with a graceful fallback when it isn't available).

### 5. Your own sound instead of the Android default

Put an audio file in your web bundle (mp3, wav, ogg, m4a, flac or opus) and name its path as the sound. It works the same on an instant notification and on a reminder that fires days later with the app closed.

The file is copied into place when you schedule, so a wrong file name comes back as false straight away instead of turning into the default sound at 7am.

One Android rule worth knowing: a notification channel's sound is fixed when the channel is created, so Appwright makes a separate channel per sound. Changing a sound therefore resets that channel's own settings in Android's notification screen - unavoidable, and the honest behaviour.

```
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.
```

### 6. Reminders with sound, pictures and buttons

scheduleNotificationEx() takes everything notify() takes, plus when to fire it. Use it instead of the older five-argument scheduleNotification() when you want anything more than a title and a body.

```
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.
```

### 7. Opening the app itself at a set time

Add openApp: true and the reminder becomes a full-screen alert: on a locked phone the app opens over the lock screen, on an unlocked one it appears as a heads-up banner.

This is the whole of what Android allows. An app cannot silently launch itself in the background - that has been blocked since Android 10 - so any page that promises 'the app just opens at 7am' has to go through this. On Android 14+ the user grants the alert per app; check canOpenAppAtTime() and send them to the settings screen if it says denied.

When the app opens this way your page gets an appmint:reminder event, so it can run the work it could not do while closed.

```
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);
});
```

### 8. Reliability on real devices

Scheduled reminders are as reliable as Android allows:

- On Android 12+, exact timing needs SCHEDULE_EXACT_ALARM. If it is off for your app, the reminder is still armed but Doze may batch it by minutes. Ask getAlarmPrecision() - it answers 'exact' or 'inexact' - and call requestExactAlarms() to send the user to the setting rather than letting them think your app is late.
- Some aggressive phones (Xiaomi, Samsung, Oppo, etc.) kill background alarms to save battery. For critical reminders, ask users to disable battery optimization for your app.
- Reminders are re-armed automatically after a reboot or an app update.

