MobDev.IOSInstalls (mob_dev v0.7.0)

Copy Markdown View Source

A record of which apps mob_dev has installed on which physical iOS device.

This exists for exactly one reason: so that mob_dev can clear other Mob apps off a device without touching anything else on it.

Physical-device Mob apps each start an in-process EPMD bound to 0.0.0.0:4369 (mob/ios/mob_beam.m), so only one can run at a time — launching a second gets EADDRINUSE and no BEAM. Clearing the others before launch is therefore necessary. What is not necessary, and what this module exists to prevent, is deciding which processes to kill by pattern-matching the running process list: every third-party app on the phone runs from /private/var/containers/Bundle/Application/, so that pattern matches Spotify, a banking app and everything else the owner had open (MOB-70).

A device is someone's phone. mob_dev gets to kill what mob_dev put there, and nothing else. If this record is missing or empty, the correct behaviour is to kill nothing.

Entries are dropped on uninstall (forget/2). Since the process listing carries no bundle ids, matching is by .app name — so a stale entry is not inert: it would stay killable, and a third-party app that later took that name would inherit it.

Stored as JSON at ~/.mob/ios_installs.json, keyed by device UDID. It is a cache, not a source of truth: deleting it costs a stale Mob app surviving a launch, not correctness.

Summary

Functions

Drop bundle_id from udid's record, after uninstalling it.

Apps mob_dev has installed on udid, newest first. [] when unknown — which callers must treat as "kill nothing", not "kill everything".

Path to the registry file. Override with MOB_IOS_INSTALLS in tests.

Record that bundle_id (whose bundle is app_name.app) is installed on udid.

Types

app()

@type app() :: %{bundle_id: String.t(), app_name: String.t()}

Functions

forget(udid, bundle_id)

@spec forget(String.t(), String.t()) :: :ok

Drop bundle_id from udid's record, after uninstalling it.

Matching is by app NAME, so a stale entry is not inert: it stays killable for ever, and a third-party app that later takes that name inherits the entry. Forgetting on uninstall is what makes the module's promise — we kill what we put there — true rather than approximately true.

installed(udid)

@spec installed(String.t()) :: [app()]

Apps mob_dev has installed on udid, newest first. [] when unknown — which callers must treat as "kill nothing", not "kill everything".

path()

@spec path() :: Path.t()

Path to the registry file. Override with MOB_IOS_INSTALLS in tests.

record(udid, bundle_id, app_name)

@spec record(String.t(), String.t(), String.t()) :: :ok

Record that bundle_id (whose bundle is app_name.app) is installed on udid.

Idempotent: re-installing the same app does not duplicate the entry, and a changed app_name for a known bundle id replaces it rather than accumulating.