# `MobDev.NativeBuild`
[🔗](https://github.com/genericjam/mob_dev/blob/main/lib/mob_dev/native_build.ex#L1)

Builds native binaries (APK for Android, .app bundle for iOS simulator)
for the current Mob project.

Reads paths from `mob.exs` in the project root. If `mob.exs` is missing
or paths haven't been configured, prints instructions and exits.

OTP runtimes for Android and iOS are downloaded automatically from GitHub
and cached at `~/.mob/cache/` by `MobDev.OtpDownloader`.

## mob.exs keys

  * `:mob_dir`           — mob library repo (native C/ObjC/Swift source)
  * `:elixir_lib`        — Elixir stdlib lib dir

# `android_toolchain_available?`

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

Returns true when the Android build toolchain looks usable from the given
project directory. Three signals must all be present:

  1. `adb` is on PATH (build needs it to install the APK after Gradle)
  2. `<project_dir>/android/local.properties` exists and sets `sdk.dir`
  3. The directory `sdk.dir` points at exists on disk

Returns false otherwise so the deploy can skip Android cleanly instead of
failing late inside Gradle. Pure of side effects.

# `build_all`

```elixir
@spec build_all(keyword()) :: [:ok | {:error, term()}]
```

Builds native binaries for all platforms present in the project.
Runs Android Gradle build if `android/` dir exists.
Runs iOS build script if `ios/build.sh` exists (simulator), or
`xcodebuild` if targeting a physical iOS device via `device:` opt.

# `detect_physical_ios`

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

Returns the UDID of the sole connected physical iOS device, or nil.
When exactly one physical device is connected, it can be used automatically.
With zero or 2+ physical devices, returns nil.

# `fallback_entitlements_plist`

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

Generates the fallback entitlements plist that `build_device.sh` writes when
no `ios/*.entitlements` file is found in the project.

`aps_env` should be `"development"`, `"production"`, or `nil`.  When non-nil
the `aps-environment` key is included, allowing APNs push token registration
to succeed.  When nil the key is omitted (the historic default, suitable for
apps that do not use push notifications).

This function is public so it can be unit-tested independently of the shell
script that actually writes the file on device builds.

# `ios_toolchain_available?`

```elixir
@spec ios_toolchain_available?() :: boolean()
```

Returns true when an iOS build is feasible: macOS host with `xcrun`
installed. Linux/Windows always returns false. Pure of side effects.

# `narrow_platforms_for_device`

```elixir
@spec narrow_platforms_for_device([atom()], String.t() | nil) :: [atom()]
```

When `--device <id>` is given, narrow `platforms` to just the platform
the device lives on. Drops Android when the id resolves to an iOS
device (sim or physical), drops iOS otherwise.

Public so `mix mob.deploy` can apply the same narrowing before calling
`MobDev.Deployer.deploy_all/1` — otherwise the deployer's per-platform
`filter_by_device_id` complains "No device matched" against the
irrelevant platform even though the build itself was correctly
targeted.

Returns `platforms` unchanged when `device_id` is nil.

# `narrow_platforms_for_device`

```elixir
@spec narrow_platforms_for_device([atom()], String.t() | nil, (-&gt; [MobDev.Device.t()])) ::
  [atom()]
```

Variant that takes an iOS-discovery function so tests (and other
callers that already have the device list in hand) can avoid the
network-bound `IOS.list_devices/0` LAN scan.

The lister is called at most once per invocation; both `ios_device?`
and the physical-UDID format fallback consume the same result.

# `otp_dir_for_abi`

```elixir
@spec otp_dir_for_abi(String.t(), String.t(), String.t()) :: String.t()
```

Returns the OTP directory for the given Android ABI string.

---

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