Packages
mob_dev
0.6.21
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.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.17
0.5.16
0.5.15
0.5.14
0.5.13
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
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.37
0.3.35
0.3.34
0.3.33
0.3.28
0.3.26
0.3.23
0.3.21
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
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.18
0.2.17
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
Development tooling for the Mob mobile framework
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/mob/adopt/bridge.ex
defmodule Mix.Tasks.Mob.Adopt.Bridge do
@shortdoc "Installs the Mob LiveView bridge (MobHook + bridge div)"
@moduledoc """
Patches `assets/js/app.js` and `lib/<web>/components/layouts/root.html.heex`
to wire `window.mob` through a LiveView `phx-hook`. Output matches
`mix mob.new --liveview`.
Mob's native shell injects `window.mob` into every WebView for direct
JS↔native interop (camera, audio, sensors). The LV bridge patches
here *replace* that injection on mount with a LiveView-routed shim,
so `window.mob.send` goes through `pushEvent`/`handle_event` instead
of straight to native code. Useful when you want server-side BEAM
visibility into JS messages. Skip this if your project isn't using
LiveView (e.g. Hologram, vanilla controllers) — the native injection
alone is what you want.
## Options
- `--no-live-view` — skip the patches entirely with a notice. For
Hologram-only or non-Phoenix hosts.
Other orchestrator flags (`--no-ios`, `--no-android`, `--local`,
`--python`, `--host-url`) are accepted but inert here — declared in
the schema only so `mix mob.adopt` can forward its full argv
without Igniter rejecting unknown options.
## Refusal (LV mode)
Refuses (via `Igniter.add_issue/2`) when `assets/js/app.js` is missing
or doesn't contain a `new LiveSocket(...)` call, or when the
`root.html.heex` layout is missing or has no `<body>` tag. The pre-1.0
contract is "blessed shape only" — `--no-live-view` is the escape
hatch for everything else.
## Idempotency
Both `MobDev.Adopt.Patcher.inject_mob_hook/1` and
`inject_mob_bridge_element/1` short-circuit when their markers
(`MobHook` / `mob-bridge`) are already present.
Typically called by `mix mob.adopt`, not directly.
"""
use Igniter.Mix.Task
alias Igniter.Project.Application, as: ProjectApplication
alias MobDev.Adopt.Patcher
alias MobDev.AdoptGuard
@common_schema [
ios: :boolean,
android: :boolean,
local: :boolean,
python: :boolean,
host_url: :string,
live_view: :boolean
]
@common_defaults [ios: true, android: true, live_view: true]
@impl Igniter.Mix.Task
def info(_argv, _composing_task) do
%Igniter.Mix.Task.Info{
group: :mob,
example: "mix mob.adopt.bridge",
schema: @common_schema,
defaults: @common_defaults
}
end
@impl Igniter.Mix.Task
def igniter(igniter) do
mode = AdoptGuard.mode_from(igniter.args.options)
# Guard call is idempotent — orchestrator runs the same checks but
# `prepare_for_write` dedupes issues. Defends direct invocation.
igniter = AdoptGuard.check(igniter, mode)
cond do
igniter.issues != [] ->
igniter
mode == :thin ->
Igniter.add_notice(igniter, """
`mob.adopt.bridge` skipped (--no-live-view). The native shell
will inject `window.mob` directly; no LiveView hook needed.
""")
true ->
igniter
|> patch_app_js()
|> patch_root_html()
end
end
defp patch_app_js(igniter) do
Igniter.update_file(igniter, "assets/js/app.js", &update_app_js/1)
end
defp update_app_js(source) do
content = Rewrite.Source.get(source, :content)
Rewrite.Source.update(source, :content, Patcher.inject_mob_hook(content))
end
defp patch_root_html(igniter) do
web = "#{ProjectApplication.app_name(igniter)}_web"
candidates = [
"lib/#{web}/components/layouts/root.html.heex",
"lib/#{web}/templates/layout/root.html.heex"
]
case Enum.find(candidates, &Igniter.exists?(igniter, &1)) do
nil -> igniter
path -> Igniter.update_file(igniter, path, &update_root_html/1)
end
end
defp update_root_html(source) do
content = Rewrite.Source.get(source, :content)
Rewrite.Source.update(source, :content, Patcher.inject_mob_bridge_element(content))
end
end