Notifications & FCM Token
Bridges for checking/requesting push notification permission and retrieving the Firebase Cloud Messaging (FCM) token.
Android
Bridge object: AndroidNotification
Methods
Method | Return | Description |
|---|
requestNotificationPermission()
| void
| Prompts the user for notification permission (Android 13+) |
getNotificationPermissionStatus()
| string (JSON)
| Returns current notification permission/settings status |
openNotificationSettings()
| void
| Opens the app's notification settings page |
setNotifyOnStartup(enabled)
| void
| Persists whether to request notification on app start |
getNotifyOnStartup()
| boolean
| Returns the persisted notify-on-startup setting (default false) |
getFirebaseToken()
| string
| Returns the FCM token synchronously (may be empty) |
requestFirebaseToken()
| void
| Requests a fresh token; result dispatched via event |
sendLocalNotification(payload)
| void
| Schedules/displays a local notification from website payload |
createNotificationChannel(payloadJson)
| string (JSON)
| Creates/updates a notification channel (Android 8+) |
listNotificationChannels()
| string (JSON)
| Lists app notification channels |
deleteNotificationChannel(channelId)
| string (JSON)
| Deletes a channel by ID (except protected default channel) |
Events
Listen for these CustomEvents on window:
Event name | event.detail shape
| Description |
|---|
mobiweb:notificationPermission
| { granted: boolean }
| Result of permission request |
mobiweb:fcmToken
| { token: string, oldtoken?: string }
| New or refreshed FCM token |
mobiweb:cookiesCleared
| { success: boolean }
| Result of cookie clearing |
Example
// Check current status
const status = JSON.parse(AndroidNotification.getNotificationPermissionStatus());
console.log('Notifications enabled:', status.notificationsEnabled);
// Request permission
AndroidNotification.requestNotificationPermission();
// Listen for result
window.addEventListener('mobiweb:notificationPermission', (e) => {
console.log('Granted:', e.detail.granted);
});
// Get token synchronously
const token = AndroidNotification.getFirebaseToken();
// Request token, listen for event
AndroidNotification.requestFirebaseToken();
window.addEventListener('mobiweb:fcmToken', (e) => {
console.log('FCM token:', e.detail.token);
});
iOS
Bridge object: AppleNotification (injected shim)
The iOS shim exposes the same intent as Android but communicates via WKScriptMessageHandler.
Methods
Method | Return | Description |
|---|
AppleNotification.requestNotificationPermission()
| void
| Prompts the user for notification permission (alert, badge, sound) |
AppleNotification.requestCriticalAlertsPermission()
| void
| Prompts the user for the Critical Alerts permission. Always available on the shim; result is reported asynchronously via mobiweb:appleCriticalAlertsPermissionResult. If the build's provisioning profile lacks the com.apple.developer.usernotifications.critical-alerts entitlement, the event detail will be { granted: false, criticalAlertSetting: 'notSupported' }. |
AppleNotification.getNotificationPermissionStatus()
| Promise<object>
| Resolves current notification permission/settings status, including Critical Alerts status |
AppleNotification.requestToken()
| void
| Requests an FCM token |
AppleNotification.getToken()
| string
| Returns the cached FCM token synchronously |
AppleNotification.isTokenValid()
| boolean
| Returns whether the cached token is valid |
AppleNotification.sendLocalNotification(payload)
| void
| Schedules/displays a local notification from website payload |
AppleNotification.createChannel(payload)
| void
| Creates/updates iOS channel mapping (UNNotificationCategory) |
AppleNotification.listChannels()
| void
| Lists persisted iOS channel mappings via event |
AppleNotification.deleteChannel(channelId)
| void
| Deletes iOS channel mapping via event |
Events
Event name | event.detail shape
| Description |
|---|
mobiweb:appleNotificationPermissionResult
| { granted: boolean }
| Result of standard notification permission request |
mobiweb:appleCriticalAlertsPermissionResult
| { granted: boolean, criticalAlertSetting?: 'enabled' \| 'disabled' \| 'notSupported' \| 'unknown' }
| Result of Critical Alerts permission request. granted: false + criticalAlertSetting: 'notSupported' indicates the entitlement is missing from the installed build. granted: false with criticalAlertSetting: 'disabled' means the user declined. |
mobiweb:appleNotificationPermissionStatus
| { notificationsEnabled: boolean, authorizationStatus: string, alertSetting: string, badgeSetting: string, soundSetting: string, criticalAlertsEnabled: boolean, criticalAlertSetting: string }
| Current notification settings status. Includes requestId when triggered by getNotificationPermissionStatus(). |
mobiweb:appleNotificationToken
| { token: string, oldtoken?: string }
| New or refreshed FCM/APNs token |
Example
// Check current status (iOS)
const status = await AppleNotification.getNotificationPermissionStatus();
console.log('Notifications enabled:', status.notificationsEnabled);
console.log('Critical alerts enabled:', status.criticalAlertsEnabled);
// Request permission (iOS)
AppleNotification.requestNotificationPermission();
window.addEventListener('mobiweb:appleNotificationPermissionResult', (e) => {
console.log('Granted:', e.detail.granted);
});
// Request Critical Alerts — always available; inspect the event detail for outcome
window.addEventListener('mobiweb:appleCriticalAlertsPermissionResult', (e) => {
const { granted, criticalAlertSetting } = e.detail || {};
if (granted) {
console.log('Critical alerts granted');
} else if (criticalAlertSetting === 'notSupported') {
console.warn('Critical alerts entitlement missing from this build');
} else {
console.log('Critical alerts denied:', criticalAlertSetting);
}
}, { once: true });
AppleNotification.requestCriticalAlertsPermission();
// Get token synchronously
const token = AppleNotification.getToken();
// Request token via event
AppleNotification.requestToken();
window.addEventListener('mobiweb:appleNotificationToken', (e) => {
console.log('Token:', e.detail.token);
});
Local Notification Payload
sendLocalNotification(payload) accepts notification configuration at the root level (same keys currently used by push data payloads) plus optional custom data and trigger settings.
{
title: 'Payment Reminder',
body: 'Tap to complete your payment',
// Existing notification config keys still work (sound, silent, badge, color, group, etc.)
sound: 'default',
data: {
url: 'https://example.com/pay/123',
orderId: '123'
},
trigger: {
// 'immediate' | 'delay' | 'time' | 'exit' | 'home'
type: 'delay',
delayMs: 10_000
// delayMs also works with 'home' and 'exit'
// For specific time use: at: Date.now() + 60_000
}
}
Trigger options:
Trigger | Payload example |
|---|
Immediate | { trigger: { type: 'immediate' } } or omit trigger
|
Delay | { trigger: { type: 'delay', delayMs: 5000 } }
|
Specific time | { trigger: { type: 'time', at: Date.now() + 60000 } }
|
On home screen | { trigger: { type: 'home' } }
|
On home screen + delay | { trigger: { type: 'home', delayMs: 5000 } }
|
On app exit | { trigger: { type: 'exit' } }
|
On app exit + delay | { trigger: { type: 'exit', delayMs: 5000 } }
|
Behavior notes:
Permission Status Shape
Android getNotificationPermissionStatus() returns a JSON string:
{
"platform": "android",
"notificationsEnabled": true,
"runtimePermissionGranted": true,
"appNotificationsEnabled": true
}
On Android 12 and older, runtimePermissionGranted is always true because the POST_NOTIFICATIONS runtime permission does not exist. notificationsEnabled is true only when the runtime permission is granted and app notifications are enabled in system settings.
iOS getNotificationPermissionStatus() resolves to the same object also dispatched through mobiweb:appleNotificationPermissionStatus:
{
"platform": "ios",
"notificationsEnabled": true,
"authorizationStatus": "authorized",
"alertSetting": "enabled",
"badgeSetting": "enabled",
"soundSetting": "enabled",
"criticalAlertsEnabled": false,
"criticalAlertSetting": "notSupported"
}
notificationsEnabled is true for authorized, provisional, or ephemeral authorization. Critical Alerts require criticalAlertsEnabled: true; criticalAlertSetting: "notSupported" means the installed build lacks the Apple-approved entitlement/provisioning support.
Channel Management
For complete channel-management payloads, response/event schemas, and platform compatibility notes, see Notification Channel Management.
Publishing to Channels via FCM Proxy
Once channels are created, your FCM proxy backend can target them by including channel_id in the notification's data payload:
{
"title": "Order Shipped",
"subtitle": "Your order has shipped",
"token": "...",
"data": {
"channel_id": "order_updates",
"url": "https://app.com/orders/123"
}
}
The device automatically routes the notification to the specified channel, inheriting its sound, vibration, importance, and other settings. See Publishing via FCM Proxy for full details and examples.
function requestNotificationPermission() {
if (typeof AndroidNotification !== 'undefined') {
AndroidNotification.requestNotificationPermission();
window.addEventListener('mobiweb:notificationPermission', (e) => {
console.log('Android granted:', e.detail.granted);
}, { once: true });
} else if (typeof AppleNotification !== 'undefined') {
AppleNotification.requestNotificationPermission();
window.addEventListener('mobiweb:appleNotificationPermissionResult', (e) => {
console.log('iOS granted:', e.detail.granted);
}, { once: true });
}
}
function sendLocalNotification(payload) {
if (typeof AndroidNotification !== 'undefined') {
AndroidNotification.sendLocalNotification(payload);
} else if (typeof AppleNotification !== 'undefined') {
AppleNotification.sendLocalNotification(payload);
}
}
function openNotificationSettings() {
if (typeof AndroidNotification !== 'undefined' && typeof AndroidNotification.openNotificationSettings === 'function') {
AndroidNotification.openNotificationSettings();
}
}
async function getNotificationPermissionStatus() {
if (typeof AndroidNotification !== 'undefined') {
return JSON.parse(AndroidNotification.getNotificationPermissionStatus());
}
if (typeof AppleNotification !== 'undefined') {
return AppleNotification.getNotificationPermissionStatus();
}
return null;
}
21 May 2026