# `DalaDev.Enable`
[🔗](https://github.com/manhvu/dala_dev/blob/main/lib/dala_dev/enable.ex#L1)

Pure helpers for `mix dala.enable` — extracted for testability.

## LiveView bridge architecture

Enabling LiveView mode involves three coordinated patches. Understanding why
all three are necessary prevents subtle bugs when setting up projects manually.

### The two bridges

The native WebView (iOS WKWebView / Android WebView) injects a `window.dala`
JavaScript object into every page it loads. This object routes calls through
the NIF bridge:

    window.dala.send(data)      // JS → NIF → Elixir handle_info
    window.dala.onMessage(fn)   // registers handler for NIF → JS messages
    window.dala._dispatch(json) // called by the NIF to deliver messages to JS

In LiveView mode you want a different routing: JS messages should travel over
the LiveView WebSocket so that `handle_event/3` in your LiveView receives them
and `push_event/3` delivers server messages to JS. The DalaHook replaces
`window.dala` with a LiveView-backed version on mount:

    window.dala.send(data)      // JS → pushEvent("dala_message") → handle_event/3
    window.dala.onMessage(fn)   // registers handler for handleEvent("dala_push")
    window.dala._dispatch       // no-op: server messages arrive via handleEvent

### Why a DOM element is required (the non-obvious part)

Phoenix LiveView hooks only execute their `mounted()` callback when an element
carrying `phx-hook="DalaHook"` is present in the rendered HTML *and* the
LiveView WebSocket has connected. Registering DalaHook in the `hooks:` map in
`app.js` is necessary but not sufficient — the hook is dormant until LiveView
finds a matching DOM element.

Without the element:
- DalaHook never mounts
- `window.dala` is never replaced with the LiveView version
- `window.dala.send()` routes through the native NIF bridge instead of LiveView
- `handle_event/3` never fires; your LiveView cannot receive JS messages

The element is a hidden `<div>` placed immediately after the opening `<body>`
tag in `root.html.heex`:

    <div id="dala-bridge" phx-hook="DalaHook" style="display:none"></div>

Placing it at the top of `<body>` ensures the hook mounts as early as possible,
so `window.dala` is overridden before any page-specific JS runs.

### Android timing note

iOS injects the native `window.dala` shim via `WKUserScript` at
`.atDocumentStart` — before any page JS runs. Android injects it via
`evaluateJavascript` in `onPageFinished` — after the page has loaded. Between
page load and `onPageFinished` on Android, `window.dala` is undefined. In
practice LiveView connects after `onPageFinished`, so both shims are available
by the time the DalaHook mounts. If you call `window.dala` during
`DOMContentLoaded`, guard with `if (window.dala)`.

# `build_plist_entry`

```elixir
@spec build_plist_entry(String.t(), term(), keyword()) :: String.t()
```

Builds a plist `<key>/<value>` entry for Info.plist injection.

Options:
  - `type: :bool` — emits `<true/>` or `<false/>` instead of `<string>`

# `dala_bridge_element`

```elixir
@spec dala_bridge_element() :: String.t()
```

Returns the hidden bridge `<div>` element that must appear in `root.html.heex`.

See the module doc for why this element is required.

# `dala_hook_js`

```elixir
@spec dala_hook_js() :: String.t()
```

Returns the DalaHook JS constant to inject into app.js.

# `find_root_html`

```elixir
@spec find_root_html(String.t(), String.t()) :: String.t() | nil
```

Finds `root.html.heex` in a Phoenix project rooted at `project_dir`.

Checks both the Phoenix 1.7+ convention:

    lib/<app_name>_web/components/layouts/root.html.heex

and the pre-1.7 convention:

    lib/<app_name>_web/templates/layout/root.html.heex

Returns the path string or `nil` if neither file exists.

# `inject_android_network_security_config`

```elixir
@spec inject_android_network_security_config(String.t()) :: String.t()
```

Adds `android:networkSecurityConfig="@xml/network_security_config"` to the
`<application>` tag in an AndroidManifest.xml string.

Idempotent — returns the content unchanged if the attribute is already present.

# `inject_dala_bridge_element`

```elixir
@spec inject_dala_bridge_element(String.t()) :: String.t()
```

Injects the hidden bridge `<div>` into `content` (a `root.html.heex` file).

The element is placed immediately after the opening `<body>` tag. This is
the mount point for DalaHook — without it the hook never executes and
`window.dala` is never replaced with the LiveView version. See the module doc
for the full explanation.

Returns the patched HTML string unchanged if `id="dala-bridge"` is already
present.

# `inject_dala_hook`

```elixir
@spec inject_dala_hook(String.t()) :: String.t()
```

Injects the DalaHook definition and registration into `content` (the full
text of `assets/js/app.js`).

- Inserts the hook constant after the last top-level `import` line.
- Registers `DalaHook` in the `hooks:` option passed to `LiveSocket`.

Returns the patched JS string. Idempotency (skip if already present) is
handled by the calling task, not by this function.

# `network_security_config_xml`

```elixir
@spec network_security_config_xml() :: String.t()
```

Returns the XML content for the Android network security config.

# `read_app_name_from`

```elixir
@spec read_app_name_from(String.t()) :: String.t()
```

Reads the `app:` atom from the given `mix.exs` path and returns the app
name as a string, or raises.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
