NativePHP for Mobile Documentation

repository·main·Indexed 22 days ago

https://github.com/nativephp/mobile-air

Framework for Laravel developers to build native iOS and Android applications using PHP. Features an embedded PHP runtime, a plugin system for native API access, on-device background processing, and the 'God Method Bridge' for unified protocol-based routing between PHP, Swift, and Kotlin.

Tokens
66K
Snippets
155
Records
272
Agent score
77%

What's inside NativePHP for Mobile

  1. Overview of the Native UI Plugin Rewrite

    main

    The native-ui plugin (formerly compose-ui) is undergoing a rewrite to provide a consistent, themeable, and accessible UI kit that renders natively on both iOS and Android. The rewrite moves away from hand-rolled styling toward using native platform primitives and a centralized theming system.

    Key improvements in the new architecture include:

    • Native Primitives: Using actual platform components (e.g., Android OutlinedTextField) instead of hand-rolled styled text.
    • Theming System: A centralized Theme class and configuration that allows consumer apps to set brand colors that propagate across all components.
    • Type Safety: Moving away from 'stringly-typed' props across the bridge to prevent silent failures.
    • Accessibility (a11y): Integration of roles, labels, and contrast validation.
    • Two-way Binding: Improved state synchronization using the native:model directive.
  2. Overview of NativePHP for Mobile

    main

    NativePHP for Mobile enables Laravel developers to build native iOS and Android applications using a single PHP codebase. Instead of learning Swift or Kotlin, you can leverage your existing Laravel knowledge to ship mobile apps.

    Key Features:

    • Single Codebase: Build for both iOS and Android from one Laravel project.
    • Embedded PHP Runtime: Runs directly on the device with a persistent mode for high performance.
    • Native API Access: Use a plugin system to interact with device-specific capabilities.
    • On-Device Background Processing: Supports background tasks, queue workers, and scheduled jobs running locally on the device.
    • Push Notifications: Integrated support for APNs (iOS) and FCM (Android).
    • Hot Reload: Rapid development cycle using simulators or physical devices.
  3. What is the God Method Bridge?

    main

    The God Method is a unified, protocol-based routing system that allows calling native iOS/Android functions directly from PHP using a single entry point: nativephp_call('Method.Name', '{params: true}').

    This architecture enables dynamic function registration, meaning you can add new native capabilities without needing to recompile the PHP binaries. It supports type-safe parameter handling, consistent error responses, and event-driven asynchronous operations.

    nativephp_call('Device.GetInfo', '{}')
  4. Understand the Persistent PHP Runtime Model

    main

    The project is moving from a WebView-first model to a Persistent PHP Runtime model to significantly reduce navigation latency.

    Current Model (WebView-first)

    Every navigation triggers a full PHP lifecycle: onCreate() $\rightarrow$ WebView setup $\rightarrow$ loadUrl() $\rightarrow$ php_embed_init() $\rightarrow$ Laravel bootstrap $\rightarrow$ php_embed_shutdown(). This results in ~125-350ms of overhead per navigation.

    New Model (Persistent PHP)

    PHP boots once and stays alive. It decides whether to render a native UI or hand off to a WebView: onCreate() $\rightarrow$ phpRuntime.boot() (once) $\rightarrow$ phpRuntime.dispatch("/") $\rightarrow$ PHP returns either a Native Tree (for Compose) OR an HTML response (for WebView).

    Performance Impact

    MetricClassic (WebView/Request)Persistent PHP
    First page load~300ms~200ms boot + ~10ms dispatch
    Subsequent navigation~200ms each~10ms each
    5 page navigations~1.3s total~250ms total
    StateStateless (session files)In-memory
  5. How Native UI works with SuperNative and EDGE

    main

    NativePHP Mobile uses a fully native UI architecture (SwiftUI on iOS, Jetpack Compose on Android) driven by PHP.

    • SuperNative: The engine that manages the UI. Each screen is represented by a PHP component class that holds state and automatically re-renders when its properties change.
    • EDGE (Element Definition and Generation Engine): A Blade component language under the native: namespace. It supports hot-reload and allows you to define native elements using Blade syntax.
    • Routing: Screens are organized and navigated using Route::native().
  6. Understand the NativePHP Mobile threading model

    main

    NativePHP Mobile operates using a three-thread model to ensure the UI remains responsive even during heavy PHP processing:

    1. PHP Thread: Hosts the persistent runtime. The Laravel application is booted once and kept warm. It runs the screen's runloop (Render $\rightarrow$ Publish $\rightarrow$ Sleep until event).
    2. Reader Thread: Decodes and diffs incoming binary frames from the PHP thread. It coalesces updates by dropping stale intermediate frames to ensure the UI doesn't lag behind the current state.
    3. UI Thread: The main platform thread that mounts the diffed changes to the screen. This thread also handles SharedValue gestures and animations directly to maintain high frame rates.

    Additional Runtimes:

    • Laravel Queues: Run on a separate embedded worker runtime.
    • Android Lifecycle: When an Android Activity is destroyed, the PHP runtime is 'parked' rather than torn down, allowing for faster resumption.
  7. Understand the SuperNative architecture

    main

    SuperNative is the default architecture in NativePHP Mobile v4. It provides a PHP-driven, platform-native UI experience using SwiftUI on iOS and Jetpack Compose on Android.

    Key characteristics:

    • No Web View Required: Unlike traditional hybrid apps, it uses shared memory to communicate between PHP and the native UI, avoiding the overhead of a web view.
    • EDGE Blade Components: Uses Blade components that compile to a fixed-length binary format for high-performance rendering.
    • Truly Native: Components like native:button are real platform buttons, inheriting native accessibility, theming, and dark mode support automatically.
    • What it is NOT: It is not a pixel-perfect rendering engine like Skia/Impeller, it is not a Virtual Machine, and it is not an HTML-to-native transpiler.

    Opting back into Web View: If you need to use a web view for specific screens, you can use Route::native() to point to a screen containing a fullscreen webview element. You must also set NATIVEPHP_START_URL=/home in your .env file.

    // Example of opting into a web view for a specific route
    Route::native('/some-web-route');
  8. How the Event System works

    main

    The event system allows native code to trigger asynchronous operations that notify the PHP/Livewire layer.

    The Flow:

    1. Swift: Calls LaravelBridge.shared.send?(eventClass, payload).
    2. JavaScript: Injects a dispatch into the browser: window.Livewire.dispatch('native:EventClass', payload).
    3. PHP: A Livewire component listens for the event using the #[On('native:EventClass')] attribute.

    To implement a new event, you must create a PHP Event class, dispatch it from Swift using the full namespace, and add the constant to the JavaScript NativeEvents object.

    // 1. Create PHP Event Class
    namespace Native\Mobile\Events\Your;
    class ThingHappened {
        use /* ... */;
        public function __construct(public string $result, public ?string $id = null) {}
    }
    
    // 2. Dispatch from Swift
    LaravelBridge.shared.send?("Native\\Mobile\\Events\\Your\\ThingHappened", ["result" => "success"])
    
    // 3. Listen in Livewire
    #[On('native:Native\\Mobile\\Events\\Your\\ThingHappened')]
    public function handleThing($result, $id = null) { ... }
  9. Implement Data Binding and Reactivity

    main

    NativePHP Mobile uses a reactive model similar to Livewire for native components.

    Two-way Data Binding: Use native:model="property" on input elements to bind to a public property in your NativeComponent. Supports modifiers like .blur, .lazy, and .debounce.300ms.

    <native:text-input native:model="name" />

    Reactivity Attributes:

    • #[Computed]: Methods treated as properties. They are memoized per frame and invalidated on state change. Use #[Computed(persist: true)] to survive re-renders until state changes.
    • #[Poll(interval)]: Runs a method at a specific interval (e.g., #[Poll(5000)]) or use native:poll="1s" in Blade to trigger re-renders.
    • #[On(EventClass::class)]: Listens for native events (e.g., push notifications, websocket messages). Parameters bind by name to event properties. Listeners automatically teardown when the component unmounts.

    Lifecycle Hooks:

    • mount(): Runs only on the first push to the screen.
    • onResume(): Runs when returning to the screen.
    • onBackPressed(): Specifically for Android back button handling.
    • unmount(): Runs when the component is removed.
    • updated{Property}(): Runs when a bound property changes.
    <native:text-input native:model="name" />
  10. Understand the Native UI design philosophy

    main

    The native-ui plugin follows a Native idiom per platform approach. Instead of forcing a single look (like Material Design) on all devices, components are rendered using the native primitives of the host OS to ensure they feel integrated.

    • iOS: Uses SwiftUI primitives (e.g., Button, TextField, Toggle, NavigationStack, .sheet, .searchable).
    • Android: Uses Material3 primitives (e.g., Button, OutlinedTextField, Switch, Scaffold, TopAppBar, ModalBottomSheet, SearchBar).

    This ensures that an iOS user sees iOS-style components and an Android user sees Material3 components, even though they are controlled by the same PHP API.

  11. How Native UI mode manages state and events

    main

    Native UI mode differs from WebView mode by maintaining a persistent PHP runtime. Instead of shutting down after a script execution, it enters an event loop:

    1. Initialization: PHP calls nativephp_element_init() to allocate memory regions for the UI (a 4MB flat buffer, a 4MB property buffer, and a 256KB event buffer).
    2. Publishing UI: PHP calls nativephp_element_publish($tree) to serialize a PHP array tree into a packed binary format in the flat buffer. This is sent to the Kotlin Compose renderer via JNI.
    3. Waiting for Events: PHP calls nativephp_element_wait_event(-1), which blocks the PHP thread using a condition variable (pthread_cond_wait()).
    4. Event Processing: When a user interacts with the UI, Kotlin writes a binary event into the 256KB event buffer and signals the condition variable. PHP unblocks, processes the event, rebuilds the UI tree, and repeats the loop.
    5. Persistence: The PHP interpreter stays alive and holds state throughout the session. The global mutex remains locked, preventing any WebView requests from executing until the Native UI session ends and nphp_element_shutdown() is called.
  12. Understand the NativePHP In-Process Architecture

    main

    NativePHP does not use Inter-Process Communication (IPC). Instead, the PHP interpreter (libphp.so) is loaded directly into the Android app's process via System.loadLibrary("php"). This means the Zend VM, memory manager, and PHP interpreter run as native code within the same Linux process as the Kotlin/Compose code.

    Because they share the same address space, they share:

    • One heap
    • One set of file descriptors
    • One set of environment variables

    This architecture eliminates the overhead of context switching and data copying typically associated with IPC (like sockets or pipes), making communication as fast as inter-thread communication.