The {:link, link} message a screen receives when the app is opened by a
URL: a link tapped in another app, a QR code read by the camera or a scanner
app, adb shell am start -a android.intent.action.VIEW -d 'myapp://…',
xcrun simctl openurl booted 'myapp://…'.
def handle_info({:link, %{url: url}}, socket) do
case URI.parse(url) do
%URI{scheme: "myapp", host: "thread", query: query} when is_binary(query) ->
params = URI.decode_query(query)
{:noreply, Mob.Socket.push_screen(socket, MyApp.ThreadScreen, params)}
_ ->
{:noreply, socket}
end
endAny app on the device can open one, with anything in it. Parse it and check what it asks for before acting on it.
Fields
:url— the URL as the platform handed it over.:source—:launchwhen it opened the app, or arrived while the app was starting: it was held until the root screen had mounted.:runningwhen the app was already running.
Where it is delivered
To the process registered with register/1 while it is alive, otherwise to
the screen currently showing. A link that launches the app arrives once the
root screen has mounted, exactly once. A screen that defines its own
handle_info/2 clauses needs one for {:link, _} (or a catch-all) to
receive links without crashing.
Which links open the app
A custom scheme is declared at build time: config :mob_dev, url_schemes: ["myapp"] in mob.exs makes the native build (mob_dev 0.7.12 or later) add
an intent filter to the Android main activity and a CFBundleURLTypes entry
to the iOS bundle. A change needs a native rebuild. On Android the main
activity must be android:launchMode="singleTask", or a link opened from
another app's task starts a second activity there; the build refuses
url_schemes without it.
Native code hands each URL to mob with mob_deliver_link(const char *url)
(mob_beam.h, both platforms): the generated Android MainActivity
forwards ACTION_VIEW intents through MobBridge.nativeDeliverLink, and the
iOS SceneDelegate forwards its URL contexts. An app whose native files were
generated before mob_new 0.6.4 adds those calls itself; see "Deep links" in
the device capabilities guide. Like notifications, every link passes through
the :mob_screen router, which keeps the one that launched the app until
the root screen has mounted; see
decisions/2026-10-03-deep-link-delivery.md.
Summary
Functions
Sends links to pid rather than to the screen showing, while pid is
alive. A later call replaces the registration.
The registered pid, alive or not, or nil.
Drops the registration: links go to the screen showing again.
Types
@type t() :: %{url: String.t(), source: :launch | :running}
Functions
@spec register(pid()) :: :ok
Sends links to pid rather than to the screen showing, while pid is
alive. A later call replaces the registration.
It can be called before the root screen starts (in the app's on_start/0,
say), so the link that launched the app goes to pid too.
@spec registered() :: pid() | nil
The registered pid, alive or not, or nil.
@spec unregister() :: :ok
Drops the registration: links go to the screen showing again.