mix mob.enable (mob_dev v0.5.11)

Copy Markdown View Source

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.heexthis 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 on iOS and Android.

  • iOS: BeeWare's Python-Apple-support Python.xcframework is bundled by mix mob.deploy --native.
  • Android: 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 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 library + the 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.