# `mix mob.enable`
[🔗](https://github.com/genericjam/mob_dev/blob/master/lib/mix/tasks/mob.enable.ex#L1)

Enables one or more optional Mob features by patching `mix.exs`, manifest
files, and generating any required source files.

## Usage

    mix mob.enable FEATURE [FEATURE ...]

Multiple features can be enabled in a single command:

    mix mob.enable camera photo_library
    mix mob.enable camera photo_library file_sharing liveview

## Features

### `liveview`

Enables LiveView mode — the Mob app runs a local Phoenix endpoint and displays
it in a native WebView. Web developers can ship a mobile app with zero native
UI code.

What it does:

  - Generates `lib/<app>/mob_screen.ex` — a `Mob.Screen` that opens a WebView
    at `http://127.0.0.1:PORT/`
  - Injects the `MobHook` LiveView hook into `assets/js/app.js`
  - Injects a hidden `<div id="mob-bridge" phx-hook="MobHook">` into
    `root.html.heex` — **this is required for the hook to mount**
  - Updates `mob.exs` with `liveview_port` so `Mob.LiveView.local_url/1` works

### Why the hidden div is required

Phoenix LiveView hooks only execute when a DOM element carrying
`phx-hook="MobHook"` exists in the rendered page. Registering `MobHook` in
`app.js` is necessary but not sufficient — without a matching DOM element the
hook never mounts and `window.mob` is never replaced with the LiveView-backed
version. Messages would silently route through the native NIF bridge instead
of the LiveView WebSocket, so `handle_event/3` would never fire.

See `MobDev.Enable` module doc and `guides/liveview.md` for the full
two-bridge architecture explanation.

After running:

  1. Add `MyApp.MobScreen` to your supervision tree (or call
     `Mob.Screen.start_root(MyApp.MobScreen)` from your `Mob.App.on_start/0`)
  2. Ensure Phoenix is running on the port set in `mob.exs` (default: 4000)

### `camera`

Adds camera permission declarations to platform manifests.

- iOS: adds `NSCameraUsageDescription` to `ios/*/Info.plist`
- Android: adds `<uses-permission android:name="android.permission.CAMERA"/>`
  to `android/app/src/main/AndroidManifest.xml`

### `photo_library`

- iOS: adds `NSPhotoLibraryAddUsageDescription` to Info.plist
- Android: no manifest change needed (API 29+)

### `file_sharing`

- iOS: adds `UIFileSharingEnabled` and `LSSupportsOpeningDocumentsInPlace`
  to Info.plist
- Android: adds `<provider android:name="FileProvider">` with paths config

### `location`

- iOS: adds `NSLocationWhenInUseUsageDescription` to Info.plist
- Android: adds `ACCESS_FINE_LOCATION` permission

### `notifications`

- iOS: creates `ios/<app>.entitlements` with `aps-environment: development`.
  After running, execute `mix mob.provision` so Xcode downloads a push-capable
  provisioning profile. Then call `Mob.Permissions.request(socket, :notifications)`
  and `Mob.Notify.register_push(socket)` at runtime to obtain a device token.
- Android: runtime only — `POST_NOTIFICATIONS` is requested at runtime, no
  manifest key needed.

### `pythonx`

Enables embedded CPython via [Pythonx](https://hex.pm/packages/pythonx)
on iOS **and** Android.

- **iOS:** BeeWare's [`Python-Apple-support`](https://github.com/beeware/Python-Apple-support)
  `Python.xcframework` is bundled by `mix mob.deploy --native`.
- **Android:** [Chaquopy](https://chaquo.com/chaquopy/)'s prebuilt CPython
  is unpacked at first launch. `libpythonx.so` (the Pythonx NIF) is
  cross-compiled with the Android NDK against a stub `libpython3.13.so`
  so the BEAM dynamic loader is satisfied; the real lib resolves at
  runtime via SONAME match.
- **Bare CPython only.** Bundles ship the interpreter, stdlib, and
  standard C extensions (`_ssl`, `_ctypes`, `_hashlib`, …). Third-party
  wheels (`cryptography`, `numpy`, `RNS`, …) are out of scope —
  produce your own (BeeWare's [`mobile-forge`](https://github.com/beeware/mobile-forge)
  on iOS, Chaquopy's wheel pipeline on Android) and drop them into
  your project.

What it does:

  - Adds `{:pythonx, "~> 0.4"}` to `mix.exs` deps.
  - Generates `lib/<app>/python_paths.ex` — pure detection module that
    locates the bundled framework at runtime (`:desktop` /
    `{:ios, paths}` / `{:android, paths}` / `{:partial, missing}`).
  - **No `:uv_init` config patch.** Pythonx ships an Application
    that auto-runs uv at boot if `:uv_init` is in compile-time config,
    and uv doesn't exist on device. Instead the on_start template
    inlines `pyproject_toml` and calls `Pythonx.Uv.fetch/2 +
    Pythonx.Uv.init/2` only on the `:desktop` branch. Same code path
    `iex -S mix` would use, just opt-in.

Bundle size impact: ~70 MB on iOS, ~30 MB on Android (interpreter +
stdlib + arch-specific C extensions). Apply this only when you actually
want to call Python from BEAM — non-Python apps stay vanilla.

After running, your `Mob.App.on_start/0` should:

  - call `Application.ensure_all_started(:pythonx)` (starts the
    `Pythonx.Janitor`, required for `Pythonx.eval/3`);
  - case-match `<App>.PythonPaths.detect/1` and call `Pythonx.Uv.fetch
    + init` on `:desktop` (provisioning a uv-managed CPython on first
    run) or `Pythonx.init/4` on `{:ios, _}` / `{:android, _}`.

See `guides/python_embedding.md` for the full template.

### `mlx`

Enables Apple's [MLX](https://github.com/ml-explore/mlx) library + the
[EMLX](https://hex.pm/packages/emlx) Nx backend on iOS. Gives the app
fast on-device tensor math (matmul, FFT, linalg, etc.) backed by
Apple's Accelerate framework (vectorized BLAS/LAPACK).

- **iOS device + simulator:** `libmlx.a` + `libemlx.a` are
  cross-compiled and statically linked into the app binary. The
  pre-built bundle (~5 MB compressed, ~30 MB on disk per arch) is
  downloaded once and cached at `~/.mob/cache/libmlx-<ver>-ios-<slice>/`
  by `MobDev.MLXDownloader`. `MOB_STATIC_EMLX_NIF` flips on
  automatically — the EMLX NIF is registered in the static-NIF table
  so `load_nif/2` resolves it without dlopen.
- **Android:** not supported in v1. No Metal on Android — a CPU-only
  NDK build via OpenBLAS is the path forward but isn't shipped yet.
- **CPU-only for v1.** Metal-on-iOS needs the iOS-Metal CMakeLists
  patch and Xcode 16's optional Metal Toolchain — deferred to a v2
  tarball variant.

What it does:

  - Adds `{:nx, "~> 0.10"}` and `{:emlx, "~> 0.2"}` to `mix.exs` deps.
  - Generates `lib/<app>/ml_init.ex` — a one-call helper that sets
    `EMLX.Backend` as Nx's global default, with a clean
    `Nx.BinaryBackend` fallback if the NIF can't load.

After running, your `Mob.App.on_start/0` should call
`<App>.MLInit.configure()` once `Mob.Screen.start_root/1` and
`Mob.Dist.ensure_started/1` have run.

---

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