diff --git a/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md b/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md index 79708bac5..b0e9a1dd9 100644 --- a/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md +++ b/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md @@ -3,73 +3,72 @@ title: About the New Architecture order: 10 --- -NativePHP for Mobile runs your Laravel app on the device itself — no server, no network round-trip. Traditionally, -your app's UI rendered as HTML inside a web view. That model is productive and familiar, and it's +NativePHP for Mobile runs your Laravel app on the device itself. There is no server and no network round-trip. +Until now, your app's UI rendered as HTML inside a web view. That model is productive and familiar, and it's [still fully supported](../architecture/super-native#is-the-web-view-still-an-option). But it puts a browser between -your app and the platform, and some things can only feel truly native when they *are* native. +your app and the platform, and some things only feel native when they *are* native. -The new architecture — [SuperNative](../architecture/super-native) — removes that layer entirely. Your screens are -real SwiftUI and Jetpack Compose views, created and updated directly by your PHP code. Here's why we built it, and -what it changes. +The new architecture, [SuperNative](../architecture/super-native), removes that layer. Your screens are real SwiftUI +and Jetpack Compose views, created and updated directly by your PHP code. Here's why we built it and what it +changes. ## Why a new architecture? ### Truly native rendering A web view is a remarkable piece of engineering, but users can tell. Scroll physics, text rendering, transitions, -context menus, dark mode, dynamic type, screen readers — every one of these is approximated in a browser and -effortless in the platform's own UI framework. +context menus, dark mode, dynamic type, screen readers. Every one of these is approximated in a browser and comes +for free in the platform's own UI framework. -With the new architecture, an EDGE component like `` isn't a styled `
` — it's the same button -every other native app on that device uses. Accessibility, theming and platform conventions come along for free, +With the new architecture, an EDGE component like `` is the same button every other native app on +that device uses, rather than a styled `
`. Accessibility, theming and platform conventions come along with it, because there's nothing between your UI and the operating system. -### Shared memory, not serialization +### Shared memory instead of serialization -Frameworks that drive native UI from another language usually pay a toll at the border: state gets serialized to -JSON, shipped across a bridge, and parsed on the other side — for every update. +Frameworks that drive native UI from another language usually pay a toll at the border. State gets serialized to +JSON, shipped across a bridge, and parsed on the other side, on every update. NativePHP doesn't have that border. Your PHP runtime is [embedded inside the app process](embedded-php), and the rendering layer communicates through **shared memory**. When your component re-renders, PHP writes a compact binary -description of the screen directly into a buffer the native side reads from — no JSON, no sockets, no copies across -a bridge. The native layer walks your PHP data structures directly, in the same process, in native code. +description of the screen directly into a buffer the native side reads from. There is no JSON and no bridge to +cross. The native layer walks your PHP data structures directly, in the same process, in native code. -The result: a state change in PHP reaches the screen in well under a frame. +A state change in PHP reaches the screen in well under a frame. ### Native-speed interaction -Some things should never wait for application code — a drag should track your finger, an animation should never -drop a frame. The new architecture has a dedicated lane for these: -SharedValues live on the native side and are updated on the UI thread by gestures and animations at the display's -full frame rate. PHP holds a handle and hears about the outcome; the -per-frame work never crosses into PHP at all. +Some things should never wait for application code. A drag should track your finger, and an animation should never +drop a frame. The new architecture has a dedicated lane for these. SharedValues live on the native side and are +updated on the UI thread by gestures and animations at the display's full frame rate. PHP holds a handle and hears +about the outcome. The per-frame work never crosses into PHP at all. -You get Reanimated-style, gesture-driven motion — written in Blade. +You get Reanimated-style, gesture-driven motion, written in Blade. ## What can you expect? -Practically, the same development experience you already have, with a different result on screen: +Practically, the same development experience you already have, with a different result on screen. -- **Same Laravel app.** Routes, controllers, Eloquent, validation, queues — nothing about your backend changes. - Screens are registered with `Route::native()` and driven by PHP component classes, Livewire-style. -- **Same Blade.** You compose screens from [EDGE components](../edge-components/introduction) — declarative Blade - tags with Tailwind-style utility classes — and the framework turns them into SwiftUI and Compose. -- **Native output.** Navigation stacks, tab bars, sheets, lists and gestures are the platform's own, in light and +- Your Laravel app stays the same. Routes, controllers, Eloquent, validation and queues are untouched. Screens are + registered with `Route::native()` and driven by PHP component classes, Livewire-style. +- Your Blade stays the same. You compose screens from [EDGE components](../edge-components/introduction), + declarative Blade tags with Tailwind-style utility classes, and the framework turns them into SwiftUI and Compose. +- The output is native. Navigation stacks, tab bars, sheets, lists and gestures are the platform's own, in light and dark mode, with the platform's accessibility support built in. -- **Adopt at your pace.** The web view is still available as a component, so you can go all-native, all-web, or +- You adopt at your own pace. The web view is still available as a component, so you can go all-native, all-web, or migrate screen by screen. ## Should you use it today? -SuperNative is **the default**: new apps render native screens from the very first route. It's in beta, so -expect rapid iteration — and if you'd rather wait, [opting out](../architecture/super-native#is-the-web-view-still-an-option) -is one route and one component. +SuperNative is **the default**. New apps render native screens from the very first route. It's in beta, so expect +rapid iteration. If you'd rather wait, +[opting out](../architecture/super-native#is-the-web-view-still-an-option) is one route and one component. Ready to go deeper? Start with [The Renderer](renderer). diff --git a/resources/views/docs/mobile/4/architecture/cross-platform-implementation.md b/resources/views/docs/mobile/4/architecture/cross-platform-implementation.md index e5b13455b..f50af9a05 100644 --- a/resources/views/docs/mobile/4/architecture/cross-platform-implementation.md +++ b/resources/views/docs/mobile/4/architecture/cross-platform-implementation.md @@ -3,9 +3,8 @@ title: Cross-Platform Implementation order: 40 --- -NativePHP renders with each platform's own UI framework — SwiftUI on iOS, Jetpack Compose on Android — yet one -Blade template produces the same screen on both. That consistency isn't achieved by testing hard; it's achieved by -sharing the core. +NativePHP renders with each platform's own UI framework, SwiftUI on iOS and Jetpack Compose on Android, yet one +Blade template produces the same screen on both. One shared core is what makes that possible. ## One core, two thin shells @@ -13,25 +12,25 @@ Everything that defines *what* gets rendered lives in a single shared implementa [compiled directly into the PHP runtime](embedded-php) that ships on both platforms: - walking your PHP element trees and encoding them into [frames](glossary#frame), -- the binary [node](glossary#node) format itself — every field, in the same order, with the same meaning, +- the binary [node](glossary#node) format itself, every field in the same order with the same meaning, - the skip-and-reuse logic described in [Subtree Reuse](subtree-reuse), - and the [event channel](glossary#wire-events) that carries interactions back to PHP. What remains per platform is deliberately thin: a reader that decodes frames and diffs trees, and a renderer that -maps each node type to a SwiftUI view or a composable. Even those two layers are written as mirrors of each other -— the same diffing rules, the same frame-coalescing behavior, the same enums for flexbox values, so +maps each node type to a SwiftUI view or a composable. Even those two layers are written as mirrors of each other, +with the same diffing rules, the same frame-coalescing behavior and the same enums for flexbox values, so `justify-content: center` is the identical byte on the wire and the identical concept on both screens. -The practical consequence: when we fix a bug or land a performance improvement in the pipeline, both platforms get -it simultaneously, because there's only one pipeline. +In practice, when we fix a bug or land a performance improvement in the pipeline, both platforms get it at the same +time, because there's only one pipeline. ## Native layout on both platforms Layout follows the same philosophy. Each node carries flexbox-style layout values, and each platform implements -flexbox *inside its own layout system* — a pure-Swift `Layout` on iOS and a Compose `Layout` on Android, built to -the same semantics. There's no shared C++ layout engine sitting apart from the UI framework: your components -measure and place like any other SwiftUI or Compose view, which is exactly why safe areas, dynamic type and -platform navigation transitions work naturally with them. +flexbox *inside its own layout system*, a pure-Swift `Layout` on iOS and a Compose `Layout` on Android, built to +the same semantics. There's no shared C++ layout engine sitting apart from the UI framework. Your components +measure and place like any other SwiftUI or Compose view, which is why safe areas, dynamic type and platform +navigation transitions work naturally with them. iOS is the reference implementation for visual behavior; Android is held to it. Where the platforms disagree by default (text padding, stretch behavior, pixel-versus-point units), the Android renderer adapts so the same @@ -39,13 +38,13 @@ classes produce the same result. ## Two seams, one boundary -Rendering isn't the only traffic between PHP and native. Device features — camera, biometrics, geolocation, -secure storage and everything the [plugin system](../plugins/introduction) exposes — travel over a separate, +Rendering isn't the only traffic between PHP and native. Device features (camera, biometrics, geolocation, +secure storage and everything the [plugin system](../plugins/introduction) exposes) travel over a separate, simpler seam: [bridge functions](../plugins/bridge-functions), a registry of named native functions PHP can call with JSON in and JSON out. The two seams are independent by design. The rendering path is a hot loop measured in microseconds, so it gets the -binary shared-memory treatment; device APIs are occasional calls where clarity and extensibility matter more, so +binary shared-memory treatment. Device APIs are occasional calls where clarity and extensibility matter more, so they get a friendly, pluggable interface. Plugin authors only ever touch the second one. ## Failing loud, not weird @@ -53,5 +52,5 @@ they get a friendly, pluggable interface. Plugin authors only ever touch the sec A shared binary format is only safe if both sides agree on it, so the format carries an explicit **version number**. At startup, each native reader checks the version reported by the Element Runtime against the one it was compiled for; on mismatch it refuses to render rather than misinterpret bytes. Because the PHP runtime and the -native shells [ship together in lockstep](embedded-php), the check should never fire in a real app — it exists so +native shells [ship together in lockstep](embedded-php), the check should never fire in a real app. It exists so that if the impossible happens, you get one clear error instead of a subtly broken UI. diff --git a/resources/views/docs/mobile/4/architecture/embedded-php.md b/resources/views/docs/mobile/4/architecture/embedded-php.md index ab99edcc7..c2a98165a 100644 --- a/resources/views/docs/mobile/4/architecture/embedded-php.md +++ b/resources/views/docs/mobile/4/architecture/embedded-php.md @@ -3,20 +3,20 @@ title: Embedded PHP order: 70 --- -There's no server in a NativePHP app — and no separate PHP process either. PHP ships *inside* your app as a +There's no server in a NativePHP app, and no separate PHP process either. PHP ships *inside* your app as a library, compiled specifically for mobile devices and linked into the native application itself. This page explains what that build is, why we produce it ourselves, and how it reaches your project. ## PHP as a library -Standard PHP is built to sit behind a web server. Mobile PHP is built with the **embed SAPI**: instead of a -`php` binary, the build produces a C library (`libphp`) that the Swift and Kotlin shells link against and call -directly. When your app boots, it initializes the PHP engine in-process, loads your Laravel app from the bundled +Standard PHP is built to sit behind a web server. Mobile PHP is built with the **embed SAPI**. Instead of a `php` +binary, the build produces a C library (`libphp`) that the Swift and Kotlin shells link against and call directly. +When your app boots, it initializes the PHP engine in-process, loads your Laravel app from the bundled [app package](../getting-started/introduction), and keeps it resident as the [persistent runtime](threading-model#lifecycle-booted-once-kept-warm). Running in-process is what makes the rest of the architecture possible: shared memory only works when both sides -share a process. It's also simply fast — there's no FastCGI, no sockets, no per-request process to spawn. +share a process. It's also fast, since there's no FastCGI layer and no per-request process to spawn. NativePHP for Mobile currently bundles **PHP 8.4**, cross-compiled for iOS (device and simulator) and Android (ARM64), thread-safe, and tuned for embedding. @@ -24,28 +24,28 @@ NativePHP for Mobile currently bundles **PHP 8.4**, cross-compiled for iOS (devi ## Built in lockstep with the framework The renderer's [wire format](glossary#frame) has two sides: the [Element Runtime](glossary#element-runtime) that -writes it, and the native readers that decode it. The Element Runtime is a PHP **extension** — native code +writes it, and the native readers that decode it. The Element Runtime is a PHP **extension**, native code compiled into `libphp` itself, alongside the engine. -That's why we build PHP ourselves, and why every release of `nativephp/mobile` pins exact binary builds: the PHP +That's why we build PHP ourselves, and why every release of `nativephp/mobile` pins exact binary builds. The PHP engine, the NativePHP extension inside it, and the Swift/Kotlin readers around it are produced and shipped -**together**, from matching sources. Both sides of every boundary are always the same version — there is no +**together**, from matching sources. Both sides of every boundary are always the same version, so there is no "which PHP works with which framework release" matrix to manage. The wire format's [version handshake](cross-platform-implementation#failing-loud-not-weird) exists as a backstop, but lockstep shipping is what makes it a formality. The same extension also provides the [bridge functions](../plugins/bridge-functions) seam that device APIs and -plugins are built on — one native extension, both boundaries. +plugins are built on. One native extension, both boundaries. ## What's inside The builds include the extensions a Laravel app expects, statically compiled along with their dependencies: bcmath, ctype, curl, dom, fileinfo, filter, intl, mbstring, openssl, pdo_sqlite, phar, session, simplexml, -sockets, sodium, sqlite3, tokenizer, xml, xmlreader, xmlwriter, zip and zlib — plus the `nativephp` extension +sockets, sodium, sqlite3, tokenizer, xml, xmlreader, xmlwriter, zip and zlib, plus the `nativephp` extension described above. SQLite is the bundled database, a CA certificate bundle is included so HTTPS works out of the box, and ICU is included so localization and `intl`-powered formatting behave properly on device. -Everything is compiled from source for each platform — including OpenSSL, libxml2, SQLite and friends — so the +Everything is compiled from source for each platform, including OpenSSL, libxml2, SQLite and friends, so the builds have no dependencies on whatever libraries happen to exist on a given device. ## How it reaches your app @@ -57,12 +57,12 @@ php artisan native:install ``` the framework downloads the prebuilt PHP bundles matching your `nativephp/mobile` version and places them into the -platform projects — static libraries for iOS, shared libraries for Android. `native:run` then compiles your app -with PHP inside it, exactly like any other native dependency. +platform projects, as static libraries for iOS and shared libraries for Android. `native:run` then compiles your +app with PHP inside it, exactly like any other native dependency.