# NativePHP Mobile v4 Documentation

## Getting Started

- [https://nativephp.com/docs/mobile/4/getting-started/introduction] Use these docs for an overview of NativePHP for Mobile: embeds a pre-compiled PHP runtime plus Laravel inside a Swift/Kotlin shell app with a custom PHP extension bridging native APIs (camera, biometrics, push notifications); renders truly native UI via EDGE Blade components (not a web view wrapper); runs fully on-device/offline with no web server; single codebase for iOS and Android with no Swift/Kotlin/Gradle/Xcode knowledge required
- [https://nativephp.com/docs/mobile/4/getting-started/quick-start] Use these docs for the fastest paths to a running app: Jump (no Xcode/Android Studio) via `laravel new my-app --using=nativephp/mobile-starter` or `composer require nativephp/mobile` then `php artisan native:jump` and scanning the QR code with the Jump app; local builds via `native:install` then `native:run`; the `native` script helper installed by `native:install` allowing `php native run` / `./native run`; Kitchen Sink demo apps on Play Store and TestFlight
- [https://nativephp.com/docs/mobile/4/getting-started/upgrade-guide] Use these docs for upgrading 3.x → 4.0: `nativephp/mobile` v4 declares Composer conflicts with `nativephp/mobile-device`/`-dialog`/`-file`/`-system` (now core built-ins) so remove them first via `php artisan native:plugin:uninstall --core-v4` (add `--force` to skip confirmation), per-plugin uninstalls, or plain `composer remove`; no app code changes — `Native\Mobile\Facades\{Device, Dialog, File, System}` facades and events (`ButtonPressed`, etc.) unchanged; Vite dev server now opt-in (`native:watch --vite`, `native:run --watch --vite`; drop redundant `--no-vite`); bump constraint to `~4.0.0`, run `composer update` and `php artisan native:install --force` to rebuild native project files; plugin authors widen constraint to `^3.0|^4.0`
- [https://nativephp.com/docs/mobile/4/getting-started/environment-setup] Use these docs for machine requirements: PHP 8.3+, Laravel 11+; iOS needs Apple silicon Mac (M1+), Xcode 16.0+, Command Line Tools, Homebrew + CocoaPods — Apple Developer Program ($99/yr) only needed for real devices/App Store/push, not Simulator; Android needs Android Studio 2024.2.1+, SDK API 29+, 7zip on Windows, possibly a separate JDK (check Gradle JDK compatibility matrix); set `JAVA_HOME`/`ANDROID_HOME` env vars; fixes for "No AVDs found"; real devices need iOS Developer Mode + registered device, or Android developer options + USB debugging
- [https://nativephp.com/docs/mobile/4/getting-started/installation] Use these docs for installing: `composer require nativephp/mobile` (no WSL support; add `C:\temp` and project folder to Windows Defender exclusions); set `NATIVEPHP_APP_ID=com.yourcompany.yourapp` (and optionally `NATIVEPHP_DEVELOPMENT_TEAM`) in `.env` BEFORE running `php artisan native:install`; installer prompts for ICU-enabled PHP binaries (needed for `intl` — required by Filament); creates the ephemeral `nativephp/` directory (add to `.gitignore`; rebuilt by `native:install --force` on upgrades) plus `config/nativephp.php`; test in the browser first, then `php artisan native:run`
- [https://nativephp.com/docs/mobile/4/getting-started/configuration] Use these docs for `config/nativephp.php` and env vars: `NATIVEPHP_APP_ID` (reverse-DNS bundle ID), `NATIVEPHP_APP_VERSION` (defaults to `DEBUG` which always re-extracts the app archive on boot) and `NATIVEPHP_APP_VERSION_CODE`; persistent runtime (`NATIVEPHP_RUNTIME_MODE=persistent|classic`, `reset_instances`, `gc_between_dispatches`; ~200-300ms → ~5-30ms per request); deep links (`NATIVEPHP_DEEPLINK_SCHEME`/`NATIVEPHP_DEEPLINK_HOST`); `NATIVEPHP_START_URL`; `cleanup_env_keys` / `cleanup_exclude_files`; per-device `orientation` array; `ipad => true` (irreversible once published); Android SDK levels (`NATIVEPHP_ANDROID_COMPILE_SDK=36`, `MIN_SDK=26`, `TARGET_SDK=36`); Android build flags (`NATIVEPHP_ANDROID_MINIFY_ENABLED`, `SHRINK_RESOURCES`, `OBFUSCATE`, `DEBUG_SYMBOLS=FULL`, `PARALLEL_BUILDS`, `INCREMENTAL_BUILDS`); `NATIVEPHP_ANDROID_STATUS_BAR_STYLE=auto|light|dark`; dev server ports (`NATIVEPHP_HTTP_PORT=3000`, `NATIVEPHP_WS_PORT=8081`); `hot_reload.watch_paths`/`exclude_patterns`; iOS-only `permissions` array overriding plugin-merged Info.plist usage strings; App Store Connect keys (`APP_STORE_API_KEY`, `APP_STORE_API_KEY_ID`, `APP_STORE_API_ISSUER_ID`, `APP_STORE_APP_NAME`) used by `native:package --upload-to-app-store`
- [https://nativephp.com/docs/mobile/4/getting-started/development] Use these docs for the dev workflow: platform checks via `System::isIos()`/`System::isAndroid()`; the `nativephpMobile` Vite plugin + `nativephpHotFile()` from `./vendor/nativephp/mobile/resources/js/vite-plugin.js` in `vite.config.js`, building assets with `npm run build -- --mode=ios|android`; Inertia 3 gotcha — must `npm install axios` since NativePHP intercepts axios at bundle time; `native:run` to compile, `native:open` for Xcode/Android Studio; hot reloading via `native:watch` (or `native:run --watch`), Vite HMR opt-in via `--vite` (supports npm/bun/pnpm/yarn); `hot_reload.watch_paths` config (keep `public` listed); run iOS and Android watchers simultaneously in two terminals on macOS; keep `NATIVEPHP_APP_VERSION=DEBUG` during development; gitignore `public/ios-hot` and `public/android-hot`; non-JS hot reload on real iOS devices not yet available; Laravel Boost supported via `php artisan boost:install`
- [https://nativephp.com/docs/mobile/4/getting-started/commands] Use these docs for the full `native:*` Artisan command reference: `native:install {platform?}` (`--force`/`--fresh`, `--with-icu`/`--without-icu` (~30MB), `--skip-php`); `native:run {os?} {udid?}` (`--build=debug|release|bundle`, `--watch`, `--vite`, `--start-url=`, `--no-tty`); `native:watch {platform?} {target?}` (`--vite`); `native:jump` (`--ip=`, `--http-port=` default 3000, `--ws-port=` 3001, `--bridge-port=` 3002, `--vite-proxy-port=` 3003, `--no-serve`, `--laravel-port=` 8000, `--no-mdns`); `native:open {os?}`; `native:tail` (Android-only log tail); `native:version`; `native:make {name}` / `native:rm {name?}` / `native:make-test {name}` for NativeComponent classes; `native:validate` (`--component=`); `native:debug` (`--json`); `native:emulator {os}`; `native:sim {target?}` (`data|app|uninstall`, `--bundle-id=`, macOS only); `native:package {platform}` (Android: `--keystore=`, `--key-alias=`, `--upload-to-play-store`, `--play-store-track=`; iOS: `--export-method=`, `--upload-to-app-store`, `--validate-profile`, `--api-key=`); `native:release {patch|minor|major}`; `native:credentials {platform?}` (`--reset`); `native:check-build-number`; plugin commands `native:plugin:create|list|register|uninstall|validate|make-hook|boost|install-agent`; `native-ui:generate-icons` (`--refresh-material`, `--output=` default `app/Icons`) generating `App\Icons\Ios`/`Android`/`AndroidOutlined` enums
- [https://nativephp.com/docs/mobile/4/getting-started/versioning] Use these docs for the package's semver policy: patch releases touch only Laravel/PHP code — safe `composer update`, no rebuild, no store resubmission; minor releases may change native (Kotlin/Swift) code — require `php artisan native:install --force` and store submission; major releases reserved for breaking changes; recommended constraint is a tilde range with full patch (e.g. `~4.0.0`); your own app versioning scheme is free-form
- [https://nativephp.com/docs/mobile/4/getting-started/support-policy] Use these docs for platform support: aims to support current vendor-supported major OS versions with the current major release prioritized — as of September 2025 that means iOS 18+ and Android 13+; not all features guaranteed across versions; backwards compatibility for older versions via the partner program
- [https://nativephp.com/docs/mobile/4/getting-started/changelog] Use these docs for the v4.0 "SuperNative" changelog: SwiftUI/Jetpack Compose native UI as the new default; Livewire-like `NativeComponent` PHP classes per screen; shared memory between PHP and native (no serialization); web view demoted to an opt-out component; `NativeLayout` classes for shared chrome; `Route::native()` navigation stack; in-process component testing suite; breaking changes: device/dialog/file/system plugins folded into core, Vite dev server opt-in via `--vite`
- [https://nativephp.com/docs/mobile/4/getting-started/contributing] Use these docs for contributing: fork/clone the mobile repo, branch, PR against `main`; focused changes, tests for new functionality, docs updates for public API changes; bug reports with repro steps; security vulnerabilities emailed privately to support@nativephp.com

## The Basics

- [https://nativephp.com/docs/mobile/4/the-basics/overview] Use these docs for how NativePHP Mobile is composed: your Laravel app, the `nativephp/mobile` Composer package, custom PHP 8.4 builds compiled as embeddable C libraries (fetched by `native:install`, embedded into the Swift/Kotlin app shells rather than run under a web server), and the `native:run` command that packages your app per platform; boot steps include installing newer bundles, running migrations, clearing caches, and creating storage symlinks
- [https://nativephp.com/docs/mobile/4/the-basics/native-ui] Use these docs for the fully native UI architecture (SwiftUI on iOS, Jetpack Compose on Android, driven by PHP): SuperNative is the engine where each screen is a PHP component class holding state and re-rendering on property changes; EDGE (Element Definition and Generation Engine) is the Blade component language under the `native:` namespace with hot-reload support; screens are organized via `Route::native()` routing and `NativeLayout` layouts
- [https://nativephp.com/docs/mobile/4/the-basics/routing] Use these docs for native stack navigation: register screens with `Route::native('/item/{id}', ItemDetail::class)`, read params with `$this->param('id')` and passed data with `$this->data('source', 'default')`; navigate with `$this->navigate('/item/42', [...])`, `$this->back()`, `$this->replace('/login')` (fade default), `$this->exitToWeb('/dashboard')`; override animations by chaining `->transition(Transition::SlideFromBottom)` (cases: SlideFromRight/SlideFromLeft/SlideFromBottom/Fade/FadeFromBottom/ScaleFromCenter/ParallaxPush/None); the `@navigate` Blade directive works on any node with transition modifiers (`@navigate.slideFromBottom="..."`) and action modifiers (`@navigate.back`, `@navigate.replace`, `@navigate.exitToWeb`, combinable like `@navigate.replace.fade`); `$this->route('name', [...])` resolves named routes; override `onBackPressed()` to customize the Android device back button; bottom-nav-item taps use replace semantics
- [https://nativephp.com/docs/mobile/4/the-basics/layouts] Use these docs for shared chrome via `NativeLayout` classes attached with `Route::native(...)->layout(...)` or `Route::nativeGroup(...)`: override `navBar()`/`tabBar()` returning fluent `NavBar` (title/subtitle/titleView/logo/back/backgroundColor/textColor/font/elevation/displayMode/scrollBehavior/searchBar/action), `NavAction` (per-platform icon, label, press, url, destructive, nested `items()` menus), `TabBar` (max 5 tabs, activeColor, labelVisibility, dark, minimizeOnScroll for iOS 26, highlight), and `Tab::link/action/search` (badge, news, active) builders; chrome fonts have three tiers (layout `$font`, per-bar `->font()`, per-screen `NavBarOptions::make()->font()`); `HasLayoutDrawer` + `Drawer::make(view(...))->width(320)->reveal()/->modal()` for side drawers with `InteractsWithDrawer`/`$hidesDrawer`/`drawerOverride()` per-screen overrides; inline `native:bottom-bar` or layout `bottomBar()` pins keyboard-aware bottom content (never add manual keyboard padding); `HasFloatingOverlay` + `FloatingOverlay::make(...)->offset(88)/->top()` floats a pill over every screen; per-screen `navigationOptions()` returning `NavBarOptions`, `$hidesNavBar`, `navTitle()`, imperative `$this->setNavBar([...])`/`setTabBar([...])`; `wrapWithChrome` picks safeAreaTop/safeAreaBottom/safeArea automatically — don't add `safe-area` under a layout
- [https://nativephp.com/docs/mobile/4/the-basics/events] Use these docs for listening to native events on a `NativeComponent`: annotate methods with `#[On(EventClass::class)]` (from `Native\Mobile\Attributes\On`) where parameters bind by name to the event's public properties; `#[On]` is repeatable and listeners auto-teardown on unmount; use fluent `$this->on(Event::class, Closure)` for runtime/conditional registration inside `mount()`; events originate device-side (Vibe websocket messages, push notification taps, bridge-call completions) and only fire while the screen is on the stack; tests can deliver events via `emitNative(Event::class, [...])`
- [https://nativephp.com/docs/mobile/4/the-basics/dialogs] Use these docs for the core built-in `Native\Mobile\Facades\Dialog` facade: `Dialog::alert('Confirm', 'Are you sure?', ['Cancel', 'Delete'])` shows a real UIAlertController/AlertDialog and returns a `PendingAlert`; buttons are plain strings or `['label' => 'Delete', 'style' => 'destructive']` arrays (styles `default`/`cancel`/`destructive` — destructive renders red, cancel gets the platform's dismiss treatment, both shapes mix freely) with fluent `->id()`, `->event()`, `->remember()` (read back via `PendingAlert::lastId()`), `->show()` (auto-shows on destruct), `->buttonPressed(Closure)` running on the live component, and `->on(class, Closure)`; handle taps via `#[On(ButtonPressed::class)]` with event properties `index` (0-based), `label`, `?id` bound by parameter name; `Dialog::toast('Item saved!')` shows a Snackbar (Android) / overlay (iOS) with `'long'` (~4s, default) or `'short'` (~2s) duration
- [https://nativephp.com/docs/mobile/4/the-basics/device] Use these docs for the core built-in `Native\Mobile\Facades\Device` facade: `Device::vibrate()` (bool, Android `VIBRATE` permission auto-merged), `Device::flashlight()` (returns `['success' => bool, 'state' => bool]`), `Device::getId()` (stable per-install id — `identifierForVendor` on iOS, `ANDROID_ID` on Android, `null` off-device), `Device::getInfo()` and `Device::getBatteryInfo()` (both return JSON strings needing `json_decode`; info fields include `platform`, `model`, `osVersion`, `language`, `isVirtual`, `memUsed`, `webViewVersion`; battery gives `batteryLevel` 0.0–1.0 and `isCharging`)
- [https://nativephp.com/docs/mobile/4/the-basics/file] Use these docs for the core built-in `Native\Mobile\Facades\File` facade: `File::move($from, $to)` and `File::copy($from, $to)` both return bool; parent directories auto-created, existing destinations overwritten, copy integrity verified, and Android falls back to copy+delete when a rename crosses file systems
- [https://nativephp.com/docs/mobile/4/the-basics/system] Use these docs for the core built-in `Native\Mobile\Facades\System` facade: platform detection via `System::isIos()` / `isAndroid()` / `isMobile()`, matching global helpers `isIos()`, `isAndroid()`, `isMobile()`, and Blade directives `@ios`, `@android`, `@mobile`, `@web` (with `@else…`/`@unless…` forms); `System::appSettings()` opens the app's page in device Settings for re-granting permissions; `System::flashlight()` is deprecated in favor of `Device::flashlight()`
- [https://nativephp.com/docs/mobile/4/the-basics/safe-area] Use these docs for safe-area insets around the notch/status bar and home indicator: classes `safe-area` (both edges), `safe-area-top`, `safe-area-bottom`, plus PHP equivalents `Column::make()->safeArea()/->safeAreaTop()/->safeAreaBottom()`; layouts' `wrapWithChrome` flow already applies the right variant (TabBar present → `safeAreaTop()`, NavBar only → `safeAreaBottom()`, no chrome → `safeArea()`, both bars → neither), so never stack `safe-area-bottom` inside a chrome-wrapped screen — reserve `safe-area*` for standalone chrome-less full-screen views
- [https://nativephp.com/docs/mobile/4/the-basics/positioning] Use these docs for CSS-style absolute positioning outside flex flow: classes `absolute`, `relative` (default), and `top-[N]`/`right-[N]`/`bottom-[N]`/`left-[N]` insets in dp; setting only `right-`/`bottom-` anchors to that edge, setting both `left-` and `right-` (or `top-` and `bottom-`) stretches between them; canonical FAB pattern is `class="absolute bottom-[20] right-[20] w-[56] h-[56]"` with `@tap`; gotcha: `native:stack` does not honor absolute children — use `native:row` or `native:column` as the positioned parent
- [https://nativephp.com/docs/mobile/4/the-basics/jump] Use these docs for the Jump companion app + `php artisan native:jump` dev loop: starts a PHP dev server (QR code page), `artisan serve`, and a WebSocket bridge that relays `nativephp_call()` to the phone; requires Jump v2+, same Wi-Fi, open ports 3000/3001/3002/3003; Vite HMR proxied automatically via port 3003; flags `--ip=`, `--no-mdns`, `--no-serve --laravel-port=8000` (export `JUMP_BRIDGE_PORT=3002` with your own server); bridge logs at `storage/logs/jump-bridge.log`; config under the `server` key in `config/nativephp.php`; comparison table for Jump vs `native:run`
- [https://nativephp.com/docs/mobile/4/the-basics/native-functions] Use these docs for calling native device APIs from PHP via plugin facades (`Native\Mobile\Facades\Biometrics`, `Browser`, `Camera`) with no web view required, plus the typed `Native` JavaScript library for legacy SPA/web-view use: add `"imports": { "#nativephp": "./vendor/nativephp/mobile/resources/dist/native.js" }` to package.json, then `import { On, Off, Microphone, Events } from '#nativephp'` and subscribe with `On(Events.Microphone.MicrophoneRecorded, cb)` / `Off(...)`
- [https://nativephp.com/docs/mobile/4/the-basics/app-icon] Use these docs for custom app icons: place a single 1024×1024 PNG with no transparency at `public/icon.png`; auto-resized for all Android densities and used as the base iOS icon; requires the GD PHP extension with ~2GB memory on the dev machine
- [https://nativephp.com/docs/mobile/4/the-basics/splash-screens] Use these docs for custom splash screens: place `public/splash.png` (Light Mode) and `public/splash-dark.png` (Dark Mode), PNG format at minimum 1080×1920 pixels, with the GD PHP extension enabled (~2GB memory)
- [https://nativephp.com/docs/mobile/4/the-basics/assets] Use these docs for bundling assets: run `npm run build` before `php artisan native:run` when the app ships web-view JS/CSS; all files from the Laravel root are included and must be accessed with relative paths via Laravel's path helpers; user-generated/persistent files live outside `public` and are symlinked, accessed via `Storage::disk('mobile_public')->url('user_content.jpg')`; pro tip: set `FILESYSTEM_DISK=mobile_public` in `.env` for mobile builds

## EDGE Components (Native UI)

- [https://nativephp.com/docs/mobile/4/edge-components/introduction] Use these docs for the EDGE (Element Definition and Generation Engine) overview: Blade tags like `native:button` compile at runtime to a binary config rendered by native code (SwiftUI/Material3) outside the web view; full component catalog (layout, content, forms, navigation, lists, overlays, drawing); the `native:` prefix is optional (`<column>` works); required-props validation errors at render time; Inertia apps must set `window.router` to convert link postbacks
- [https://nativephp.com/docs/mobile/4/edge-components/layout] Use these docs for shared layout/style/event attributes on every EDGE element: sizing (`width`/`height` dp or `"50%"`, `fill`, `fill-width`, `min-/max-*`, `aspect-ratio`), `:padding`/`:margin` (scalar or 2-4 value CSS-shorthand arrays), `gap`, flex (`flex-grow/shrink/basis`), alignment, `center`, style attrs (`bg`, `border-radius`, `border-width`+`border-color`, `opacity`, `elevation`), events `@tap`/`@doubleTap`/`@longPress`, `safe-area(-top/-bottom)`, `hidden`, and the canonical Tailwind class parser: full supported-class table plus `dark:`/`ios:`/`android:` variants, `/N` alpha suffixes, arbitrary `prefix-[value]`, and `glass`/`glass:prominent/interactive/clear` Liquid Glass classes; `w-full` on a child overrides parent `items-center` (stretch semantics)
- [https://nativephp.com/docs/mobile/4/edge-components/column] Use these docs for `native:column`, the vertical flex container (mobile `<div>` equivalent): `gap-N` = vertical child spacing, `items-*` = horizontal cross-axis alignment, `justify-*` = vertical main-axis distribution (`between/around/evenly` need bounded height), `flex-1`, `safe-area`/`safe-area-top`/`safe-area-bottom` at page root; inherits all shared Tailwind classes; PHP `Column::make(...)->fill()->padding()->gap()`
- [https://nativephp.com/docs/mobile/4/edge-components/row] Use these docs for `native:row`, a horizontal flex container: `gap-N` (horizontal spacing), `items-*` (vertical cross-axis alignment incl. `items-stretch`), `justify-*` (`justify-between/around/evenly` etc.), `flex-1`, plus the full shared class set; pairs with `native:spacer` for toolbars; PHP `Row::make(...)->gap()->alignItems()`
- [https://nativephp.com/docs/mobile/4/edge-components/stack] Use these docs for `native:stack`, a z-layering overlay container (SwiftUI ZStack / Compose Box) — first child at bottom, later children on top, each placed at natural size and centered; give children `w-full`/`h-full` to fill; used for badges and image overlays (`bg-black/40` caption layers); for corner-anchored dots use a `relative` column + `absolute bottom-[0] right-[0]` child instead; PHP `Stack::make(...)->width()->height()`
- [https://nativephp.com/docs/mobile/4/edge-components/scroll-view] Use these docs for `native:scroll-view` (Android LazyColumn/LazyRow, iOS ScrollView): `axis` = `vertical` (default) / `horizontal` / `both` (2D pan; inner content needs explicit larger dimensions), `shows-indicators` (effectively iOS-only), `scroll-anchor="bottom"` for chat-style stick-to-bottom; typically wraps one column/row with width-fill on both; PHP `ScrollView::make()->horizontal()/both()/showsIndicators()/autoScrollTo($index)`
- [https://nativephp.com/docs/mobile/4/edge-components/spacer] Use these docs for `native:spacer`, a self-closing flexible gap with automatic `flex-grow: 1` that claims leftover main-axis space inside rows/columns (does nothing in a non-flex stack); fixed-size spacers need `flex-grow-0` alongside `h-8`/`w-N` or the default grow wins; classic uses: push content to bottom, right-align toolbar icons; PHP `Spacer::make()->height(8)->flexGrow(0)`
- [https://nativephp.com/docs/mobile/4/edge-components/pressable] Use these docs for `native:pressable`, a tappable column-like container wrapping multiple children, with `@tap`, `@longPress`, `@doubleTap` (handlers can interpolate args like `selectItem({{ $id }})`), `@navigate` for view-only routing, `:menu` (shadows `@tap`), and native-thread press feedback props `:press-scale`, `:press-opacity`, `:press-translate-y`; PHP `Pressable::make(...$children)->onPress()`
- [https://nativephp.com/docs/mobile/4/edge-components/text] Use these docs for `native:text` (content between tags): props `font-size`, `font-weight` 1–7, `color` hex, `text-align`, `max-lines` (ellipsis), `underline`, `line-through`, `text-transform`, `letter-spacing`, and `font` for custom fonts from `resources/fonts/` (filename sans extension; `php artisan native:font` downloads Google Fonts; app-wide default via the fonts `default` alias in config/native-ui.php (legacy `font-family` token still honored); avoid `font-bold` on single-weight files); Tailwind: `leading-*` line height (iOS can't tighten below natural), `italic`, `underline`, `uppercase`, `tracking-*`, `font-serif`/`font-mono`, `dark:*`; nested `native:text` = inline styled runs in one attributed string; `select-text`/`select-none` scope long-press selection; `content-transition="numeric"` animates in-place text changes as rolling counter digits (iOS numericText; Android directional slide+fade — `opacity` crossfades, tune with `animate-duration`/`animate-easing`); supports `@tap`
- [https://nativephp.com/docs/mobile/4/edge-components/text-input] Use these docs for the three self-closing input variants `native:outlined-text-input`, `native:filled-text-input` (theme-only chrome), and chromeless `native:bare-text-input` (class styling passes through — `bg`, `rounded-*`, `glass`, borders); shared props: `value`, `placeholder`, `label`, `supporting`, `disabled`, `read-only`, `is-error`, `loading`, `keyboard` (`text|number|email|phone|url|decimal|password|numberPassword`), `secure`, `multiline` + `min-lines`/`max-lines`, `max-length`, `keep-focus-on-submit`, `prefix`/`suffix`, `leading-icon`/`trailing-icon`, `font`, `size` (sm/md/lg), `sync-mode`/`debounce-ms`; events `@change` and `@submit`; `native:model` with `.live`/`.blur`/`.debounce.500ms` modifiers; pin composers in a `native:bottom-bar` for keyboard visibility
- [https://nativephp.com/docs/mobile/4/edge-components/button] Use these docs for `native:button` with `label` (or plain-text slot content), `variant` (`primary|secondary|destructive|ghost`), `size` (`sm|md|lg`), `icon`/`icon-trailing`, `font`, `disabled`, `loading` (spinner replaces leading icon, blocks presses), `menu` (NavAction array opens dropdown instead of firing press), and `@tap`; no per-instance color/bg/border/radius overrides — theme only, drop to `native:pressable` for full control; layout attrs (width, margin, flex-grow) pass through; PHP `Button::make()->variant()->onPress()` with `ios:`/`android:` icon args
- [https://nativephp.com/docs/mobile/4/edge-components/button-group] Use these docs for `native:button-group`, a segmented single-choice selector where the active pill fills `theme.primary`: required `:options` string array, `value`/`selected-index` (default 0), `disabled`, `sync-mode` (`live|blur|debounce`), `@change` receiving the new index, and two-way `native:model` binding to a public int property; prefer `native:tab-row` or `native:select` for many/long options
- [https://nativephp.com/docs/mobile/4/edge-components/toggle] Use these docs for `native:toggle`, a self-closing on/off switch (SwiftUI Toggle / Material3 Switch): props `value` (bool), `label` (inline, left of switch), `disabled`, `a11y-label`/`a11y-hint`; `@change` receives the new boolean; `native:model` two-way binds; colors always theme.primary/onPrimary — per-instance `bg`/`border-*`/`opacity` are dropped
- [https://nativephp.com/docs/mobile/4/edge-components/checkbox] Use these docs for `native:checkbox` (SF Symbol pair on iOS, Material3 Checkbox on Android): `value` boolean, inline `label`, `disabled`, `sync-mode` + `debounce-ms`, `@change` receiving the new boolean, and `native:model` two-way binding to a public bool property; colors are theme-only, margin classes position it
- [https://nativephp.com/docs/mobile/4/edge-components/radio-group] Use these docs for `native:radio-group` single-choice container with `native:radio` children (each: required unique `value`, `label`, `disabled`); group props `value`, `label`, `disabled`; `@change` receives the new value; `native:model` two-way binds the selected value string; PHP `RadioGroup::make(...Radio::make($value)->label())->value()->onChange()`
- [https://nativephp.com/docs/mobile/4/edge-components/select] Use these docs for `native:select`, a single-choice dropdown over flat option strings (iOS SwiftUI Menu popover, Android M3 ExposedDropdownMenuBox): required `:options` array (associative arrays flatten to labels — the displayed string IS the bound value), `value`, `label`, `placeholder` (shows while null), `disabled`; `@change` receives the chosen string; `native:model` two-way binds; colors/borders come from theme
- [https://nativephp.com/docs/mobile/4/edge-components/slider] Use these docs for `native:slider`: `:min` (default 0), `:max` (default 1), `:step` (0 = continuous), `value`, `disabled`; `@change` receives the new float; `native:model` with `.live` (every drag tick, default), `.blur` (release only), `.debounce.300ms` modifiers controls PHP round-trip frequency; track/thumb always theme.primary — no color overrides
- [https://nativephp.com/docs/mobile/4/edge-components/chip] Use these docs for `native:chip`, a compact selectable capsule tag: `label`, `selected`/`value` boolean, leading `icon`, `disabled`, `@change` with new boolean, `native:model` binding to a public bool; selected fills theme.primary, unselected uses theme.surfaceVariant with outline stroke; radius adjustable via `rounded-*`; single-select rows drive `:selected` from one string property with `@change="setFilter('all')"`
- [https://nativephp.com/docs/mobile/4/edge-components/icon] Use these docs for `native:icon` (SF Symbols on iOS, Material Icons on Android): `name` with four-tier resolution (dotted names like `car.side.fill` are direct iOS-only SF paths; Material ligatures like `shopping_cart` work directly on Android; manual mappings e.g. `home`→`house.fill`; smart + circle fallback), `ios`/`android` per-platform overrides (also typed enums `App\Icons\Ios`/`Android`/`AndroidOutlined` via `php artisan native-ui:generate-icons`), `:size` (dp, default 24), `color`/`dark-color` hex, `a11y-label` (decorative/hidden without it); includes the cross-platform icon-name reference table; same names work in any component's `icon` attribute
- [https://nativephp.com/docs/mobile/4/edge-components/image] Use these docs for `native:image` (async-loaded: AsyncImage on iOS, Coil on Android): required `src` URL, `:fit` int (0/1 = fit within bounds, 2/3 = fill/crop), `tint-color` hex (needs alpha-channel assets), `alt` for accessibility (omitted = decorative, hidden from VoiceOver/TalkBack); round avatars with `rounded-full` class; PHP `Image::make($src)->fit(2)->tintColor()`
- [https://nativephp.com/docs/mobile/4/edge-components/divider] Use these docs for `native:divider`, a self-closing always-1pt horizontal rule colored by `border-*` classes (`border-theme-outline`, `border-[#hex]`, `dark:border-*`) else the platform separator color; supports `opacity-*` and margin classes; for thicker rules use a column with `h-1 bg-theme-outline`
- [https://nativephp.com/docs/mobile/4/edge-components/activity-indicator] Use these docs for `native:activity-indicator`, a self-closing indeterminate spinner (SwiftUI ProgressView / Material3 CircularProgressIndicator): props `size` (`sm|md|lg`), `color` hex overriding the default theme.primary tint, `a11y-label`/`a11y-hint`; use `native:progress-bar` for determinate progress
- [https://nativephp.com/docs/mobile/4/edge-components/progress-bar] Use these docs for `native:progress-bar`, a self-closing linear indicator: `:value` (float 0.0–1.0, determinate), `indeterminate` (animated wave, default when no value), hex overrides `color` (fill, both platforms) and `track-color` (Android-only); defaults fill=theme.primary, track=theme.surfaceVariant
- [https://nativephp.com/docs/mobile/4/edge-components/badge] Use these docs for `native:badge`, a self-closing capsule pill with `count` (renders `99+` above 99), `label` (wins over count), `variant` (`destructive` default, `primary`, `accent`), `a11y-label`/`a11y-hint`; anchor over icons via a stack with `absolute top-px right-px` (positive insets only); `bg-*`/`rounded-*` class overrides are iOS-only
- [https://nativephp.com/docs/mobile/4/edge-components/list] Use these docs for `native:list` (SwiftUI List / Compose LazyColumn) with `separator`, `horizontal`, `shows-indicators` [iOS], `plain` (opt out of the auto inset-grouped style triggered by `native:list-section` children with header/footer), `on-refresh` pull-to-refresh [iOS: must be the screen's scroll container] and `on-end-reached` infinite scroll; plus `native:list-item`: `headline` (required)/`supporting`/`overline`, mutually-exclusive leading slot (`leadingIcon`, `leadingAvatar`, `leadingMonogram`+color, `leadingImage`, `leadingCheckbox`/`leadingRadio` interactive via `on-leading-change`), trailing slot (`trailingIcon`, `trailingText`, `trailingCheckbox`, `trailingSwitch` [Android], `trailingIconButton`+`trailing-a11y-label`, `trailing-menu`, stackable `trailing-badges`), color override props (`headlineColor`, `containerColor`, etc.), `@tap`/`@longPress`, `on-swipe-delete`, and `leading-actions`/`trailing-actions` swipe arrays (`method`, `label`, `ios`/`android` icons, `tint`, `role: destructive`) which only work on direct children of a list/section
- [https://nativephp.com/docs/mobile/4/edge-components/lazy-grid] Use these docs for `native:lazy-grid`, a self-scrolling virtualized grid (SwiftUI LazyVGrid / Compose LazyVerticalGrid) for ~50+ cells: `:columns` (default 2; becomes fixed row count when `horizontal` flips to LazyHGrid), `:gap` dp applied to both axes, each child = one cell filling column width at intrinsic height; Android caveat — nested inside another scroll container it falls back to a non-lazy chunked grid, so give it bounded height to keep virtualization
- [https://nativephp.com/docs/mobile/4/edge-components/virtual-list] Use these docs for `native:virtual-list`, a self-closing windowed list that emits only the visible slice of huge collections: props `:count` (required total), `:from`/`:to` (window bounds, default 0–29), `item` (required Blade view name rendered per index, receives `['index' => $i]`), `on-window-change` (method called with `(int $from, int $to)`), `estimated-row-height` (default 56dp), `overscan` (default 30); pair with the `HasVirtualListWindow` trait supplying `$virtualWindowFrom`/`$virtualWindowTo` and `setVirtualWindow()`; one virtual list per screen; use plain `native:list` for small collections
- [https://nativephp.com/docs/mobile/4/edge-components/carousel] Use these docs for `native:carousel`, a horizontal paging lazy stack: `:item-width` (dp, default 200), `:item-spacing` (dp, default 8); children are auto-clipped to rounded rects (16pt iOS, ~28dp Android); use scroll-view + row for custom snapping/indicators/vertical paging
- [https://nativephp.com/docs/mobile/4/edge-components/refreshable] Use these docs for `native:refreshable`, a standalone scrolling container with native pull-to-refresh (iOS SwiftUI `.refreshable` with haptics, Android PullToRefreshBox): `@refresh` names the component method, spinner shows a ~800ms minimum window and dismisses itself (no "done" call); children ARE the scroll content — never nest a scroll-view or another refreshable; for row lists prefer `native:list`'s built-in `on-refresh`
- [https://nativephp.com/docs/mobile/4/edge-components/modal] Use these docs for `native:modal`, a full-screen overlay driven by required boolean `visible`, with `dismissible` (default true, adds close icon + swipe-to-dismiss), `a11y-label`/`a11y-hint`, and `@dismiss` (fires only on user close/swipe, not programmatic hide — always sync `visible` there); accepts any EDGE children
- [https://nativephp.com/docs/mobile/4/edge-components/bottom-sheet] Use these docs for `native:bottom-sheet` (SwiftUI `.sheet` with presentationDetents / Material3 ModalBottomSheet): required boolean `visible`, `detents` (default `"medium,large"`; `small`=25%, `medium`, `large`, `full`, or fraction like `"0.4"`), `@dismiss` event (always handle it or `visible` desyncs after gesture dismissal); container color is theme.surface — wrap children in a `bg-*` column for custom surfaces
- [https://nativephp.com/docs/mobile/4/edge-components/menus] Use these docs for attaching tap-to-open dropdown menus (SwiftUI Menu / Compose DropdownMenu) via `:menu` on button/pressable (shadows `@tap`), `:trailing-menu` on list-item, or `items()` on nav-bar actions; items are `NavAction::make($id)` arrays with `icon()` (per-platform `ios:`/`android:`), `label()`, `press()`, `url()`, `a11yLabel()`, `destructive()`, and `NavAction::divider()`; menus work only on nav-bar actions — bottom-nav/tab-bar items and inline top-bar ignore `items()`
- [https://nativephp.com/docs/mobile/4/edge-components/tab-row] Use these docs for `native:tab-row`, an in-screen horizontal tab strip with underline indicator (scrollable on overflow; distinct from bottom-nav routing chrome): props `value`/`selected-index` (int, default 0); `@change` receives the new index; `native:model` binds the selected index to a public int property; children `native:tab` with required `label`, optional `icon`, `a11y-label`; active tab/underline use theme.primary
- [https://nativephp.com/docs/mobile/4/edge-components/bottom-nav] Use these docs for `native:bottom-nav` (inline element; the `TabBar`/`Tab` builders in a NativeLayout class are preferred) with props `label-visibility` (`labeled|selected|unlabeled`), `dark`, `active-color`, `background-color`, `text-color`; up to 5 `native:bottom-nav-item` children requiring `id`, `icon`, `label`, `url` plus `active`, `badge`, `news` (mutually exclusive with badge); taps use replace semantics; bar self-handles bottom safe area; per-screen `tabBarOptions()` returning `TabBarOptions::make()->hidden()->highlight()` or `protected bool $hidesTabBar = true`
- [https://nativephp.com/docs/mobile/4/edge-components/top-bar] Use these docs for the inline `native:top-bar` (deprecated in favor of the Layout model's `NavBar` builder): props `title` (required), `subtitle`, `show-navigation-icon`, `background-color`, `text-color`, `elevation` (renders as a bottom hairline); up to 10 `native:top-bar-action` children (`id`, `icon` required, `label`, `url`) with overflow menus after 3 icons on Android / 5 on iOS; also covers `NavBar`/`NavAction` builders and per-screen `navigationOptions(): NavBarOptions` — `hidden()` (or `protected bool $hidesNavBar = true`) for full-bleed screens, `displayMode` (`large`/`inline`/`automatic`), `scrollBehavior` (`collapse`/`pinned`/`enterAlways`), `searchBar($placeholder, $onQuery, $debounceMs)`; hidden-bar iOS caveat: edge-swipe-back stops working, render your own back control
- [https://nativephp.com/docs/mobile/4/edge-components/side-nav] Use these docs for the inline `native:side-nav` slide-out drawer (deprecated in favor of the Layout model's `Drawer` builder): props `gestures-enabled` (Android; iOS always gesture-enabled), `dark`; children `native:side-nav-header` (title, subtitle, icon, background-color, show-close-button [Android], pinned), `native:side-nav-item` (required id/label/icon/url, plus open-in-browser, active, badge, badge-color), `native:side-nav-group` (heading, expanded, icon), `native:horizontal-divider`
- [https://nativephp.com/docs/mobile/4/edge-components/gesture-area] Use these docs for `native:gesture-area`, which captures a vertical pan/drag over its children and writes the translation into a required `:pan-y` `SharedValue` (`\Native\Mobile\Edge\SharedValue::make()`); bind that value to animatable child props (`translate-y`, `opacity`, `scale`) so drags drive animation entirely on the UI thread with no PHP round-trip
- [https://nativephp.com/docs/mobile/4/edge-components/canvas] Use these docs for `native:canvas`, a drawing surface for shape primitives that lays out like a column (use `native:stack` for overlay layering); shapes fill from `bg` attribute or `bg-*`/`bg-theme-*` classes and round via `rounded-*`; examples include bar charts from bottom-aligned rects with `opacity-*` ramps and pulsing beacons via `:scale` + `animate-loop` + `:animate-duration` (ms) + `animate-easing`
- [https://nativephp.com/docs/mobile/4/edge-components/shapes] Use these docs for shape primitives `native:rect`, `native:circle` (default border-radius 9999; equal width/height for perfect circle), and `native:line`; rect/circle take `:width`/`:height`/`bg` + Tailwind `rounded-*`/`border-*`/`opacity-*`/`shadow-*`; `left`/`top` props are NOT read by renderers — use `class="absolute top-[8] left-[8]"` or a stack; on iOS line draws a fixed 100pt stroke, so prefer `native:divider` for full-width rules
- [https://nativephp.com/docs/mobile/4/edge-components/web-view] Use these docs for `native:web-view` (legacy escape hatch) and full-screen web-view surface behavior: viewport meta tag with `user-scalable=no` and `viewport-fit=cover` for edge-to-edge; safe-area CSS variables `--inset-top/bottom/left/right` and the `nativephp-safe-area` class; Android status-bar icon color via `nativephp.status_bar_style` config (`auto`/`light`/`dark`); automatic `keyboard-visible` class toggled on `<body>`; Android WebView compatibility caveat — Tailwind v4's `@theme` breaks on older WebViews, consider Tailwind v3 for low `min_sdk`

## Digging Deeper

- [https://nativephp.com/docs/mobile/4/digging-deeper/data-binding] Use these docs for `native:model` two-way binding of native inputs to public component properties (the native wire:model equivalent); supported controls: text-input (string), toggle/checkbox (bool), slider (float), radio-group/select (string), chip/button-group (selection), tab-row (int active index); sync modifiers `native:model.blur`, `.lazy` (alias for blur), `.debounce.300ms`, default `.live` on every change; changes fire `updated{Property}()` and invalidate all `#[Computed]` values; unbound alternative is `:value="$name"` + `@change="rename"`
- [https://nativephp.com/docs/mobile/4/digging-deeper/reactivity] Use these docs for `#[Computed]` (Native\Mobile\Attributes\Computed) memoized derived properties read as `$this->total` (no parentheses) or `{{ $this->total }}` in Blade, with cache cleared on any state change and `#[Computed(persist: true)]` to survive re-renders; `#[Poll]` (default 2000ms, e.g. `#[Poll(5000)]`) on a method runs it then re-renders, on a class just re-renders on interval; Blade-side `native:poll` forms: bare (2s default), `native:poll="500ms"`/`"1s"`, or modifier `native:poll.2s`
- [https://nativephp.com/docs/mobile/4/digging-deeper/lifecycle-hooks] Use these docs for NativeComponent screen lifecycle: `mount()` runs once on push (read route params via `$this->param('id')`), `onResume()` on return from a popped child screen, `onBackPressed()` intercepts hardware back (call `$this->back()` to leave), `unmount()` for cleanup on stack removal (call `parent::unmount()`); `updated{Property}()` hooks fire on model-bound changes; `#[Lazy]` (Native\Mobile\Attributes\Lazy) paints a `placeholder()` immediately while `mount()` runs in background; related attributes `#[Computed]`, `#[On]`, `#[Poll]`, `onSearchQuery(string $query)`
- [https://nativephp.com/docs/mobile/4/digging-deeper/gestures] Use these docs for UI-thread animation via `SharedValue::make($initial)` (Native\Mobile\Edge\SharedValue) bound to `native:gesture-area` `:pan-y`, with chainable formulas `->interpolate([$inMin,$inMax],[$outMin,$outMax])` (clamping), `->clamp()`, `->multiply()`, `->add()`, PHP snapshot via `->value()`; animatable props accepting shared values: `translate-x`, `translate-y`, `scale`, `rotate`, `opacity`; property animations via `animate-duration` (ms), `animate-easing` (`linear`/`ease-in`/`ease-out`/`ease-in-out`), `animate-loop`; instant press feedback with `press-scale`, `press-opacity`, `press-translate-y` (no PHP round-trip)
- [https://nativephp.com/docs/mobile/4/digging-deeper/theming] Use these docs for theme tokens in `config/native-ui.php` (publish via `php artisan vendor:publish --tag=native-ui-config`, provided by the `nativephp/native-ui` plugin): paired tokens `primary/on-primary`, `secondary`, `surface`, `background`, `surface-variant`, `outline`, `destructive`, `accent`, plus `radius-sm|md|lg|full`, `font-sm|md|lg|xl`, and the fonts `default` alias for the app-wide face (legacy `font-family` token still honored); color formats hex, `#RRGGBBAA` alpha, Tailwind palette names (`red-300`), named colors, `/opacity` modifiers; Blade classes `bg-theme-surface`/`text-theme-on-surface`/`border-theme-outline`; dark block auto-derived from light by luminance inversion; PHP reads via `System::appearance()`, `System::isDarkMode()`, helpers `isDark()`/`isLight()`, `theme('primary', $fallback)`; `AppearanceChanged` event with `#[On]`; runtime tenant theming with `Theme::merge()`/`Theme::reset()`; keep `on-*` colors at 4.5:1 WCAG AA
- [https://nativephp.com/docs/mobile/4/digging-deeper/search] Use these docs for native search bars: override `searchItems(): ?array` for a static on-device-filtered corpus (return `null` to omit search) or `onSearchQuery(string $query): array` for dynamic DB/network results (input is debounced natively); show the bar via `NavBar::make()->searchBar(placeholder: '...', debounceMs: 300)` on a stack layout or `Tab::search('Search', icon: 'magnifyingglass', placeholder: '...')` as a tab; testable with `->search('query')` and `->searchResults()`
- [https://nativephp.com/docs/mobile/4/digging-deeper/accessibility] Use these docs for `a11y-label` and `a11y-hint` attributes on every element (fluent PHP `a11yLabel()`/`a11yHint()`); icon-only buttons/chips/tabs must get `a11y-label`; standalone icons are decorative by default; images use `alt`; list items take `trailing-a11y-label`; `NavAction::make(...)->a11yLabel(...)` for top-bar actions; free platform behavior: Dynamic Type/font scaling, 44pt iOS / 48dp Android touch targets, Reduce Motion (iOS), WCAG AA 4.5:1 default palette; audit all screens with `Native::visit($uri)->assertAccessible()` iterating `NativeRouter::registeredRoutes()`
- [https://nativephp.com/docs/mobile/4/digging-deeper/websockets] Use these docs for the free Vibe plugin (`composer require nativephp/mobile-vibe` + `php artisan native:plugin:register nativephp/mobile-vibe` + `native:run`): Pusher-protocol client working with Vask, Laravel Reverb, or Pusher; config via `PUSHER_APP_KEY`/`PUSHER_HOST`/`PUSHER_PORT`/`PUSHER_SCHEME` and `VIBE_AUTH_ENDPOINT` (app secret never ships to device); `Vibe::channel()`, `Vibe::private()` (auto `private-` prefix), `Vibe::presence()` (auto `presence-`, `->here()`/`->joining()`/`->leaving()`), `Vibe::subscribe()` (full name), all returning `PendingSubscription` with `->on($event, $callback)`; `Vibe::resolveTokenUsing(fn () => SecureStorage::get('api_token'))` once in `AppServiceProvider::boot()`; `#[OnEcho('OrderShipped')]` (Nativephp\Vibe\Attributes\OnEcho) binds payload fields to method params by name; subscribe in `mount()`, auto-teardown on unmount; foreground-only (OS suspends socket in background — use push notifications instead); set `protected bool $forceFullFrames = true;` for high-frequency live lists
- [https://nativephp.com/docs/mobile/4/digging-deeper/push-notifications] Use these docs for push notifications via Firebase Cloud Messaging (FCM routes through APNS automatically — no separate APNS setup): place `google-services.json` (Android) and `GoogleService-Info.plist` (iOS) in the app root; download a service account key as `fcm-service-account.json` for server-side sending; request tokens with `PushNotifications::getToken()`, which fires `TokenGenerated` (Native\Mobile\Events\PushNotification\TokenGenerated); push does not work in the iOS Simulator — physical device required
- [https://nativephp.com/docs/mobile/4/digging-deeper/queues] Use these docs for the background queue worker: set `QUEUE_CONNECTION=database` in `.env` and NativePHP auto-starts a dedicated thread-safe PHP runtime on a separate thread polling `queue:work --once`; standard `SyncData::dispatch($payload)` works; only the `database` connection (same SQLite DB) is supported; jobs persist across app restarts; Laravel retry/failure handling applies; no supervisor setup needed; works on both iOS and Android
- [https://nativephp.com/docs/mobile/4/digging-deeper/databases] Use these docs for SQLite (the only supported driver — MySQL/Postgres deliberately unsupported to prevent embedded credentials): NativePHP auto-switches to SQLite at build, creates the DB in the app container, and runs migrations on every app start as needed; use migrations for data seeding (run-once, tracked, versioned, reversible); databases are deleted with the app; API-first sync recommended with tokens in `SecureStorage`
- [https://nativephp.com/docs/mobile/4/digging-deeper/authentication] Use these docs for mobile auth patterns: token-based auth (short-lived auth token + longer 30-day refresh token) stored in secure storage — token existence alone is not proof of authentication; Laravel Sanctum tokens don't expire by default (enable expiration); OAuth flows should use `Browser::auth('https://...?redirect=myapp://auth/handle')` with `NATIVEPHP_DEEPLINK_SCHEME=myapp` in `.env`; check connectivity first via `Network::status()`; protect the auth endpoint with rate limiting
- [https://nativephp.com/docs/mobile/4/digging-deeper/security] Use these docs for mobile security practices: treat the device environment as hostile, use OAuth2 with expiring (<48h) tokens, always HTTPS; `SecureStorage` facade stores small (few KB) data in device Keystore/Keychain, persisted beyond app lifetime; NativePHP generates a unique per-device `APP_KEY` stored in secure storage so `Crypt::encryptString()`/`decryptString()` work for larger data at rest; caution: Crypt-encrypted data is unrecoverable off-device
- [https://nativephp.com/docs/mobile/4/digging-deeper/deep-links] Use these docs for deep linking via Custom URL Schemes (`NATIVEPHP_DEEPLINK_SCHEME=myapp` → `myapp://some/path`; only works if the app is installed) and Associated Domains / Universal Links / App Links (`NATIVEPHP_DEEPLINK_HOST=example.net`; requires hosting `.well-known/apple-app-site-association` for iOS and `.well-known/assetlinks.json` for Android); both can coexist; Associated Domains usually don't work in simulators — test on real devices, and delete/reinstall the app since registration failures are cached

## Architecture

- [https://nativephp.com/docs/mobile/4/architecture/super-native] Use these docs for the SuperNative introduction: PHP-driven platform-native UI (SwiftUI on iOS, Jetpack Compose on Android) via shared memory, Livewire-like component classes, and EDGE Blade components — the default in v4, no web view needed; what it is NOT (not Skia/Impeller pixel-perfect rendering, not a VM, not an HTML-to-native transpiler — Blade compiles to a fixed-length binary format); opting back into web-view-only apps via `Route::native()` to a screen containing a fullscreen webview element plus `NATIVEPHP_START_URL=/home` in `.env`; plugin architecture has no breaking changes and plugins can ship native EDGE components
- [https://nativephp.com/docs/mobile/4/architecture/about-the-new-architecture] Use these docs for why the new architecture exists: truly native rendering (a `native:button` is a real platform button, not a styled div — accessibility, theming, dark mode free), shared memory instead of JSON serialization across a bridge (PHP writes a compact binary screen description into a buffer the native side reads in-process, state changes reach screen in under a frame), SharedValues updated on the UI thread at full frame rate for gestures/animations; SuperNative is the default (beta) and the web view remains available for screen-by-screen migration
- [https://nativephp.com/docs/mobile/4/architecture/renderer] Use these docs for the renderer's three layers — the Element Runtime (native code inside the PHP runtime encoding Element Trees into binary frames in shared memory), the native readers (Swift/Kotlin frame decode + diff), and the platform renderers (SwiftUI/Compose) — and its design goals: zero serialization in one process, native flexbox built on each platform's own Layout protocol (no third-party layout engine, so safe areas/dynamic type/keyboard avoidance work natively), identical-frame skipping and subtree reuse, a versioned type-safe wire format that fails loudly on mismatch, and PHP-free interactions via SharedValues
- [https://nativephp.com/docs/mobile/4/architecture/render-publish-mount] Use these docs for the three-phase render pipeline: Render (component `render()` builds the Element Tree; utility classes like `p-4`/`text-2xl` parsed to concrete values; `@tap="refresh"` handlers replaced with stable callback IDs), Publish (Element Runtime writes fixed-layout binary nodes to shared memory, skips byte-identical frames, replaces unchanged subtrees with reuse markers), Mount (reader thread decodes and diffs, main thread re-renders only changed views keeping identity/state/animations); native-side state (scroll, drag, SharedValue animations) updates on the UI thread per-frame without consulting PHP
- [https://nativephp.com/docs/mobile/4/architecture/cross-platform-implementation] Use these docs for how one Blade template renders identically on both platforms: a single shared C core compiled into the PHP runtime handles tree walking, the binary node format, skip-and-reuse logic, and the event channel, with thin per-platform readers/renderers written as mirrors; flexbox implemented natively per platform (pure-Swift Layout on iOS, Compose Layout on Android) with iOS as the visual reference implementation; the two independent seams — binary shared-memory rendering vs JSON-in/JSON-out bridge functions for device APIs and plugins; explicit wire-format version checked at startup
- [https://nativephp.com/docs/mobile/4/architecture/subtree-reuse] Use these docs for the three automatic reuse layers: whole-frame skip (byte-for-byte comparison drops identical frames), subtree reuse markers (per-element content-hash fingerprints let unchanged subtrees publish as a single tiny marker), and mount-time diffing (views that survive keep identity, scroll position, focus, running animations); keying dynamic lists with `:native:key="$message->id"` so an inserted item reads as one new card instead of every card changed; periodic forced full frames after navigation, reset, or hot reload
- [https://nativephp.com/docs/mobile/4/architecture/threading-model] Use these docs for the three-thread model: the singular PHP thread hosting the persistent runtime (Laravel booted once, kept warm) running each screen's runloop (render → publish → sleep until event), the reader thread that decodes/diffs frames and coalesces by dropping stale intermediate frames, and the UI thread that only mounts diffed changes; SharedValue gestures/animations evaluated on the UI thread with PHP receiving one event at completion; Laravel queues on a separate embedded worker runtime; Android activity destruction parks (not tears down) the runtime; hot reload is the only true restart, with navigation stack saved/restored
- [https://nativephp.com/docs/mobile/4/architecture/embedded-php] Use these docs for the embedded PHP build: PHP 8.4 compiled with the embed SAPI as a `libphp` C library linked into the Swift/Kotlin shells, booted in-process with no FastCGI/sockets; the `nativephp` extension (Element Runtime + bridge functions seam) compiled into libphp with engine, extension, and native readers shipped in lockstep per release; bundled extensions (bcmath, ctype, curl, dom, fileinfo, filter, intl, mbstring, openssl, pdo_sqlite, phar, session, simplexml, sockets, sodium, sqlite3, tokenizer, xml, xmlreader, xmlwriter, zip, zlib) with SQLite, a CA bundle, and ICU statically compiled; `native:install` downloads the prebuilt bundles
- [https://nativephp.com/docs/mobile/4/architecture/glossary] Use these docs for definitions of the architecture terms: SuperNative, EDGE, Native Component, Element, Element Tree, Element Runtime, Frame, Node, Node Tree, Renderers, Runloop, Persistent Runtime, Callback ID, Wire Events (the ordered binary native→PHP event channel), SharedValue, Bridge Functions (the JSON-based second seam for camera/biometrics/geolocation/plugins), and Embed SAPI

## Plugins

- [https://nativephp.com/docs/mobile/4/plugins/introduction] Use these docs for the plugin concept: Composer packages bundling PHP facades/events/service providers, native Swift+Kotlin code, and a manifest; capabilities include bridge functions, events to components, permissions, Gradle/CocoaPods/SPM dependencies, private Maven repos, Android Activities/Services/Receivers/Providers, bundled assets, build-time lifecycle hooks, and validated secrets; usage pattern is `MyPlugin::doSomething()` plus `#[OnNative(SomethingHappened::class)]` listeners
- [https://nativephp.com/docs/mobile/4/plugins/using-plugins] Use these docs for installing and registering plugins: `composer require vendor/nativephp-plugin-name`; premium marketplace plugins need `composer config repositories.nativephp-plugins composer https://plugins.nativephp.com` and `composer config http-basic.plugins.nativephp.com your-email your-license-key`; publish provider with `php artisan vendor:publish --tag=nativephp-plugins-provider` then `php artisan native:plugin:register vendor/plugin-name` (explicit registration is a security measure against transitive deps); verify with `native:plugin:list`, rebuild with `native:run`; remove with `native:plugin:uninstall` (flags `--force`, `--keep-files`)
- [https://nativephp.com/docs/mobile/4/plugins/creating-plugins] Use these docs for scaffolding plugins with `php artisan native:plugin:create`: structure has `composer.json` (`"type": "nativephp-plugin"`, `extra.nativephp.manifest` pointing to `nativephp.json`), `src/` (ServiceProvider, Facades, Events, Commands), `resources/android/src/` (Kotlin, vendor-namespaced packages like `com.myvendor.plugins.myplugin` determine file placement), `resources/ios/Sources/` (Swift), `resources/js/` (bridge stubs POSTing to `/_native/api/call`); full manifest fields table (`namespace` required; `bridge_functions`, `events`, `android.*`, `ios.*`, `assets`, `hooks`, `secrets`); local dev via path repository; register with `native:plugin:register` (`--remove` to remove); AI tooling: `native:plugin:install-agent` (`--all`, `--force`), `native:plugin:boost` generating `resources/boost/guidelines/core.blade.php`
- [https://nativephp.com/docs/mobile/4/plugins/bridge-functions] Use these docs for PHP↔native bridge functions: declare in `nativephp.json` `bridge_functions` with `name` (e.g. `MyPlugin.DoSomething`), `ios` (Swift `EnumName.ClassName` path), `android` (full Kotlin class path); Swift classes implement the `BridgeFunction` protocol with `execute(parameters:) throws -> [String: Any]` returning `BridgeResponse.success(data:)`/`BridgeResponse.error(message:)`; Kotlin classes implement `com.nativephp.mobile.bridge.BridgeFunction` with `override fun execute(parameters: Map<String, Any>)`; PHP side calls `nativephp_call('MyPlugin.DoSomething', json_encode($options))` guarded by `function_exists('nativephp_call')` and decodes `->data`
- [https://nativephp.com/docs/mobile/4/plugins/events] Use these docs for dispatching events from native code to PHP: declare event FQCNs in the manifest `events` array; event classes are plain PHP with `Dispatchable, SerializesModels` (no `ShouldBroadcast` needed); Swift dispatches via `LaravelBridge.shared.send?("Vendor\\MyPlugin\\Events\\ProcessingComplete", payload)` (wrap in `DispatchQueue.main.async`); Kotlin via `NativeActionCoordinator.dispatchEvent(activity, eventClass, payload.toString())` posted through `Handler(Looper.getMainLooper())`; critical gotcha: dispatch silently fails off the main/UI thread
- [https://nativephp.com/docs/mobile/4/plugins/lifecycle-hooks] Use these docs for build-time plugin hooks: `pre_compile`, `post_compile`, `copy_assets`, `post_build`, declared in `nativephp.json` `hooks` as Artisan command signatures; generate with `php artisan native:plugin:make-hook`; commands extend `NativePluginHookCommand` with helpers `platform()`, `isIos()`, `isAndroid()`, `buildPath()`, `pluginPath()`, `appId()`, `copyToAndroidAssets()`, `copyToIosBundle()`, `downloadIfMissing($url, $dest)`, `unzip()`; prefer the declarative `assets` manifest field for simple copies
- [https://nativephp.com/docs/mobile/4/plugins/permissions-dependencies] Use these docs for manifest permissions and dependencies: `android.permissions` strings merged into AndroidManifest.xml; `ios.info_plist` key-value entries (`NSCameraUsageDescription`, API keys, `${ENV_VAR}` placeholders; vague usage descriptions risk App Store rejection); `android.dependencies` Gradle types `implementation`/`api`/`compileOnly`/`runtimeOnly`; iOS `pods` array and `swift_packages` (`url` + `version`; preferred over CocoaPods); `android.repositories` for private Maven repos with `credentials` supporting `${ENV_VAR}`
- [https://nativephp.com/docs/mobile/4/plugins/advanced-configuration] Use these docs for advanced `nativephp.json` fields: `secrets` (per-var `description` + `required`; build fails with guidance if missing); `android.activities`/`services`/`receivers`/`providers` merged into AndroidManifest.xml (attributes like `theme`, `exported`, `foregroundServiceType`, `intent-filters`); `android.features`; `android.meta_data`; declarative `assets` (`"source": "destination"`, Android destinations `assets/`, `res/raw/`, `res/drawable/`, iOS `Resources/`; text assets support `${ENV_VAR}` substitution); `ios.background_modes` (audio, fetch, processing, location, remote-notification, bluetooth-central/peripheral); `ios.entitlements`; `ios.capabilities`; `android.min_version` (int SDK, baseline 29) and `ios.min_version` (string, baseline "18.0"); `android.init_function`/`ios.init_function` run synchronously once at app startup
- [https://nativephp.com/docs/mobile/4/plugins/validation-testing] Use these docs for `php artisan native:plugin:validate` (checks manifest syntax/required fields, bridge declarations vs native code, registered hook commands, declared assets) and common errors ("Bridge function not found in native code", "Invalid manifest JSON", "Hook command not registered"); test PHP with standard PHPUnit, test native code by running the app (`native:run`) and tailing device logs with `php artisan native:tail`; debugging checklist: `"type": "nativephp-plugin"` in composer.json, `composer dump-autoload`, rebuild after native changes, exact name matches, main-thread event dispatch
- [https://nativephp.com/docs/mobile/4/plugins/best-practices] Use these docs for marketplace publishing standards: README must cover installation, PHP usage, JS usage, all methods/events/permissions/secrets; every plugin must ship a JS library in `resources/js/` exporting a function per bridge function; test on physical devices (iOS Simulator lacks camera/biometrics); generate Boost guidelines via `php artisan native:plugin:boost`; run `native:plugin:validate` with zero errors; approval requires a LICENSE file, a GitHub release/tag, a configured webhook, a support channel, Swift in `resources/ios/Sources/`, Kotlin in `resources/android/src/`, `nativephp/mobile` in composer.json require, and `ios.min_version` + `android.min_version` in nativephp.json; distribute test builds via TestFlight / Google Play testing tracks
- [https://nativephp.com/docs/mobile/4/plugins/core] Use these docs as the index of official core plugins: browser, camera, microphone, network, share (free); biometrics, geolocation, scanner, secure-storage (premium); firebase (push notifications) and vibe (websockets); per-plugin pages live at `/docs/mobile/4/plugins/core/{name}`; note that Device, Dialog, File, and System are core built-ins in v4 (documented in The Basics), and detailed guides for vibe, firebase, secure storage, and Browser::auth() live in the Digging Deeper section

## Testing

- [https://nativephp.com/docs/mobile/4/testing/introduction] Use these docs for the in-process SuperNative testing suite (Pest or PHPUnit, no device/simulator, CI-friendly) where a `FakeBridge` stands in for the native runtime and assertions target the published wire tree; the `Native` facade (`use Native\Mobile\Testing\Native`) entry points — `Native::test(Counter::class)` (accepts `params:` and `data:` arguments), `Native::visit('/profile/5')` (mounts the route's component resolving params and layout), `Native::fakeBridge()` (script responses before mount) — both returning a fluent `TestableComponent`; core assertions `assertSee()`/`assertDontSee()`, `tap()`, `assertSet()`/`assertNotSet()` (reads public or `#[Computed]` properties); scaffolding tests with `php artisan native:make-test Counter` (`--force` to overwrite)
- [https://nativephp.com/docs/mobile/4/testing/interactions] Use these docs for driving screens in tests: targeting by visible text or by `ref` (set via `ref="vibrate-card"` in Blade or `->ref()` on element builders); pressing with `tap()`, `press()`, `longPress()`; form controls `input()`, `submit()`, `toggle()`, `check()`, `slide()`, `select()`, `selectRadio()`, `changeTab($target, $index)`, `dismissSheet()` (model-bound fields sync their property); lower-level `set($property, $value)` (fires `updatedFoo()` hooks then re-renders) and `call($method, ...$args)`; the generic `fireEvent($target, $type, $fields)` primitive; on-demand polling with `firePolls()` / `firePoll($method)` for `#[Poll]` methods; `search($query)` + `searchResults()`; and `pressBack()` with `assertWentBack()`
- [https://nativephp.com/docs/mobile/4/testing/native-events] Use these docs for testing the async native round trip: `emitNative($event, $payload)` delivers a native event class firing `#[On]` listeners, fluent `->on()` closures, and pending `then()`/`catch()` callbacks; call assertions `assertNativeCalled($method, $paramsFilter)`, `assertNativeNotCalled()`, `assertNativeCalledTimes()`, `assertNativeCallOrder()`; pending-callback assertions `assertAwaitingNativeEvent()`/`assertNotAwaitingNativeEvent()`; scripting synchronous responses with `Native::fakeBridge()->respondTo('Device.ToggleFlashlight', [...])` (accepts arrays or closures) — script before mounting for components that hydrate in `mount()`; direct bridge access via `bridge()` exposing `assertNothingCalled()`, `calls`, `publishes`, `callsTo($method)`, `lastPublish()`
- [https://nativephp.com/docs/mobile/4/testing/navigation] Use these docs for navigation and flow testing: intent assertions `assertNavigatedTo($uri)`, `assertReplacedWith($uri)`, `assertWentBack()`, `assertExitedToWeb($uri)`, `assertTransition()` (accepts a `Transition` case or string like `'slide_from_bottom'`), `assertNoNavigation()`; walking flows with `follow()` which returns a new harness mounted on the destination carrying data/params/layout, `goBack()` which pops to the live previous screen with state intact and `onResume()` fired, and `assertScreen($componentClass)`; chrome assertions `assertNavTitle()`, `assertHasTabBar()`, `assertTabBarVisible()`/`assertTabBarHidden()`, `assertHasTab($label)`, `assertTabActive($label)` — `visit()` resolves the route's layout automatically while `test()` needs an explicit `layout` argument for chrome
- [https://nativephp.com/docs/mobile/4/testing/accessibility] Use these docs for the in-process screen-reader audit: `assertAccessible()` walks the rendered wire tree and fails with a located list of violations — icon-only buttons/chips/tabs without an `a11y-label`, clickable icons/images without labels or `alt` text, pressables with no visible text, unlabeled form controls, list items with unlabeled trailing icon buttons; sweeping every screen data-driven via `NativeRouter::registeredRoutes()` (from `Native\Mobile\Edge\NativeRouter`); `accessibilityViolations()` returns the raw violation strings for allow-listing; `toBeAccessible()` Pest sugar via `PestExpectations::register()`; not a replacement for a manual VoiceOver/TalkBack pass
- [https://nativephp.com/docs/mobile/4/testing/advanced] Use these docs for advanced testing tools: rendering with `platform: 'ios'|'android'` to activate `ios:`/`android:` Tailwind variants plus `assertElement($type, $matcher)`/`assertMissingElement()` on raw wire nodes; render-count guards `renderCount()`, `assertRenderCount()`, `assertRerendered()`/`assertNotRerendered()`; wire snapshots via `assertMatchesSnapshot($name)` written to `tests/__snapshots__/`, refreshed with `UPDATE_SNAPSHOTS=1 php artisan test`; raw inspection with `tree()`, `instance()`, `get($property)`, `bridge()`, `navigationIntent()`, `dumpTree()`; Pest sugar via `\Native\Mobile\Testing\PestExpectations::register()` in `tests/Pest.php` adding `toSee`, `toNotSee`, `toHaveSet`, `toHaveNavigatedTo`, `toHaveElement`, `toBeOnScreen`, `toBeAccessible`; whole-app smoke tests iterating `NativeRouter::registeredRoutes()`

## Publishing

- [https://nativephp.com/docs/mobile/4/publishing/introduction] Use these docs for the release workflow overview (release → test → package → submit → publish) and Bifrost (bifrost.nativephp.com) as the managed alternative for certificates/keystores/OTA updates; `php artisan native:release patch|minor|major` bumps `NATIVEPHP_APP_VERSION` and auto-increments `NATIVEPHP_APP_VERSION_CODE` in `.env`; cutting an optimized release build with `php artisan native:run --build=release` (strips debug code and Composer dev dependencies — test it on a real device); prerequisites: bundle ID, Android keystore + key alias, iOS certificates + provisioning profiles
- [https://nativephp.com/docs/mobile/4/publishing/android] Use these docs for Play Store packaging: `php artisan native:credentials android` generates a JKS keystore, writes credentials to `.env`, and gitignores the keystore (saved in `nativephp/credentials/android/`); `native:package android` with `--keystore`/`--keystore-password`/`--key-alias`/`--key-password` (or env vars `ANDROID_KEYSTORE_FILE`, `ANDROID_KEYSTORE_PASSWORD`, `ANDROID_KEY_ALIAS`, `ANDROID_KEY_PASSWORD`) builds a signed APK, or `--build-type=bundle` for the AAB the Play Store requires; direct upload via `--upload-to-play-store --play-store-track=internal|alpha|beta|production --google-service-key=key.json` (auto-increments version code from the latest Play Store build); other flags: `--test-push=app.aab`, `--skip-prepare` (incremental, not after native-code changes), `--jump-by=10`, `--output=dir`, `--no-tty` (CI); artifacts land under `nativephp/android/app/build/outputs/`
- [https://nativephp.com/docs/mobile/4/publishing/ios] Use these docs for App Store packaging: `php artisan native:package ios` with credentials as flags or env vars — `--api-key-path`/`APP_STORE_API_KEY_PATH` (.p8), `--api-key-id`/`APP_STORE_API_KEY_ID`, `--api-issuer-id`/`APP_STORE_API_ISSUER_ID`, `--certificate-path`/`IOS_DISTRIBUTION_CERTIFICATE_PATH` (.p12/.cer), `--certificate-password`, `--provisioning-profile-path` (.mobileprovision), `--team-id`/`IOS_TEAM_ID`; `--export-method=app-store|ad-hoc|enterprise|development` (default app-store); creating an App Store Connect API key under Users & Access → Keys (download the .p8 immediately — no re-download); `--upload-to-app-store`, `--validate-profile` (dumps entitlements, push support, associated domains, APS environment), `--test-upload`, `--clean-caches`, `--rebuild`, `--validate-only`; version bumps via `native:release patch`
