Packages
mob
0.6.5
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.26
0.6.25
0.6.24
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.2
0.6.1
0.6.0
0.5.18
0.5.17
0.5.16
0.5.15
0.5.14
0.5.11
0.5.10
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.0
BEAM-on-device mobile framework for Elixir
Current section
Files
Jump to
Current section
Files
lib/mob/notify.ex
defmodule Mob.Notify do
@moduledoc """
Local and push notifications.
Requires `:notifications` permission (request via `Mob.Permissions.request/2`).
No `Info.plist` key needed on iOS. Android 13+ (API 33) requires
`POST_NOTIFICATIONS` in `AndroidManifest.xml`; older Android
versions are user-controlled via system settings. The default
`mix mob.new` template ships `POST_NOTIFICATIONS`. See the
[permissions guide](permissions.html) for the cross-platform table.
All notifications arrive via `handle_info` regardless of app state (foreground,
background, or relaunched after being killed). No special `mount/3` handling needed.
## Local notifications
Mob.Notify.schedule(socket,
id: "reminder_1",
title: "Time to check in",
body: "Open the app to see today's updates",
at: ~U[2026-04-16 09:00:00Z], # or delay_seconds: 60
data: %{screen: "reminders"}
)
# Cancel a pending notification
Mob.Notify.cancel(socket, "reminder_1")
def handle_info({:notification, %{id: id, data: data, source: :local}}, socket), do: ...
## Push notifications (requires `mob_push` package on your server)
# Call once after :notifications permission granted
Mob.Notify.register_push(socket)
def handle_info({:push_token, :ios, token}, socket), do: ...
def handle_info({:push_token, :android, token}, socket), do: ...
def handle_info({:notification, %{title: t, body: b, data: d, source: :push}}, socket), do: ...
iOS: `UNUserNotificationCenter`. Android: `NotificationManager` + `AlarmManager` + FCM.
"""
@doc """
Schedule a local notification.
Options:
- `id:` (required) — string identifier, used to cancel the notification
- `title:` (required) — notification title
- `body:` (required) — notification body text
- `at: %DateTime{}` — absolute trigger time (UTC)
- `delay_seconds: integer` — trigger after N seconds (alternative to `at:`)
- `data: %{}` — arbitrary map passed back in the `handle_info` payload
"""
@spec schedule(Mob.Socket.t(), keyword()) :: Mob.Socket.t()
def schedule(socket, opts) do
id = Keyword.fetch!(opts, :id)
title = Keyword.fetch!(opts, :title)
body = Keyword.fetch!(opts, :body)
data = Keyword.get(opts, :data, %{})
trigger_at =
case opts[:at] do
%DateTime{} = dt -> DateTime.to_unix(dt)
nil -> DateTime.to_unix(DateTime.utc_now()) + (opts[:delay_seconds] || 0)
end
# Convert data map keys to strings for JSON serialisation
data_str = Map.new(data, fn {k, v} -> {to_string(k), v} end)
opts_json =
:json.encode(%{
"id" => id,
"title" => title,
"body" => body,
"trigger_at" => trigger_at,
"data" => data_str
})
:mob_nif.notify_schedule(opts_json)
socket
end
@doc """
Cancel a pending local notification by its id.
Has no effect if the notification has already been delivered.
"""
@spec cancel(Mob.Socket.t(), String.t()) :: Mob.Socket.t()
def cancel(socket, id) do
:mob_nif.notify_cancel(id)
socket
end
@doc """
Register this device for push notifications.
The device token arrives as `{:push_token, platform, token_string}` where
`platform` is `:ios` or `:android`.
Send this token to your server and use the `mob_push` library to send
notifications to it.
"""
@spec register_push(Mob.Socket.t()) :: Mob.Socket.t()
def register_push(socket) do
:mob_nif.notify_register_push()
socket
end
end