# Background Execution

Mob runs the BEAM on the device, but mobile operating systems still control
when a backgrounded app may execute. A GenServer cannot assume it will keep
running forever after the user leaves the app unless the app uses one of the
platform-approved background mechanisms.

## The default model: wake, handle, suspend

For most server-driven work, use push notifications:

1. The app registers with APNs or FCM via `MobNotify.register_push/1`.
   (`MobNotify` ships in the `mob_notify` plugin — add the dep + activate in
   `mob.exs`; see the [Plugins guide](plugins.md). Delivery of
   `{:notification, notif}` and `{:push_token, ...}` messages is core
   behavior.)
2. The device token is sent to your server.
3. Your server sends a notification through `mob_push`.
4. The OS delivers or stores the notification.
5. When the notification is delivered to a foreground app, or tapped from the
   background or killed state, Mob sends `{:notification, notif}` to the screen.

This model is reliable because APNs and FCM are the OS-approved wakeup paths.
It is not the same as keeping an Erlang distribution connection or WebSocket
open indefinitely while the app is backgrounded.

See [Push Notifications](push_notifications.md) for token registration,
payloads, and notification tap handling.

For **silent** wakes (no visible notification — just "run this handler
in the background"), use the [`mob_wake`](https://hexdocs.pm/mob_wake)
plugin. It ships one identifier → MFA dispatch table with four
trigger sources: iOS `BGTaskScheduler`, iOS silent APNs (paired with
`mob_push` on the server), Android `WorkManager`, and Android FCM data
messages. Verified end-to-end on both platforms in the foreground and
backgrounded states; force-quit drop is intentional platform behaviour
on both OSes.

## iOS

iOS suspends normal apps shortly after they enter the background. When that
happens, BEAM schedulers stop running with the rest of the process. Timers,
GenServers, sockets, and distribution connections do not continue like they
would on a server.

iOS can wake an app through sanctioned mechanisms such as visible notification
taps, silent pushes, background fetch, `BGTaskScheduler`, location, Bluetooth,
audio, and other entitlement-backed modes. These wakeups are constrained by the
OS and usually provide a short execution window rather than an always-on
process.

The opt-in `mob_background` plugin (`{:mob_background, "~> 0.1"}` + `config :mob,
:plugins, [:mob_background]`) exposes `MobBackground.keep_alive/0` for apps that
legitimately use audio. It keeps iOS execution alive through the audio
background mode. Do not
use this just to hide a server listener in the background; Apple expects the
declared background mode to match a user-visible app capability.

## Android

Android permits true long-running background work through a foreground service.
Mob maps `MobBackground.keep_alive/0` to a foreground service on Android.
Foreground services must show a persistent notification; Android intentionally
makes always-running background work visible to the user.

Without a foreground service, recent Android versions restrict background
execution heavily. Use FCM for server-initiated wakeups and WorkManager-style
patterns for deferred work.

## Choosing a pattern

| Goal | Recommended path |
|---|---|
| Show or route a server event to a screen | Push notification via APNs / FCM ([`mob_notify`](https://hexdocs.pm/mob_notify) + [`mob_push`](https://hexdocs.pm/mob_push)) |
| Run a specific handler when a silent push arrives | Silent push via [`mob_wake`](https://hexdocs.pm/mob_wake) (`:push` trigger) + `MobWake.wake_payload/2` |
| Run a handler on the OS's own opportunistic schedule | iOS `BGTaskScheduler` / Android `WorkManager` via [`mob_wake`](https://hexdocs.pm/mob_wake) (`:refresh` or `:processing` trigger) |
| Refresh local state after a user taps a notification | Handle `{:notification, notif}` and fetch from your server |
| Run continuously while visible | Normal Mob screen / supervision tree |
| Run continuously in Android background | `MobBackground.keep_alive/0` foreground service |
| Run continuously in iOS background | Only for legitimate background modes such as audio, location, or Bluetooth |
| Hold a hidden always-on iOS socket | Not a supported mobile OS model |

## Practical design

Design background flows as resumable work:

- Persist enough state locally with `Mob.State` or SQLite to resume after
  suspension or cold start.
- Treat network connections as disposable; reconnect after the app foregrounds
  or receives a notification.
- Make notification handlers idempotent, because a user may tap an old
  notification after the app has already synced.
- Use `MobBackground.keep_alive/0` only when your app has a real foreground
  service or background audio/location/Bluetooth reason.

For the platform API details, see the `mob_background` plugin and
[Device Capabilities](device_capabilities.md).
