Mob.Notification (mob v0.9.9)

Copy Markdown View Source

The {:notification, notification} message a screen receives when a notification arrives or is tapped, on both platforms.

def handle_info({:notification, %{presentation: :tap, data: data}}, socket) do
  {:noreply, Mob.Socket.push_screen(socket, MyApp.ThreadScreen, data)}
end

# Arrived while the app was open; the OS still shows its banner.
def handle_info({:notification, %{presentation: :foreground}}, socket) do
  {:noreply, socket}
end

Fields

  • :presentation — :foreground when the notification arrived while the app was in the foreground, :tap when the user opened it from the banner or notification centre, including the tap that launched the app from a killed state.
  • :action — for a :tap, "default" for a tap on the notification itself. An app that registers its own notification categories also sees "dismiss" and its own action identifiers here (iOS). nil for :foreground.
  • :source — :push for a remote notification, :local for one scheduled on the device.
  • :id — the notification's identifier (the id: given to MobNotify.schedule/2), or nil.
  • :title, :body — the displayed text, or nil.
  • :data — the custom payload: data: from MobNotify.schedule/2, or the custom keys of a push payload (iOS's aps dictionary is not included). Top-level keys are atoms; nested values are as JSON decodes them (maps with string keys, lists, numbers, booleans, nil).

Where it is delivered

To the process that registered for notifications through mob_notify (MobNotify.register_push/1, or MobNotify.schedule/2 on iOS) while it is alive. Otherwise to the screen currently showing. A tap that launches the app arrives at the root screen once it has mounted, exactly once.

Each native layer serialises the notification to one JSON envelope and hands it to the :mob_screen router, which decodes it with decode/1. That keeps the shape in one place rather than one per platform; see decisions/2026-10-01-notification-delivery-envelope.md.

Summary

Functions

Decodes the JSON envelope native code hands to the router.

Types

t()

@type t() :: %{
  id: String.t() | nil,
  title: String.t() | nil,
  body: String.t() | nil,
  data: map(),
  source: :local | :push,
  presentation: :foreground | :tap,
  action: String.t() | nil
}

Functions

decode(json)

@spec decode(binary()) ::
  {:ok, t()} | {:error, :invalid_json | :not_an_object | :data_key_too_long}

Decodes the JSON envelope native code hands to the router.

presentation defaults to "tap" when absent. Most callers that predate the field send taps: app-owned Android MainActivity code and callers of the iOS mob_set_launch_notification_json/1 hook. The exception is the app-owned MobFirebaseService that mob_new 0.1.45–0.4.10 generated, which hands over foreground pushes without it; such an app must add "presentation": "foreground" (see the push notifications guide).