Engineers App
Troubleshooting
When pages don't land — the diagnostic order, from most-likely to least-likely. 80% of the time it's battery optimization.
Run through these in order
No page arrived at all#
1. Battery optimization (the #1 culprit)#
Android phones — especially Xiaomi (MIUI), OnePlus, Realme, Oppo, Vivo — aggressively kill background processes to save battery. The app's FCM listener is in that crosshair. If you have one of these phones and pages don't arrive, this is almost certainly why.
- Open Android Settings → Apps → Reliable.
- Tap Battery → set to Unrestricted (sometimes called "Don't optimize", "No restrictions").
- On Xiaomi / Realme / Oppo: also find Autostart and toggle it on for Reliable. This is OEM-specific and the most-missed step.
- Open recents view, find the Reliable app card, and pull down to lock it (most OEMs support this) so the system doesn't kill it on low memory.
Why this is non-negotiable
2. Notification permissions denied#
Android 13+ requires explicit grant of POST_NOTIFICATIONS. Android 14+ additionally requires USE_FULL_SCREEN_INTENT via Settings.
- Settings → Apps → Reliable → Notifications → ensure it's ON.
- Check both channels are enabled:
reliable-page-v2andreliable-info-v1. - For full-screen intent on Android 14+: Settings → Apps → Reliable → Display over other apps → allow.
If the channels are missing entirely, you may have force-stopped the app before it had a chance to create them. Just open the app once with a logged-in user — channels register on init.
3. FCM token not registered with backend#
The app fetches an FCM token on login and POSTs it to the backend. If this call failed (network blip, JWT expired, etc.), the engineer is invisible to the paging engine — the dashboard can still see the engineer, but FCM won't reach them.
- Sign out, then sign back in — registration runs again on login.
- If you have backend access, check the
engineer_devicestable for a row with yourengineer_id. - In Flutter dev logs, look for
[fcm] registered with backendafter login. If you see[fcm] register failed, that's the bug — capture the status code and pass to your admin.
4. Verify with a manual test page#
Ask your admin to open the dashboard → On-Call → click the phone icon next to your name → send a page. This bypasses the schedule + paging engine entirely; if even a manual page doesn't arrive, the issue is FCM-side (one of the first three above), not the paging logic.
Alarm doesn't sound on silent mode#
The current build does not bypass silent / Do Not Disturb. The notification channel is set to importance.max, which is the loudest the OS gives you without a special "Critical Alerts" entitlement (iOS) or device-admin permission (Android).
If your team wants alarms to bypass DND, ask your admin to:
- Enable per-channel DND override in Settings → Apps → Reliable → Notifications → Reliable Page → Override Do Not Disturb (where supported).
- Add Reliable to system-level DND exceptions (Settings → Sound → Do Not Disturb → Apps).
- Plan for a future build that adds a device-admin-level audio override — not implemented in v1.
Full-screen intent doesn't trigger#
Two requirements that aren't always granted by default:
- The app has
android:showWhenLocked+android:turnScreenOnon its main activity (built-in to the APK). - Android 14+ users must grant USE_FULL_SCREEN_INTENT from Settings — the app prompts for it on first launch, but if you skipped, manually grant it under Settings → Apps → Reliable → Special access.
Severity-change banner is too loud#
Severity-change banners use the reliable-info-v1 channel, which is importance.default. If they're behaving like pages (sound, full-screen), you may have a leftover misconfigured channel from an older app build. Uninstall + reinstall the app — channels are immutable after creation, so a fresh install is the only way to update them.
Reading the logs#
When debugging, watch the Flutter dev console for these lines:
[fcm] token: ...— token fetched successfully at app boot.[fcm] registered with backend— token POSTed to/mobile/engineers/:id/device.[fcm][fg] ... type=...— FCM arrived in the foreground (good).[fcm][bg] received ...— FCM arrived in the background (also good).[notif] channels ensured— both notification channels were registered at app boot.[notif] POST_NOTIFICATIONS granted = true/false— whether the permission was granted.[notif] show failed: ...— the local notification render failed; the rest of the line tells you why.
Still stuck after all of the above?
flutter run output starting from the test page, and the dashboard logs around the paging time. With those three, your admin can usually narrow it to a one-line fix.