Mobile Engineering
Learn one mobile state transition at a time. Every chapter provides exact model evidence and names the Android, iOS, device, accessibility, network, signing, and store behavior that still needs separate platform verification.
Your first mobile state model: process death, route identity, and durable truth
Objective Distinguish transient process memory, restorable route identity, and durable user data by replaying one process-death event.
Core explanation
A mobile application is an operating-system guest, not a continuously running desktop process. Android and iOS may create, pause, background, reclaim, and later recreate its screens or entire process as memory, power, and user activity change. The sandbox limits files, credentials, sensors, and inter-application communication; signed builds, entitlements, manifests, and store policies grant only declared capabilities. Separate rendering, screen state, domain rules, repositories, local persistence, network clients, and thin platform adapters so each boundary can be tested and replaced. Keep environment configuration distinct from secrets: anything shipped in an application package can eventually be inspected. Persist durable user work transactionally, save only small restoration identifiers, and make initialization idempotent because callbacks and launches may repeat.
Three kinds of state, not one architecture diagram
Begin with the values in the JSON packet: transient process memory, a small route identity, and a durable draft reference. Predict exactly which values survive process death before reading about repositories, lifecycle callbacks, packages, or store delivery. The distinction is useful on every platform because the operating system may reclaim the process while the user still owns saved work.
The packet is replayable model evidence only. A Kotlin/Android adapter must separately prove Activity or process recreation and real persistence; a Swift/Apple adapter must separately prove scene or application restoration and real persistence. The later laboratory explains those adapters but does not retroactively turn the packet into a device run.
Compare platform lifecycle, sandbox, and delivery models
Android, iOS, and cross-platform runtimes execute inside system-managed sandboxes where the operating system can suspend, background, reclaim, or terminate work. An app does not own continuous process lifetime. Screens, scenes or activities, services, extensions, and background tasks have distinct entry and restoration rules. Design every important operation so process death between steps is recoverable.
The install contains code, resources, manifests, entitlements or permissions, signatures, and configuration visible to the user’s device. Client secrets cannot be protected as server credentials. The store and operating system mediate signing, review, distribution, updates, rollback availability, data backup, and permissions. Specify supported OS, device classes, orientations, form factors, account behavior, offline promise, and data sensitivity before choosing libraries.
Organize domain, application, data, and UI dependencies
Keep validated values and business state independent from a UI toolkit, database, HTTP client, or store SDK. Application use cases coordinate repositories, clocks, IDs, authorization context, and analytics. Data adapters translate remote DTOs and local records. UI models own screen state under the platform’s main-thread or main-actor rule, and views render and send user intents.
Dependencies point inward toward stable rules while runtime composition supplies concrete adapters. Avoid a generic repository that exposes SQL-like queries to every screen, a global singleton service locator, or view code that mutates database entities directly. A feature package should have one primary reason to change and an intentional public API. Architecture is proven when a use case runs under a command or unit harness without the framework.
Lock toolchains, dependencies, variants, and signing inputs
Record platform SDK and compiler, build-tool and plugin versions, dependency locks, target OS, architecture, build variant or scheme, feature switches, generated code, asset pipeline, application identifier, version, revision, and artifact hash. Debug, test, profile, and release can differ in optimization, logging, networking, entitlements, and signing; test the real release configuration.
Signing credentials and store API keys stay outside source and untrusted CI. Reproducible source inputs do not always make a bit-identical signed package, but provenance must tie the archive to the verified source and pipeline. Inspect final manifests, entitlements, embedded libraries, architectures, privacy declarations, debug symbols, and accidental endpoints. Promote the exact approved package when the delivery system permits.
Laboratory: establish a recoverable course-app skeleton
Create domain, use-case, local-data, remote-data, UI-model, app, and test boundaries in the chosen platform. Implement a local static course list and detail opened by CourseId, plus a build-info screen using safe facts. Kill and restore the process at every navigation step. Run the domain and use case without an emulator or simulator.
Seed a secret in the bundle, debug endpoint in release, view importing database row, large mutable object passed through navigation, unsupported OS API, dependency not locked, wrong signing entitlement, and process death after selection. Acceptance builds clean debug and release variants, restores by stable ID, exposes no private build credential, and documents how another maintainer adds one feature.