# `MobDev.Deployer`
[🔗](https://github.com/genericjam/mob_dev/blob/master/lib/mob_dev/deployer.ex#L1)

Pushes compiled BEAM files from `_build/dev/lib/*/ebin/` to connected devices.

Does NOT rebuild APKs or recompile native code — that's `deploy.sh` (first-time setup).
Use this for day-to-day code iteration: edit Elixir → `mix mob.deploy` → code running.

## Transport selection

**Erlang dist (preferred)**: when a device node is already reachable via Erlang
distribution, BEAMs are hot-loaded via RPC. No restart needed — modules are
loaded in place exactly like `nl/1` in IEx.

**adb push / cp (fallback)**: when no dist connection exists (first deploy, app not
running), falls back to the traditional push-then-restart path.

## Platform behaviour

**Android**: pushes via `adb push` (requires `adb root`, i.e. emulator or debug build),
or falls back to `adb push` → `/data/local/tmp/` → `run-as tar xf` for real devices.

**iOS simulator**: copies files locally into `/tmp/otp-ios-sim/beamhello/` (no network
hop — the simulator shares the Mac filesystem).

# `android_package_installed?`

```elixir
@spec android_package_installed?(String.t(), String.t()) :: boolean()
```

True when the `adb shell pm list packages <pkg>` output indicates
`<pkg>` is installed on the device.

The check is a substring match for `package:<pkg>` because adb's
output is one `package:<name>` line per matching package — empty
output means "no match" (not "package called empty").

Public so the rule can be regression-tested without an emulator.

# `categorize_results`

```elixir
@spec categorize_results([{:ok | :skipped | :error, MobDev.Device.t()}]) ::
  {[MobDev.Device.t()], [MobDev.Device.t()], [MobDev.Device.t()]}
```

Bucket a per-device results list into `{deployed, failed, skipped}`.

Three outcomes:

  * `:ok` — push succeeded → `deployed`
  * `:skipped` — device wasn't a target (e.g. app not installed,
    typical when only one platform was built) → `skipped`
  * `:error` — push attempted and failed for a real reason → `failed`

Public so the categorization invariant (skipped never crosses into
failed; an unknown outcome isn't silently dropped) can be tested
independent of the hardware-dependent push pipeline.

# `deploy_all`

```elixir
@spec deploy_all(keyword()) ::
  {[MobDev.Device.t()], [MobDev.Device.t()], [MobDev.Device.t()]}
```

Discovers devices, pushes BEAMs, and optionally restarts apps.
Returns `{deployed, failed, skipped}` lists of `%Device{}`.
`skipped` is the deploy-isn't-applicable case — e.g. the app
isn't installed on a device because only the other platform was
built. Distinct from `failed` (real error during push).

---

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