Packages
Background execution keep-alive (iOS silent audio session / Android foreground service) for Mob apps
Current section
Files
Jump to
Current section
Files
mob_background
README.md
README.md
# mob_background
Background execution keep-alive for [Mob](https://github.com/GenericJam/mob)
apps — keep the BEAM node running when the screen locks or the app is
backgrounded.
- **iOS:** a silent `AVAudioEngine` session (`MixWithOthers`) so the OS keeps
the app alive. The user hears nothing; any music already playing is
undisturbed.
- **Android:** a `dataSync` foreground service with a low-priority persistent
notification. The OS won't kill it under memory pressure or when the screen
locks.
## Usage
```elixir
# Keep the app alive when the screen locks (e.g. in mount/2):
MobBackground.keep_alive()
# Allow suspension again when no longer needed:
MobBackground.stop()
```
`keep_alive/0` is idempotent — safe to call multiple times. `status/0` reports,
without changing anything, whether keep-alive can work in this host and whether
it's on.
Run `mix mob.selftest` from a host app to check on a device that the native
side is linked and wired up (`MobBackground.SelfTest`, a read-only
`background_status/0` call that never starts the keep-alive).
## Install
```elixir
# mix.exs
{:mob_background, "~> 0.1"}
# mob.exs
config :mob, :plugins, [:mob_background]
config :mob, :trusted_plugins, %{mob_background: "ed25519:<fingerprint>"}
```
`mix mob.plugin.trust mob_background` records the fingerprint, then
`mix mob.deploy --native`.
## Host requirements (the native build warns about these)
On Android the build adds everything when the plugin is activated: the
`FOREGROUND_SERVICE` permissions, the `BeamForegroundService` class (copied
into `io/mob/background/` next to the bridge) and its `<service
android:foregroundServiceType="dataSync">` declaration. If you copied
`BeamForegroundService.kt` into your app for plugin 0.1.x somewhere other
than `io/mob/background/`, delete that copy.
The plugin deliberately doesn't add this one to your `Info.plist` (Apple
rejects the mode in apps with no audio feature, so it's the app author's
call); it prints as a warning on every `mix mob.deploy --native` of the host:
- **iOS `UIBackgroundModes`.** `Info.plist` must declare the `audio` mode (the
keep-alive uses a silent audio session). `mix mob.new` adds this; for Xcode
projects use *Signing & Capabilities → Background Modes → Audio, AirPlay, and
Picture in Picture*. Apple rejects this mode for apps with no audio feature —
only use this plugin in apps that legitimately use audio.
## Notes
- **Coexistence with Mob.Audio:** playback mixes transparently (both use
`MixWithOthers`); recording temporarily takes the audio session, and the
keep-alive engine restarts automatically when recording (or a phone call)
ends.
- **Android notification:** Android requires every foreground service to post a
visible notification ("Running in background", `IMPORTANCE_LOW`, no sound).
There is no API to hide it.
- **Android 15 time limit:** with `targetSdk` 35+, Android allows a `dataSync`
foreground service at most 6 hours per 24 hours while the app is in the
background. When the limit is hit the service stops itself (logged under the
`MobBackground` tag) and the notification disappears; the BEAM is not told.
Call `keep_alive/0` again once the app returns to the foreground.
## License
MIT.