On-device access to the activated plugins' tier-3/4 contributions.
Tiers 3 (multi-screen) and 4 (sub-app) are pure-Elixir and runtime-wired: the
host needs to know, while running, which screens / lifecycle hooks / settings /
notification handlers the activated plugins declared. mob_dev bakes that into
the host's priv/generated/mob_plugins.exs at build time (see
mix mob.regen_plugin_manifest); this module reads it once at boot and feeds
the data to the core wiring (Mob.App registers the screens, the lifecycle
dispatcher calls the hooks, the notification dispatch consults the handlers, and the
settings store namespaces by plugin).
When no tier-3/4 plugin is active (or the manifest hasn't been regenerated) the file is absent and every accessor returns the empty set — tiers 0-2 are unaffected.
Summary
Functions
Applies the default style's theme at boot (Mob.Theme.set/1 with the style
package's theme module). No default → no-op (neutral baseline / the host's
own use Mob.App, theme:). A broken theme module logs instead of failing
boot — the app renders baseline rather than not at all.
Boot-time entry point: load the host's manifest and register the activated
plugins' screens so they're navigable. Called from Mob.App.start/0.
Activated plugins' pure-Elixir composite components
(%{atom, expand: {M, F}}) — the manifest expand: ui_components form.
The configured :default_style name (or nil — neutral baseline).
Routes a notification payload to the first matching plugin handler.
Reads a plugin setting, falling back to the schema default when unset.
Caches an already-built manifest (used by load/1 and tests).
Activated plugins' lifecycle declarations.
Reads the host app's generated manifest and caches it in :persistent_term.
The cached manifest, or the empty set if nothing has been loaded.
Activated plugins' NIF module atoms. boot/1 loads each at startup so an iOS
plugin NIF's load callback fires eagerly (registering any permission handler
it owns) before a screen can request that permission.
Activated plugins' notification handlers, in dispatch order.
Writes a plugin setting after validating its value against the schema type.
Reads + evaluates the manifest for otp_app without caching. Returns the
empty set when the priv dir or file is absent, or the file is malformed (a
missing manifest must never crash boot).
Reads + evaluates a manifest from an explicit path (empty set on any failure).
Registers each manifest-declared composite expander into Mob.Composite.
Malformed entries are skipped (the build validator is where shape errors
surface; a stale hand-edited manifest must not crash boot).
Registers each manifest screen into Mob.Nav.Registry under an atom derived
from its default_route, so the host (or the plugin's own screens) can
navigate to it by route. The module is also directly navigable. The host
still chooses where to surface a plugin screen in its navigation/1
structure — registration only makes the destination resolvable.
Resolves a plugin://<plugin>/<file> image reference to its on-device bundle
path (assets/plugin/<plugin>/<file>), the convention native_build copies
plugin images to. The renderer calls this when an image src uses the
plugin:// scheme; a non-plugin URL returns :passthrough so normal image
handling continues. Returns :error for a malformed plugin:// reference.
Activated plugins' screen declarations (%{plugin, module, default_route}).
Activated plugins' settings declarations.
Resolves the screen a host pushes to let users edit a plugin's settings.
Starts the tier-4 plugin supervisor (runs each plugin's lifecycle.on_start,
starts its supervised children, and the lifecycle event dispatcher). Called
from Mob.App.start/0 after the host's own on_start/0. No-op when no plugin
declares a :lifecycle.
Activated token-only style packages (%{name, theme}), from MOB_STYLES.md's lane.
Functions
@spec apply_default_style() :: :ok
Applies the default style's theme at boot (Mob.Theme.set/1 with the style
package's theme module). No default → no-op (neutral baseline / the host's
own use Mob.App, theme:). A broken theme module logs instead of failing
boot — the app renders baseline rather than not at all.
@spec boot(atom() | nil) :: :ok
Boot-time entry point: load the host's manifest and register the activated
plugins' screens so they're navigable. Called from Mob.App.start/0.
nil (no resolvable host app — e.g. on host BEAM / tests) is a no-op. Safe
to call when no tier-3/4 plugin is active: the manifest is empty and nothing
is registered.
@spec composites() :: [map()]
Activated plugins' pure-Elixir composite components
(%{atom, expand: {M, F}}) — the manifest expand: ui_components form.
@spec default_style() :: atom() | nil
The configured :default_style name (or nil — neutral baseline).
@spec dispatch_notification(map()) :: :handled | :unhandled
Routes a notification payload to the first matching plugin handler.
Walks notification_handlers/0 in order; the first handler whose :match
(a map prefix-matched against the payload, or a {M,F,arity} predicate) wins,
and its {M,F,arity} handler is invoked with the payload. Returns :handled
or :unhandled (the host's own handle_info takes the unhandled case).
This is the pure routing core; the central notification delivery that feeds it is wired natively (Phase 3).
Reads a plugin setting, falling back to the schema default when unset.
Backed by Mob.State (the persistent K/V store) under a per-plugin namespaced
key. Returns nil for an unknown plugin/key.
@spec install(map()) :: :ok
Caches an already-built manifest (used by load/1 and tests).
@spec lifecycle() :: [map()]
Activated plugins' lifecycle declarations.
Reads the host app's generated manifest and caches it in :persistent_term.
otp_app is the host application name (e.g. :mob_plugin_demo); the file is
resolved under its priv/. Called once from Mob.App.start/0. Returns the
loaded manifest (also retrievable later via manifest/0).
@spec manifest() :: map()
The cached manifest, or the empty set if nothing has been loaded.
@spec nifs() :: [atom()]
Activated plugins' NIF module atoms. boot/1 loads each at startup so an iOS
plugin NIF's load callback fires eagerly (registering any permission handler
it owns) before a screen can request that permission.
@spec notification_handlers() :: [map()]
Activated plugins' notification handlers, in dispatch order.
Writes a plugin setting after validating its value against the schema type.
Returns :ok, {:error, {:invalid_type, type}}, or {:error, :unknown_setting}.
Reads + evaluates the manifest for otp_app without caching. Returns the
empty set when the priv dir or file is absent, or the file is malformed (a
missing manifest must never crash boot).
Reads + evaluates a manifest from an explicit path (empty set on any failure).
@spec register_composites() :: :ok
Registers each manifest-declared composite expander into Mob.Composite.
Malformed entries are skipped (the build validator is where shape errors
surface; a stale hand-edited manifest must not crash boot).
@spec register_screens() :: :ok
Registers each manifest screen into Mob.Nav.Registry under an atom derived
from its default_route, so the host (or the plugin's own screens) can
navigate to it by route. The module is also directly navigable. The host
still chooses where to surface a plugin screen in its navigation/1
structure — registration only makes the destination resolvable.
Resolves a plugin://<plugin>/<file> image reference to its on-device bundle
path (assets/plugin/<plugin>/<file>), the convention native_build copies
plugin images to. The renderer calls this when an image src uses the
plugin:// scheme; a non-plugin URL returns :passthrough so normal image
handling continues. Returns :error for a malformed plugin:// reference.
@spec screens() :: [map()]
Activated plugins' screen declarations (%{plugin, module, default_route}).
@spec settings() :: [map()]
Activated plugins' settings declarations.
Resolves the screen a host pushes to let users edit a plugin's settings.
A tier-4 plugin owns its settings UX; the host only needs the entry point, so
it calls this to get the module to push_screen/2. Returns :error when the
plugin declared no editor_screen.
@spec start_lifecycle() :: :ok
Starts the tier-4 plugin supervisor (runs each plugin's lifecycle.on_start,
starts its supervised children, and the lifecycle event dispatcher). Called
from Mob.App.start/0 after the host's own on_start/0. No-op when no plugin
declares a :lifecycle.
@spec styles() :: [map()]
Activated token-only style packages (%{name, theme}), from MOB_STYLES.md's lane.