Packages
mob_dev
0.3.6
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.17
0.5.16
0.5.15
0.5.14
0.5.13
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.37
0.3.35
0.3.34
0.3.33
0.3.28
0.3.26
0.3.23
0.3.21
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.18
0.2.17
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
Development tooling for the Mob mobile framework
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/mob.devices.ex
defmodule Mix.Tasks.Mob.Devices do
use Mix.Task
@shortdoc "List all connected Android and iOS devices"
@moduledoc """
Scans for connected Android devices (via adb) and iOS simulators/physical
devices (via xcrun simctl / ideviceinfo) and prints their status.
mix mob.devices
Each device is shown with a short **ID** you can pass to `--device`:
mix mob.deploy --device emulator-5554
mix mob.deploy --native --device 78354490
Gracefully skips platforms whose tools are not installed (adb / xcrun).
## Under the hood
# Android
adb devices -l
# → parses serial numbers, device/emulator state, and manufacturer/model
# iOS (macOS only)
xcrun simctl list devices booted --json
ideviceinfo -k UniqueDeviceID (if libimobiledevice is installed)
"""
alias MobDev.Discovery.{Android, IOS}
alias MobDev.Device
@impl Mix.Task
def run(_args) do
Mix.Task.run("app.config")
android = list_android()
ios = list_ios()
IO.puts("")
print_section("Android", android)
IO.puts("")
print_section("iOS", ios)
all = device_list(android) ++ device_list(ios)
if all != [] do
IO.puts("")
IO.puts("Pass the ID to --device to target a specific device:")
IO.puts(" mix mob.deploy --device #{Device.display_id(hd(all))}")
end
IO.puts("")
end
# ── Device discovery (returns tagged list or a reason atom) ──────────────────
defp list_android do
case System.find_executable("adb") do
nil -> {:unavailable, "adb not found — install Android platform-tools"}
_ -> {:ok, Android.list_devices()}
end
end
defp list_ios do
cond do
not macos?() ->
{:unavailable, "iOS deployment requires macOS"}
System.find_executable("xcrun") == nil ->
{:unavailable, "xcrun not found — install Xcode command-line tools"}
true ->
{:ok, IOS.list_devices()}
end
end
# ── Output ───────────────────────────────────────────────────────────────────
defp print_section(title, result) do
IO.puts("#{IO.ANSI.cyan()}#{title}#{IO.ANSI.reset()}")
case result do
{:unavailable, reason} ->
IO.puts(" (#{reason})")
{:ok, []} ->
IO.puts(" (none)")
{:ok, devices} ->
print_table(devices)
Enum.each(devices, &print_hints/1)
end
end
defp print_table(devices) do
max_name = devices |> Enum.map(&name_len/1) |> Enum.max()
max_ver = devices |> Enum.map(&ver_len/1) |> Enum.max()
max_type = devices |> Enum.map(&type_len/1) |> Enum.max()
Enum.each(devices, fn d ->
icon = status_icon(d)
name = pad(d.name || d.serial, max_name)
ver = pad(d.version || "", max_ver)
type = pad(type_label(d), max_type)
id = IO.ANSI.bright() <> Device.display_id(d) <> IO.ANSI.reset()
IO.puts(" #{icon} #{name} #{ver} #{type} #{id}")
end)
end
defp name_len(d), do: String.length(d.name || d.serial)
defp ver_len(d), do: String.length(d.version || "")
defp type_len(d), do: String.length(type_label(d))
defp type_label(%{type: :emulator}), do: "emulator"
defp type_label(%{type: :simulator}), do: "simulator"
defp type_label(%{type: :physical}), do: "physical"
defp type_label(_), do: "device"
defp status_icon(%{status: :connected}), do: "✓"
defp status_icon(%{status: :booted}), do: "·"
defp status_icon(%{status: :discovered}), do: "·"
defp status_icon(%{status: :unauthorized}), do: "✗"
defp status_icon(%{status: :error}), do: "!"
defp status_icon(_), do: "·"
defp pad(str, width), do: String.pad_trailing(str, width)
# ── Hints ────────────────────────────────────────────────────────────────────
defp print_hints(%{status: :unauthorized}) do
IO.puts(
" #{IO.ANSI.yellow()}→ Check device for 'Allow USB debugging?' prompt#{IO.ANSI.reset()}"
)
end
defp print_hints(%{platform: :android, serial: serial}) do
case Android.developer_mode(serial) do
:disabled ->
IO.puts(
" #{IO.ANSI.yellow()}→ Enable Developer Mode: Settings → About → tap Build Number 7×#{IO.ANSI.reset()}"
)
_ ->
:ok
end
end
defp print_hints(_), do: :ok
defp device_list({:ok, devices}), do: devices
defp device_list({:unavailable, _}), do: []
defp macos?, do: match?({:unix, :darwin}, :os.type())
end