Bifrost turns 1! Get 30% off annual plans with code
HAPPYBIRTHDAY

Changelog


For changes prior to v4, see the v3 documentation.

4.7.0#

Released: October 29, 2026

What's Changed

  • Keep bridge call parameters and results out of release logcat by @prosenthal828 in #523
  • Strip Composer's auth.json from bundled apps by @simonhamp in #542
  • Draw dashed, dotted and per-side borders natively by @simonhamp in #548
  • Let apps use their own SVG icons by @simonhamp in #544
  • Bump PHP binaries to 4.1.0 by @simonhamp in #531
  • Use PNG compression level 6 for Android resources by @PrestaEdit in #535
  • Turn on Gradle build and configuration caches by @simonhamp in #514
  • Skip build steps whose inputs haven't changed by @simonhamp in #513
  • Fix text-input and the mobile-ui requirement in the Boost skill by @simonhamp in #503
  • Warn on native:run when the installed PHP binaries aren't the pinned release by @simonhamp in #556
  • Keep async completions across a screen transition's reset by @simonhamp in #555
  • Let NATIVEPHP_BIN_BRANCH install a prerelease binaries build by @simonhamp in #559
  • Stop FlexContainer merging its children's alignment guides by @simonhamp in #551
  • Free what a bridge call or a render pass autoreleases on PHP's threads and the shadow thread by @gwleuverink in #547
  • Keep the CA files up to date by @simonhamp in #570
  • Check PHP binary downloads against the manifest's checksums and signature by @simonhamp in #573
  • Start the Android async lane before the first screen runs by @simonhamp in #568
  • Don't publish a frame the native side already has by @simonhamp in #569
  • Only put an iOS node through the modifiers it uses by @simonhamp in #576
  • Keep a list's unchanged rows when it gains or loses rows on iOS by @simonhamp in #575
  • Size a flex row from its flexed children's real height by @simonhamp in #571
  • Name the image fit values with an ImageFit enum by @simonhamp in #572
  • Add the phone's timezone to Device.GetInfo by @simonhamp in #566
  • Honour a11y_label on top-bar actions; make MaterialIcon honour contentDescription by @wojt-janowski in #550
  • Honour a11y-label on pressable and layout containers by @wojt-janowski in #580
  • Keep the extracted Laravel bundle out of Android backups by @simonhamp in #579
  • Accept route() and external URLs in navigate(), replace() and exitToWeb() by @shanerbaner82 in #578
  • Create singleton Compose state on the main thread before the first composition by @thelemon2020 in #577
  • fix: swipes that start on press-* elements don't scroll (iOS) by @SRWieZ in #524
  • Stop the keyboard-dismiss taps cancelling UIKit controls by @simonhamp in #545
  • Measure each flex child once per proposal by @nlo-tronet in #564
  • Flush focused Android input before interactive actions by @wojt-janowski in #565
  • Keep profileable Android builds minified by @simonhamp in #553
  • Don't stop Gradle after 600 seconds by @simonhamp in #500
  • Keep Prompts output on the build after a plugin hook runs by @simonhamp in #509
  • Put the agent guide in the Boost skill: a worked screen, tests and build output by @simonhamp in #517
  • fix: Android crashes when a positional node ID changes type by @SRWieZ in #436
  • Stop iOS re-extracting the bundle on every launch by @simonhamp in #543
  • Fail loudly on element tags nothing can render by @simonhamp in #502
  • Hand unrouted app links back to the browser, warm and cold by @simonhamp in #558
  • Let BroadcastsGlobally events reach native screens, and add a when filter to #[On] by @gwleuverink in #539
  • Let iOS plugins declare scene configurations by @bkuhl in #541
  • iOS: deliver Home Screen quick actions through a scene delegate by @prosenthal828 in #530
  • feature: font-rounded selects the rounded system font design by @SRWieZ in #529
  • Stop the runloop waking a sleeping phone by @shanerbaner82 in #511
  • Make native:validate aware of plugin elements by @simonhamp in #501
  • iOS: keep the per-tab node cache out of the SwiftUI update pass by @sandermj in #461
  • Report a started biometric prompt as started by @prosenthal828 in #522
  • Parse arbitrary percent widths/heights as percentages by @prosenthal828 in #499
  • feat: opt-in image prop on top-bar actions by @prosenthal828 in #537
  • Android: stretch column children like iOS, gated on a definite parent width by @sandermj in #451
  • iOS: start animate-loop on every appearance path by @sandermj in #447
  • Render the nav bar when it carries only actions (iOS + Android) by @sandermj in #441
  • Reconcile native navigation by router stack depth; direction-aware Android stack transitions by @sandermj in #439
  • fix: skip the farewell frame when back() answers a system back by @SRWieZ in #370
  • Let a deep link path ending in * claim a prefix on Android by @simonhamp in #557
  • Shared-element morph transitions (ref + [@navigate](https://github.com/navigate).morph) by @shanerbaner82 in #372
  • feat: run native route middleware on in-app navigation by @shanerbaner82 in #348
  • fix: deliver native events to nested child components by @shanerbaner82 in #344
  • Keep the query when a native screen exits to a web route by @simonhamp in #583
  • Add NativeComponent::query() helper for a screen's query string by @simonhamp in #401
  • Android: forward deep link queries still percent-encoded by @simonhamp in #581
  • iOS: find a screen's owning tab by its path by @simonhamp in #585
  • Bound TailwindParser's parse cache by @prosenthal828 in #586
  • Sign the iOS simulator app with the app's entitlements by @simonhamp in #582
  • Explain that the version and build number decide re-extraction by @simonhamp in #584
  • Drop the iOS caveats from the ImageFit docblocks by @simonhamp in #589
  • Keep events fired with event() at the screen by @simonhamp in #593
  • Remove the empty nativephp.sqlite committed by accident by @simonhamp in #594
  • Only show Android classic-mode crash details in debug builds by @simonhamp in #592
  • iOS: boot cold deep links to native screens natively by @simonhamp in #591
  • Scroll-view auto-scroll-to in Blade + chrome collapse seam by @shanerbaner82 in #241
  • Keep embedded php webviews out of app-level state by @simonhamp in #587
  • Build the HTTP kernel before ScreenGuard expands middleware groups by @simonhamp in #595
  • iOS: start animate-loop without animating unrelated views by @simonhamp in #598
  • Headless build/verify commands, durable fatal capture, and report() for EDGE exceptions by @shanerbaner82 in #305
  • Only show persistent and webview lane crash details in debug builds by @simonhamp in #597
  • Read the platform from NATIVEPHP_PLATFORM and deprecate Platform by @simonhamp in #596
  • Open off-host redirects outside the app on Android by @simonhamp in #599
  • Open native routes from the php webview on the native stack by @simonhamp in #600
  • Add text-outline for hollow outlined text by @simonhamp in #549
  • Restart a native session that PHP dies in, and raise the memory limit by @simonhamp in #561
  • Send border colours to native without a width, and stop dividers turning black by @simonhamp in #601
  • Move the iOS node decorations into a modifier so Release builds compile by @simonhamp in #602
  • Let a gesture area keep zoomed content on screen by @simonhamp in #603
  • Build the iOS project in Debug and Release on CI by @simonhamp in #604
  • Harden the web-view-reachable bridge surface by @simonhamp in #609
  • Keep async completions that land while a transition is signalled by @simonhamp in #615
  • Pop every level the iOS back history menu pops by @simonhamp in #616
  • fix(android): app crashes if the phone rotates while it's starting by @SRWieZ in #525
  • feature: show-label on top-bar actions by @SRWieZ in #527
  • feat(mobile): support custom native tab bar presentations by @victorycodedev in #560
  • Add HasVirtualListWindow::scrollVirtualListTo() to open a virtual list at a row by @wojt-janowski in #608
  • fix(android): a screen's bg-* doesn't reach the edges in landscape by @SRWieZ in #528
  • Stop iOS builds guessing a build number when App Store Connect fails by @simonhamp in #619
  • Close a leaving screen's sheets and modals in its farewell frame by @martin-ro in #617
  • Open a pressable's menu on a long press with :context-menu by @simonhamp in #621
  • Stop bundling .claude and give rsync and adb install more time by @simonhamp in #622
  • Let a row's shrinking children wrap short of a fixed sibling on Android by @simonhamp in #623
  • WIP - Re-inject the root web view's safe-area insets on rotation on iOS by @bkuhl in #624
  • Fix QR scans and other device events not reaching web-view pages on iOS by @bkuhl in #611
  • Fix QR scans and other device events not reaching web-view pages on Android by @bkuhl in #613
  • Let a gesture area's pan settle on snap points by @simonhamp in #625
  • Add wav(), maxDuration() and level() to the microphone by @simonhamp in #626
  • Fix double encoding characters in external deep link paths by @bkuhl in #605
  • Test against patched Laravel versions so Composer 2.11 can install by @simonhamp in #628
  • Move SECURITY.md to the root and point it at nativephp.com/security by @simonhamp in #627
  • Add CONTRIBUTING.md pointing to nativephp.com/contributing by @simonhamp in #629
  • Opt-in Laravel validation for native screens by @wojt-janowski in #614

New Contributors

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.6.0...4.7.0


4.6.1#

Released: October 25, 2026

What's Changed

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.6.0...4.6.1


4.6.0#

Released: October 2, 2026

What's Changed

  • Android: map more SF Symbol names to Material icons by @sandermj in #454
  • iOS 26: toolbar back chevron and actions hit-test the whole glass pill by @sandermj in #443
  • iOS: paint the PHP window background behind tabs chrome by @unlocdavid in #358
  • docs(boost): fix broken @navigate example in the mobile skill by @shanerbaner82 in #491
  • Surface plugin hook failures instead of building a broken app by @gwleuverink in #414
  • Build a simulator app without needing a simulator by @simonhamp in #494
  • Stop a theme border overruling an explicit border width by @sadiqk2 in #349
  • Stop the callback expression parser corrupting and dropping arguments by @sadiqk2 in #352
  • fix: inline top-bar background never paints on iOS 26.2 by @SRWieZ in #396
  • fix(android): stop mangling keystore passwords containing special characters by @shanerbaner82 in #299
  • feature: OrientationChanged event + System::orientation() — react to device rotation from PHP by @SRWieZ in #371
  • Carry webview request and response bodies as bytes on iOS and Android by @simonhamp in #490
  • fix: Android ignores centering and inset-stretch on containers with absolute children by @SRWieZ in #376
  • Fix Play Store commit when changes cannot be sent for review by @shanerbaner82 in #516
  • feature: let the app declare which languages it supports by @SRWieZ in #369
  • Symmetric keyboard dismissal with keep-focus-on-submit as the escape hatch by @simonhamp in #521
  • Remove timeout on robocopy process by @adamjmarshall in #468
  • Accept extra native payload keys when dispatching events over HTTP by @eastagiletracker in #515
  • Store the Android APP_KEY in the Keystore and stop bundling the developer's key by @simonhamp in #519
  • Fix Windows path separator bug in registerNativeComponents() by @rdanklof in #163
  • Report exceptions caught by the native error screen by @ngunyimacharia in #506
  • feat: add device thermal state + extra getInfo telemetry by @dr-codswallop in #359
  • feat(android): add WebP image format + fix uncompressed PNG output by @PrestaEdit in #399
  • feature: opt-in disabled prop on top-bar actions by @SRWieZ in #378
  • Let UI plugins register custom Blade @event names by @thelemon2020 in #432

New Contributors

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.5.2...4.6.0


4.5.2#

Released: September 23, 2026

What's Changed

  • Test shared() async results against #[On] listeners by @simonhamp in #484
  • Allow x86_64 simulator builds for Intel Macs by @simonhamp in #363
  • fix(ios): let pre-Xcode-26 toolchains compile the Liquid Glass surfaces by @simonhamp in #364
  • fix: iOS build fails on Xcode 27 when a plugin uses an older iOS library by @SRWieZ in #487
  • Let an OTA payload reach, and survive in, the app it was built for by @shanerbaner82 in #476

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.5.1...4.5.2


4.5.1#

Released: September 19, 2026

What's Changed

  • Let bg-* fill the safe areas again on iOS by @shanerbaner82 in #477
  • Fix five ways native:install reports success while doing the wrong thing by @simonhamp in #317
  • Run the package jobs migration after the app's own by @simonhamp in #479
  • Set NATIVEPHP_RUNNING before any artisan runs, and migrate once per platform by @simonhamp in #478
  • Hot reload: explicit trigger on iOS, debug builds only on Android by @simonhamp in #472
  • Place flex children from a measurement of the placement proposal by @shanerbaner82 in #480
  • fix(android): allow root hosts to reserve the navigation bar slot by @jsdatarocks in #404
  • Give each iOS simulator and device its own hot reload port by @simonhamp in #482
  • Responsive breakpoints: md:/lg:/xl: classes resolved against the live window width by @shanerbaner82 in #467
  • fix: gate the error screen's exception detail on app.debug by @CodyPChristian in #408

New Contributors

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.5.0...4.5.1


4.5.0#

Released: September 18, 2026

What's Changed

New Contributors

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.4.1...4.5.0


4.4.1#

Released: September 12, 2026

What's Changed

  • fix: honour per-screen tab-bar hiding on the custom-Column chrome path by @shanerbaner82 in #347

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.4.0...4.4.1


4.4.0#

Released: September 11, 2026

What's Changed

  • Emit the iOS launch image set whole by @unlocdavid in #320
  • Honour a whitespace policy on <text> so slot content can keep its line breaks by @shanerbaner82 in #424
  • Let apps scope which paths open on Android app links by @shanerbaner82 in #403
  • Make text whitespace symmetric with the browser, with whitespace-* classes to opt out (#356 rebased) by @shanerbaner82 in #425
  • Fix empty POST bodies and 404s on redirect in the iOS scheme handler by @gwleuverink in #326
  • Attach artisan to the live TSRM instead of re-initialising it by @gwleuverink in #329
  • Hold the extraction lock across the background artisan commands by @gwleuverink in #330
  • Merge Info.plist entries structurally so plugins can declare any value type (#377 rebased) by @shanerbaner82 in #427
  • Deliver native events to webview screens on Android by @gwleuverink in #379
  • Apply the review nits from #391 and #392 by @gwleuverink in #398
  • Resolve the iOS build number before the Laravel app is bundled by @shanerbaner82 in #434

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.3.2...4.4.0


4.3.2#

Released: September 5, 2026

What's Changed

New Contributors

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.3.1...4.3.2


4.3.1#

Released: September 1, 2026

What's Changed

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.3.0...4.3.1


4.3.0#

Released: August 28, 2026

What's Changed

  • Stop registering view paths the bundle never ships by @gwleuverink in #346
  • fix: scrolling gets stuck on elements with press-* feedback (iOS 18) by @SRWieZ in #374
  • fix: don't paint the keyboard's helper windows in UI.SetBackground (iOS) by @SRWieZ in #373
  • fix: Android bottom-bar draws under the system navigation bar by @SRWieZ in #375
  • fix: inline top-bar background never paints on iOS 26.2 by @SRWieZ in #380
  • Decode zip entry names as UTF-8 when extracting the app bundle by @gwleuverink in #331
  • Seed the Vite hot file into the simulator container on watch start by @gwleuverink in #333
  • Revert "Seed the Vite hot file into the simulator container on watch start (#333)" by @shanerbaner82 in #385
  • Revert "Decode zip entry names as UTF-8 when extracting the app bundle (#331)" by @shanerbaner82 in #386
  • Revert "fix: inline top-bar background never paints on iOS 26.2 (#380)" by @shanerbaner82 in #387
  • Revert "fix: Android bottom-bar draws under the system navigation bar (#375)" by @shanerbaner82 in #388
  • Revert "fix: don't paint the keyboard's helper windows in UI.SetBackground (iOS) (#373)" by @shanerbaner82 in #389
  • Revert "fix: scrolling gets stuck on elements with press-* feedback (iOS 18) (#374)" by @shanerbaner82 in #390
  • Decode zip entry names as UTF-8 when extracting the app bundle by @gwleuverink in #392
  • fix: Android bottom-bar draws under the system navigation bar by @SRWieZ in #395
  • Seed the Vite hot file into the simulator container on watch start by @gwleuverink in #391
  • fix: don't paint the keyboard's helper windows in UI.SetBackground (iOS) by @SRWieZ in #393

New Contributors

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.2.0...4.3.0


4.2.0#

Released: August 14, 2026

What's Changed

  • [Masterclass] Fix items-start/items-stretch inversion on iOS and max-w-* being dropped on both platforms by @shanerbaner82 in #313
  • [Masterclass] Support per-corner and per-side border radius classes by @shanerbaner82 in #314
  • [Masterclass] Dismiss the keyboard on tap for screens with native chrome by @shanerbaner82 in #315
  • Use destructive theme color for native errors by @wojt-janowski in #295
  • Fix glass elements ignoring their corner radius on iOS by @shanerbaner82 in #323
  • Restore push notification badge clearing by @wojt-janowski in #294
  • Ignore file URLs in DeepLinkRouter by @gwleuverink in #332
  • Restore the video and audio MIME types the squash dropped by @gwleuverink in #328
  • Restore the Android query string handling the SuperNative squash reverted by @gwleuverink in #327
  • fix: forward flexDirection into layout — completes flex-row/flex-col by @shanerbaner82 in #270

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.1.0...4.2.0


4.1.0#

Released: August 7, 2026

What's Changed

  • fix(ios): stop aliasing the plain "plus" icon to plus.circle.fill by @shanerbaner82 in #255
  • fix: parse flex-row / flex-col direction utilities by @shanerbaner82 in #256
  • feat: content-addressed callback ids by @shanerbaner82 in #257
  • feat: TreeObservers — observe published trees, events, and navigation by @shanerbaner82 in #259
  • feat: #[Locked] properties — bindings cannot write identity props by @shanerbaner82 in #260
  • Remove deprecated flashlight method from System class by @simonhamp in #263
  • fix: measure cross-axis size against the resolved main size by @simonhamp in #264
  • fix(ios): recompute remaining space before placing justified children by @shanerbaner82 in #254
  • feat: GatedBridge contract + FakeBridge capability deny-list by @shanerbaner82 in #258
  • perf: cut hot reload latency and its variance by @simonhamp in #266
  • feat(ios): implement UI.SetBackground for parity with Android by @shanerbaner82 in #277
  • fix: hot reload permanently wedging when a trigger lands mid-reboot by @shanerbaner82 in #278
  • feat: expose stored navigation configs on CallbackRegistry by @shanerbaner82 in #267
  • feat: NativeRouteFallback — apps decide what a browser sees on native routes by @shanerbaner82 in #268
  • feat: plugin-registered element attribute capture by @shanerbaner82 in #269
  • Fix deep link delivery in native-ui (EDGE) apps on iOS by @shanerbaner82 in #282
  • Restore the zip error detail lost by the SuperNative squash by @gwleuverink in #276
  • fix(android): avoid resizing WebView for keyboard insets by @buseduran in #156
  • feat(edge): dispatch screen lifecycle events from the navigation loop by @sylvesterdamgaard in #248
  • Ship the real app name in CFBundleName (OAuth consent alert fix) by @shanerbaner82 in #285
  • Fix top-bar background_color not rendering at the scroll edge (iOS) by @shanerbaner82 in #284
  • Extend shows-indicators to refreshable and lazy-grid by @shanerbaner82 in #286
  • Fix - Expose tree publication revisions on Android by @wojt-janowski in #280
  • Port signed-zero inset anchoring from the dev core (parser + iOS + Android) by @shanerbaner82 in #288
  • Port the background-layer core seams from the dev core (Android) by @shanerbaner82 in #287
  • Honour platforms, and stop copying SwiftPM manifests and test targets into the app target by @ICTtrying in #262
  • Distinguish a locked device from a missing key in SecureStorage by @simonhamp in #283
  • Make the Android plugin dependency block marker-delimited, so build.gradle.kts stops growing a comment per build by @ICTtrying in #271
  • Add Tailwind aliases and unsupported class warnings by @wojt-janowski in #296
  • fix(ios): stop mangling certificate passwords containing special characters by @shanerbaner82 in #210
  • fix(plugins): copy Android plugin sources into a dedicated wiped source root by @simonhamp in #215
  • Accept format v4 — event channel is a queue, and pin the binaries release by @simonhamp in #265

New Contributors

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.0.1...4.1.0


4.0.1#

Released: July 31, 2026

What's Changed

  • Recreate the runtime directories Laravel needs in the bundle copy by @gwleuverink in #247
  • Fold the runtime dir list onto BundleExclusions and guard it by name by @simonhamp in #249
  • fix(ios): use persistent WKWebsiteDataStore so cookies survive cold launch by @sawan-webmavens in #140
  • Fix: make iOS bundle extraction atomic and self-healing by @voicecode-bv in #153
  • Substitute ${ENV_VAR} placeholders in Android plugin meta-data by @voicecode-bv in #167

New Contributors

Full Changelog: https://github.com/NativePHP/mobile-air/compare/4.0.0...4.0.1


4.0.0#

Released: July 30, 2026

What's Changed

New Contributors

Full Changelog: https://github.com/NativePHP/mobile-air/compare/3.3.6...4.0.0


4.0.0-rc.1#

Released: July 15, 2026

What's Changed

  • SuperNative — fully native UI powered by SwiftUI on iOS and Jetpack Compose on Android, and the new default for v4 apps
  • Livewire-like native components — each screen is a PHP NativeComponent class holding its state and behavior, re-rendering the native UI as your properties change
  • Shared memory between PHP and the native layer — no serialization overhead or web view bridge between your code and the UI
  • Web view as a component — the classic web-view-first approach is now opt-out: render a single native route with a full-screen web view to keep building the v3 way
  • Layouts — declare shared chrome (nav bars, tab bars) once in a NativeLayout class and attach it to a route or group of routes
  • Native navigation stack — register screens with Route::native(), then push, pop, and replace them with native transitions
  • Component testing suite — mount a NativeComponent, drive interactions, and assert on state and output entirely in-process, with no device or simulator
  • Device, Dialog, File and System Plugins are now core built-ins — nativephp/mobile-device, nativephp/mobile-dialog, nativephp/mobile-file, and nativephp/mobile-system plugins have moved into nativephp/mobile. Remove the standalone plugins before upgrading (see the Upgrade Guide). The facades and events are unchanged, so no application code changes are needed.
  • The Vite dev server is now opt-in — native:run / native:watch no longer start Vite automatically. Pass --vite to enable JS/CSS HMR. The --no-vite flag still works but is now redundant. See Hot Reloading.
  • Fix: Remove stray tag by @martin-ro in #158

New Contributors

Full Changelog: https://github.com/NativePHP/mobile-air/compare/3.3.6...4.0.0-rc.1