Search documentation of mob

# Mobile surface matrix

Copy Markdown View Source

What Mob covers — what's solid, what's partial, what's missing. Use this to set realistic expectations before starting an app, and to spot gaps worth filling (either in mob core, in a plugin, or by declaring out-of-scope).

The reference surface is the union of React Native core, Expo SDK modules, and platform-native capabilities both ecosystems have converged on as "what mobile apps need." Many missing items are pluggable — see MOB_PLUGINS.md for the manifest spec.

This doc is hand-maintained from inspection of `lib/mob/` and `src/mob_nif.erl`. If you add a capability, update the matching row.

## Legend

✅ | Fully present — public Elixir API, both iOS + Android (unless noted)
🟡 | Partial — works but limited (single platform, narrow API, or known caveats)
❌ | Missing — could be a plugin or future core addition
⛔ | Out of scope — requires separate deployment target (widgets, Watch app), or fundamentally incompatible with Mob's architecture

Per-platform columns: `✓` = supported, `—` = not supported, `n/a` = not applicable on that platform.

## UI components (render tree)

Elements you can use inside `~MOB`. The set is intentionally small and orthogonal — composition over a fat component library.

Component | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
`<Box>` | ✅ | ✓ | ✓ | Container with align, padding, background, corner radius, border
`<Column>`, `<Row>` | ✅ | ✓ | ✓ | Flex layouts
`<Text>` | ✅ | ✓ | ✓ | Font, color, size, weight, align, line height, letter spacing
`<Button>` | ✅ | ✓ | ✓ | Tap handler, text, background, fill width
`<Image>` | ✅ | ✓ | ✓ | Local + remote (Coil on Android, AsyncImage on iOS)
`<TextField>` | ✅ | ✓ | ✓ | Keyboard type, return key, placeholder, change events
`<Toggle>` | ✅ | ✓ | ✓ | Boolean switch
`<Slider>` | ✅ | ✓ | ✓ | Min/max/value, change events
`<Progress>` | ✅ | ✓ | ✓ | Linear + circular
`<Divider>` | ✅ | ✓ | ✓ | Horizontal line separator
`<Spacer>` | ✅ | ✓ | ✓ | Layout filler
`<Scroll>` | ✅ | ✓ | ✓ | Vertical or horizontal, scroll observation on iOS 18+
`<List>` | ✅ | ✓ | ✓ | Vertical / horizontal stack with selection
`<LazyList>` | ✅ | ✓ | ✓ | Virtualised long-list with on_end_reached pagination
`<TabBar>` | ✅ | ✓ | ✓ | Bottom tab bar (Material 3 NavigationBar on Android, SwiftUI Tab on iOS)
`<WebView>` | ✅ | ✓ | ✓ | Inline web view, JS bridge, navigation control
`<CameraPreview>` | ✅ | ✓ | ✓ | Live preview with frame stream
`<Video>` | 🟡 | ✓ | 🟡 | Android: ExoPlayer integration pending
`<GpuView>` | ✅ | ✓ | ✓ | Metal (iOS) / GLES 3.0 (Android) fragment shader surface
Custom views via `<NativeView>` | ✅ | ✓ | ✓ | Register a plugin-defined render-tree node type
Date / Time / Color pickers | ❌ | — | — | Plugin candidate
`<SearchBar>` | ❌ | — | — | Native search bar (UISearchBar / SearchBar). Plugin candidate
`<DatePicker>` | ❌ | — | — | Plugin candidate
`<Modal>` (sheet presentation) | 🟡 | 🟡 | 🟡 | Programmatic alerts + action sheets exist; full sheet-style modal is plugin territory
Pull-to-refresh | ❌ | — | — | Missing; commonly requested. Plugin candidate
Bottom sheets | ❌ | — | — | Plugin candidate
Drawer navigation | ❌ | — | — | Plugin candidate; mob's nav model is stack-based today

## Touch, gesture, input

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
Tap / double-tap / long-press | ✅ | ✓ | ✓ | `on_tap`, `on_double_tap`, `on_long_press` props
Swipe (l/r/u/d) | ✅ | ✓ | ✓ | `on_swipe_left`, etc.
Pan / drag gesture | 🟡 | 🟡 | 🟡 | Tap-based; full pan-responder system (like react-native-gesture-handler) is missing
Pinch / zoom | ❌ | — | — | Plugin candidate; common for image/map views
Rotation gesture | ❌ | — | — | Plugin candidate
Hardware keyboard events | ❌ | — | — | `key_press/1` exists for the test harness but not as a user-facing API
Keyboard show/hide events | ❌ | — | — | Missing; commonly needed for keyboard-aware layouts
`<KeyboardAvoidingView>` equivalent | ❌ | — | — | Plugin / core candidate
Apple Pencil / stylus events | ❌ | — | n/a | Plugin territory
3D Touch / Force Touch | ❌ | — | n/a | Deprecated by Apple; low priority
Drag and drop (cross-app) | ❌ | — | — | Plugin candidate
Haptic feedback | ✅ | ✓ | ✓ | `Mob.Haptic.tap/1` etc.

## Device + system info

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
Platform detection | ✅ | ✓ | ✓ | `Mob.Device.platform/0` returns `:ios` or `:android`
OS version | ✅ | ✓ | ✓ | `Mob.Device.os_version/0`
Device model | ✅ | ✓ | ✓ | `Mob.Device.model/0`
Foreground / background state | ✅ | ✓ | ✓ | `Mob.Device.foreground?/0` + `{:device, :foreground/:background, ...}` events
Battery level + state | ✅ | ✓ | ✓ | `Mob.Device.battery_level/0`, `battery_state/0`
Thermal state | ✅ | ✓ | ✓ | `Mob.Device.thermal_state/0`
Low-power mode | ✅ | ✓ | ✓ | `Mob.Device.low_power_mode?/0`
Color scheme (light/dark) | ✅ | ✓ | ✓ | `Mob.Theme.color_scheme/0` + `Mob.Theme.Adaptive` (auto-watch)
Safe area insets | ✅ | ✓ | ✓ | `Mob.Device.safe_area/0`
Screen dimensions / pixel ratio | ✅ | ✓ | ✓ | `Mob.Device.screen_info/0`
Locale / language | 🟡 | 🟡 | 🟡 | Derivable from system; no first-class API
Time zone | 🟡 | 🟡 | 🟡 | Use Erlang's `:calendar` directly
Network info (cell vs wifi, type) | ❌ | — | — | Plugin candidate (NetInfo equivalent)
Network reachability | ❌ | — | — | Plugin candidate
Screen brightness | ❌ | — | — | Plugin candidate
Screen orientation lock | ❌ | — | — | Plugin candidate
Idle timer / screen wake | ❌ | — | — | Plugin candidate
Exit app | ✅ | n/a | ✓ | Android only; iOS forbids programmatic exit

## Storage

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
Key-value store | ✅ | ✓ | ✓ | `Mob.Storage` with typed schemas, namespacing
Files API | ✅ | ✓ | ✓ | `Mob.Files`, plus `Mob.Storage.dir/1` for app-private paths
External files dir (Android) | ✅ | n/a | ✓ | `storage_external_files_dir/1`
Save to photo library | ✅ | ✓ | ✓ | `Mob.Storage.save_to_photo_library/1` + Android MediaStore equivalent
SQLite | ✅ | ✓ | ✓ | Via `:ecto_sqlite3` + bundled `libsqlite3_nif.so`
Keychain / Keystore | ❌ | — | — | Plugin candidate (standalone API beyond biometric)
Secure-storage / encrypted-storage | ❌ | — | — | Plugin candidate

## Camera + microphone

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
Capture photo | ✅ | ✓ | ✓ | `Mob.Camera.capture_photo/1`
Capture video | ✅ | ✓ | ✓ | `Mob.Camera.capture_video/1`
Live preview | ✅ | ✓ | ✓ | `<CameraPreview>` component
Per-frame stream | ✅ | ✓ | ✓ | `Mob.Camera.start_frame_stream/2` — pushes RGBA frames to `handle_info`
Photo library picker | ✅ | ✓ | ✓ | `Mob.Photos.pick/2`
Audio recording | ✅ | ✓ | ✓ | `Mob.Audio.start_recording/2`
Audio playback | ✅ | ✓ | ✓ | `Mob.Audio.play/3`, stop, volume
Speech recognition | ❌ | — | — | Plugin candidate (SFSpeechRecognizer / SpeechRecognizer)
Voice activity detection | ❌ | — | — | Plugin candidate
Audio effects (reverb, EQ) | ❌ | — | — | Plugin candidate
Camera zoom / focus / exposure | 🟡 | 🟡 | 🟡 | Basic capture works; fine-grained control missing

## Connectivity

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
Bluetooth Classic | ✅ | n/a | ✓ | `Mob.Bt` + Hfp / Spp / Hid sub-modules
Bluetooth Low Energy (BLE) | ❌ | — | — | Plugin candidate — common request
NFC | ❌ | — | — | Plugin candidate (Core NFC / Android NFC)
WiFi info / scanning | ❌ | — | — | Plugin candidate; OS restrictions apply
USB host | ✅ | n/a | ✓ | `Mob.VendorUsb` — bulk read/write, custom devices
WebSocket client | 🟡 | n/a | n/a | Use Elixir libs directly (e.g. `:gun`)
HTTP client | 🟡 | n/a | n/a | Use Elixir libs (`:req`, `:finch`)
File upload progress | ❌ | — | — | Plugin candidate
Background download/upload | ❌ | — | — | Plugin candidate
mDNS / Bonjour | ❌ | — | — | Plugin candidate
Sockets (raw TCP/UDP) | 🟡 | n/a | n/a | Use Erlang's `:gen_tcp`/`:gen_udp`
Mob.Dist (BEAM clustering) | ✅ | ✓ | ✓ | Hot-push, device → desktop connection

## Sensors

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
Accelerometer | ✅ | ✓ | ✓ | `Mob.Motion.start(:accelerometer, ...)`
Gyroscope | ✅ | ✓ | ✓ | `Mob.Motion.start(:gyro, ...)`
Magnetometer | ❌ | — | — | Plugin candidate; `CMMotionManager` / `Sensor.TYPE_MAGNETIC_FIELD`
Barometer | ❌ | — | — | Plugin candidate
Proximity | ❌ | — | — | Plugin candidate
Ambient light | ❌ | — | — | Plugin candidate
Pedometer / step counter | ❌ | — | — | Plugin candidate
Compass / heading | ❌ | — | — | Plugin candidate

## Location

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
One-shot location | ✅ | ✓ | ✓ | `Mob.Location.get_once/0`
Continuous updates | ✅ | ✓ | ✓ | `Mob.Location.start/1`, stop
Background location | 🟡 | 🟡 | 🟡 | Mob's foreground-service keep-alive lets updates continue while backgrounded; not a true background-location API
Geofencing | ❌ | — | — | Plugin candidate (`CLCircularRegion` / `Geofencing API`)
Significant-change updates | ❌ | — | — | Plugin candidate (iOS)
Mock-location detection | ❌ | — | — | Plugin candidate
Reverse geocoding | ❌ | — | — | Use third-party API for now (e.g. Mapbox)

## Notifications

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
Local notification scheduling | ✅ | ✓ | ✓ | `Mob.Notify.schedule/2`, cancel
Push notification registration | ✅ | ✓ | ✓ | `Mob.Notify.register_push/0` → token to `handle_info`
Push delivery via APNs / FCM | ✅ | ✓ | ✓ | Via `mob_push` Hex package
Notification tap handling | ✅ | ✓ | ✓ | Foreground + background + cold-start (`take_launch_notification/0`)
Notification actions (buttons) | ❌ | — | — | Plugin / core candidate
Critical / time-sensitive flags (iOS) | ❌ | — | n/a | Plugin candidate
Notification grouping / threading | ❌ | — | — | Plugin candidate
Badge management | 🟡 | 🟡 | 🟡 | Basic only

## Background tasks

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
Foreground service / keep-alive | ✅ | ✓ | ✓ | `Mob.Background.keep_alive/0`
Background fetch (silent periodic) | ❌ | — | — | Plugin candidate (iOS Background Tasks framework / Android WorkManager)
Silent push handling | 🟡 | 🟡 | 🟡 | Push arrives but no dedicated "wake-and-handle-then-suspend" lifecycle
Background URL session | ❌ | — | — | Plugin candidate
Scheduled jobs (periodic / one-shot) | ❌ | — | — | Plugin candidate (WorkManager equivalent)

## Auth + payment

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
Biometric auth (Face ID / fingerprint) | ✅ | ✓ | ✓ | `Mob.Biometric.authenticate/2`
Apple Sign-In | ❌ | — | n/a | Plugin candidate (common requirement for App Store)
Google Sign-In | ❌ | — | — | Plugin candidate
Sign in with X / Facebook / etc. | ❌ | — | — | Plugin candidate
OAuth flow helpers | ❌ | — | — | Plugin candidate; can mostly be done from Elixir
In-app purchase (StoreKit / Play Billing) | ❌ | — | — | Plugin candidate; sensitive — needs receipt validation
Apple Pay | ❌ | — | n/a | Plugin candidate
Google Pay | ❌ | — | — | Plugin candidate
Passkeys / WebAuthn | ❌ | — | — | Plugin candidate

## ML / Vision

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
QR / barcode scanning | ✅ | ✓ | ✓ | `Mob.Scanner.scan/1` — full-screen scanner with format filtering
TFLite model inference | ✅ | ✓ | ✓ | Via `mix mob.enable tflite` (mob_dev 0.5.7+) — NNAPI/MTK on Android, Core ML delegate on iOS
Nx-based inference | 🟡 | 🟡 | 🟡 | Via `nx_eigen` exploration; not formalised
Apple Vision framework wrappers | ❌ | — | n/a | Plugin candidate (text recognition, face detection, image classification)
Apple Foundation Models (LLM) | ❌ | — | n/a | Plugin in flight — see mob PR #8 (DRAFT)
MLKit wrappers (Android) | 🟡 | n/a | 🟡 | Barcode scanning uses it under the hood; other models (text, face, pose) are plugin territory
OCR (text recognition) | ❌ | — | — | Plugin candidate
Face detection | ❌ | — | — | Plugin candidate
Pose detection | ❌ | — | — | Plugin candidate
Speech-to-text | ❌ | — | — | Plugin candidate
Translation | ❌ | — | — | Plugin candidate
Smart Reply | ❌ | — | — | Plugin candidate

## Maps

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
Native map view | ❌ | — | — | Plugin candidate (Apple Maps / Google Maps)
Annotations / markers | ❌ | — | — | Plugin candidate
Polylines / polygons | ❌ | — | — | Plugin candidate
User location display | ❌ | — | — | Plugin candidate
Map tile providers (Mapbox, etc.) | ❌ | — | — | Plugin candidate

## System integration

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
Clipboard | ✅ | ✓ | ✓ | `Mob.Clipboard.put/1`, `get/0`
Open URL (deep linking, browser) | ✅ | ✓ | ✓ | `Mob.Device.open_url/1` — picks browser, mail, tel, etc.
Share sheet (text) | ✅ | ✓ | ✓ | `Mob.Share.text/1`
Share sheet (image / file) | ❌ | — | — | Plugin candidate
Document picker | ✅ | ✓ | ✓ | `Mob.Files.pick/1`
Action sheet (iOS-style menu) | ✅ | ✓ | ✓ | `action_sheet_show/2` via Mob.Alert
Toast (Android-style) | ✅ | ✓ | ✓ | `toast_show/2` — implemented on both platforms
Alert dialog | ✅ | ✓ | ✓ | `Mob.Alert.alert/2`
Vibration patterns | ✅ | ✓ | ✓ | Via `Mob.Haptic`
App settings page (open) | ❌ | — | — | Plugin candidate
Calendar events | ❌ | — | — | Plugin candidate
Contacts | ❌ | — | — | Plugin candidate
Reminders (iOS) | ❌ | — | n/a | Plugin candidate
Permissions facade | ✅ | ✓ | ✓ | `Mob.Permissions.request/2` for camera, microphone, photos, location, notifications

## Accessibility

Capability | Status | iOS | Android | Notes
--- | --- | --- | --- | ---
Accessibility labels / hints | 🟡 | 🟡 | 🟡 | Some component props expose this; not uniform across all components
Screen reader announcements (imperative) | ❌ | — | — | Plugin / core candidate
Focus management (programmatic) | ❌ | — | — | Plugin / core candidate
Reduce-motion preference | ❌ | — | — | Plugin candidate
Bold-text preference | ❌ | — | — | Plugin candidate
Dynamic type / font scaling | 🟡 | 🟡 | 🟡 | iOS automatic via system size; explicit override needed
RTL support | 🟡 | 🟡 | 🟡 | Layout-engine level; no explicit `I18nManager` equivalent
Accessibility test inspection | ✅ | ✓ | ✓ | `Mob.Test` reads the AX tree for assertion-based UI testing

## iOS-only platform features

Capability | Status | Notes
--- | --- | ---
Live Activities / Dynamic Island | ⛔ | Requires Widget Extension target — separate from main app; not a Mob template today
Widgets (home + lock screen) | ⛔ | Same — Widget Extension target
App Clips | ⛔ | App Clip target; not in Mob templates
Watch app companion | ⛔ | WatchKit target; not in Mob templates
Share extensions | ⛔ | Share Extension target; not in Mob templates
Today extensions (deprecated by Apple) | ⛔ | —
Background App Refresh | ❌ | Plugin candidate
Apple Pencil events | ❌ | Plugin candidate
Multi-window (iPad) | 🟡 | App runs but no first-class multi-scene API
Split View / Slide Over | 🟡 | Same as multi-window
Picture in Picture (video) | ❌ | Plugin candidate
Universal Links / Custom URL Scheme | 🟡 | Open URL works; route registration is per-app, no unified API
Handoff / NSUserActivity | ❌ | Plugin candidate
Spotlight indexing | ❌ | Plugin candidate
App Shortcuts (Siri integration) | ❌ | Plugin candidate

## Android-only platform features

Capability | Status | Notes
--- | --- | ---
Home screen widgets | ⛔ | AppWidgetProvider — separate component, not in Mob templates
Quick Settings tiles | ⛔ | TileService — separate component
App Shortcuts (long-press launcher) | ❌ | Plugin candidate
Picture in Picture | ❌ | Plugin candidate
Multi-window | ✅ | Works via resizable activity flag
Split-screen | ✅ | Works via resizable activity flag
Foldable / large-screen support | 🟡 | Layout adapts; no first-class foldable APIs
Auto Backup | ✅ | Honored by default per AndroidManifest
Doze mode handling | ❌ | Plugin candidate (alarm/wake-up scheduling)
Direct Share | ❌ | Plugin candidate
Notification channels (configurable) | 🟡 | Default channel works; per-app multi-channel API is partial

## Architecturally not present (and probably shouldn't be)

Item | Why
--- | ---
JavaScript / TypeScript runtime | Mob's host language is Elixir/Erlang/Gleam on BEAM; bridging JS would defeat the architecture
React reconciler | Mob has its own render tree; no React VDOM under it
CSS / Yoga flexbox engine | iOS uses SwiftUI layout; Android uses Compose layout; both are native flexbox-equivalents
`XMLHttpRequest` / `fetch` polyfill | Use Erlang/Elixir HTTP libraries directly (`:req`, `:finch`, `:gun`)
Babel / Metro / bundler | BEAM bytecode replaces JS bundling; `mix mob.push` ships `.beam` directly

## How to use this matrix

- Starting a new app: scan the ❌ rows first to see what would need to be a plugin or worked around.
- Reporting a gap: if something here is wrong (mob has a capability I missed, or partial that's actually full), the doc is hand-maintained — please open a PR or flag it.
- Filling a gap as a plugin: see MOB_PLUGINS.md for the manifest spec. Most ❌ rows are plugin candidates (tier 1 or tier 2 depending on whether they ship UI).
- Filling a gap in core: when a capability is universal enough (every app needs it, both platforms support it cleanly) it's worth landing in core rather than as a plugin. The boundary is fuzzy; raising a discussion before doing the work is the right call.

This matrix isn't a roadmap commitment — it's a snapshot of reality. Some ❌ rows may stay ❌ for a long time because no one's asked. Others will land via community plugins. The intent is honest disclosure, not a promise of feature parity with React Native.

## Related docs

- `MOB_PLUGINS.md` — plugin manifest spec for filling missing capabilities without merging into core
- `RELEASE.md` — release process if you're shipping a new capability that lands in core
- `guides/styling.md` — visual styling for the components above (tokens, themes, dark mode)
- `guides/support_matrix.md` — minimum OS / ABI / SDK supported (a different "support matrix" — platform versions rather than capabilities)

← Previous Page Device Capabilities
Next Page → Permissions