Tilly The Coder
Tilly The Coder
NativePHP for Mobile v2: Real Native Components
Tilly The Coder

NativePHP for Mobile v2: Real Native Components

Tilly The Coder
8 mins
This is the estimated time it takes to read the article.

NativePHP Mobile v2 was released on Nov 29, 2025. By the Apr 14, 2026 crawl date, it was a real release, not just a conference teaser, but the native component story was still early. This is a v2 guide, so it uses the v2 documentation rather than the newer v3 pages.

The main promise is still Laravel running on the device. The v2 docs describe a pre-compiled PHP runtime bundled with your app, Swift and Kotlin shells that manage the PHP environment, and a custom PHP extension that exposes native functions to PHP. That is very different from shipping a server-rendered website inside a generic wrapper.

What v2 actually shipped

NativePHP v2 is easy to oversell if you mix it with later Super Native and native-ui demos. The official v2 EDGE docs are much narrower: the first native component set is about app navigation and framing, not a complete mobile design system.

  • Laravel code lives inside the app bundle.

  • No external PHP web server is required for normal app execution.

  • NativePHP bridges PHP to platform APIs such as camera, biometrics, push notifications, and device features.

  • The Swift and Kotlin shell applications host the runtime and platform integration.

  • EDGE in v2 renders native top bars, bottom navigation, and side navigation from Blade definitions.

That gives you two honest UI paths. You can keep most screens in a web-rendered Laravel interface, and then use EDGE for native app chrome where it changes the feel of the whole app. If you need rich native lists, sheets, sliders, and custom controls, that belongs in the newer Super Native/native-ui discussion, not as a blanket v2 claim.

Install a fresh v2 app

NativePHP Mobile v2 required a license-backed Composer repository. The docs recommend starting from a new Laravel app, adding the NativePHP Composer repository, then requiring the mobile package.

{
    "repositories": [
        {
            "type": "composer",
            "url": "https://nativephp.composer.sh"
        }
    ]
}
composer require nativephp/mobile:"~2.0.0"
php artisan native:install
php artisan native:run

Before running the installer, the v2 installation guide calls out the app ID and version values in `.env`. Keep these boring and explicit because they become part of the generated native projects.

NATIVEPHP_APP_ID=com.tillythecoder.lessons
NATIVEPHP_APP_VERSION="DEBUG"
NATIVEPHP_APP_VERSION_CODE="1"

The generated `nativephp` directory contains the native iOS and Android project files. Treat it as generated output. The v2 docs explicitly say upgrades can rebuild that directory with `native:install --force`, so product code should live in Laravel, not in hand-edited generated native files.

Upgrade from v1

The v2 launch post describes the upgrade path as changing the package constraint from v1 to v2, running Composer, then rebuilding the native project files. A practical v1-to-v2 upgrade looks like this:

{
    "require": {
        "nativephp/mobile": "~2.0.0"
    }
}
composer update
php artisan native:install --force

Those commands are the beginning, not the production checklist. A real mobile app still needs bundle identifiers, icons, launch screens, permissions, signing, release builds, store configuration, and device testing. NativePHP reduces the distance from Laravel to mobile, but the app still ships through iOS and Android rules.

EDGE is navigation first

EDGE stands for Element Definition and Generation Engine. In v2, it transforms Blade syntax into platform-native UI elements. The official v2 list is top bar, bottom navigation, and side navigation. That is enough to make an app feel less like a web page, but it is not the same as a complete native screen toolkit.

<native:top-bar title="Lessons" subtitle="Keep learning">
    <native:top-bar-action
        id="search"
        label="Search"
        icon="search"
        :url="route('lessons.search')"
    />
</native:top-bar>

<native:bottom-nav label-visibility="labeled">
    <native:bottom-nav-item
        id="home"
        icon="home"
        label="Home"
        url="/home"
        :active="request()->is('home')"
    />

    <native:bottom-nav-item
        id="library"
        icon="book"
        label="Library"
        url="/library"
        badge="3"
    />
</native:bottom-nav>

The bottom navigation item shape matters: v2 uses `id`, `icon`, `label`, `url`, optional `active`, optional `badge`, and optional `news`. The URL opens in the web view when it belongs to the app domain, and outside URLs open in the user's browser.

Where v2 is a strong fit

NativePHP Mobile is attractive when the app is local-first, workflow-heavy, or Laravel-backed from end to end. Good examples are internal tools, field apps, note apps, queue-driven utilities, creator apps, and education apps where your Laravel knowledge is already the team's strongest asset.

  • Internal teams that already maintain Laravel apps and need a mobile companion.

  • Offline-first utilities where business rules can run locally and sync later.

  • Creator or education apps that combine content, downloads, notifications, and account state.

  • Workflow apps for scanning, uploading, approving, collecting notes, or checking in users.

It is a weaker fit for apps that mainly need a highly custom native animation engine, complex games, or a team that already has mature Swift and Kotlin codebases. In those cases, NativePHP can still power parts of the experience, but it should not be forced into the center of the app.

Native APIs change what you can build

Access to native APIs is the reason this is more than a web view story. Once camera, push notifications, biometrics, files, and device features are available from PHP-facing APIs, the app can behave like a real mobile app while still letting you write business logic in Laravel patterns.

The important design choice is to wrap platform APIs behind your own small services. A screen should not be littered with permission checks, platform branches, and low-level calls. Ask an action to capture a receipt photo, ask a sync service to queue an upload, and ask a policy whether the current account can perform the action.

use Livewire\Component;
use Native\Mobile\Attributes\OnNative;
use Native\Mobile\Events\Camera\PhotoTaken;
use Native\Mobile\Facades\Camera;

final class ProfilePhotoForm extends Component
{
    public function takeProfilePhoto(): void
    {
        Camera::getPhoto();
    }

    #[OnNative(PhotoTaken::class)]
    public function handlePhotoTaken(string $path): void
    {
        ProcessProfilePhoto::dispatch(
            userId: auth()->id(),
            path: $path,
        );
    }
}

NativePHP reports native work back through events. The camera plugin documents a `PhotoTaken` event that can be handled in PHP with the `OnNative` attribute. Keep that platform event thin, then hand work to a normal Laravel action or job.

If you are building with Vue, React, Inertia, or plain JavaScript, the v2 bridge also exposes native APIs to the frontend side. That is useful for screens that stay web-rendered but still need real device features.

import { Camera, On, Off, Events } from '#nativephp';

const takePhoto = async () => {
    await Camera.getPhoto().id('profile-photo');
};

const handlePhotoTaken = async ({ path, id }) => {
    if (id !== 'profile-photo') {
        return;
    }

    await fetch('/profile/photo', {
        method: 'POST',
        body: JSON.stringify({ path }),
    });
};

On(Events.Camera.PhotoTaken, handlePhotoTaken);

// Call Off(Events.Camera.PhotoTaken, handlePhotoTaken) when the component unmounts.

That shape stays testable. You can test the Laravel endpoint and queued job in normal PHP tests, then use a device test to check camera permissions, cancellation, and upload behavior.

A sensible v2 project structure

  • Actions for business workflows.

  • Form requests or DTOs for validation boundaries.

  • Policies for permissions.

  • Queued jobs for sync or expensive work.

  • Small services around native APIs so the rest of the app is not coupled to platform details.

I would keep mobile-specific code obvious rather than clever. Use folders such as App\Mobile\Actions, App\Mobile\Data, and App\Mobile\Native when the code only exists for the app. Shared domain logic should stay in normal Laravel actions and services so the website, API, and mobile shell can reuse it.

A realistic screen split

For v2, I would put the shell in EDGE and keep the feature screens web-rendered unless there is a specific native API reason to change them. The top bar and bottom navigation give the app a native frame, while Laravel handles routing, policies, validation, persistence, queues, and sync.

  • EDGE: top bar, primary navigation, side drawer where it makes sense.

  • Laravel screens: feeds, forms, article views, checkout flows, and admin-style workflows.

  • Native APIs: camera, biometrics, push notifications, files, scanner, network, secure storage, and sharing.

  • Jobs and events: background sync, upload processing, notification fan-out, and audit logging.

What to verify before shipping

  • Permission prompts on a fresh install, not only on a simulator that already granted access.

  • Offline behavior when the app opens with no network.

  • Background and foreground push notification paths.

  • Release builds on at least one real iOS device and one real Android device.

  • Memory use and list performance on mid-range hardware.

  • App Store and Play Store metadata, privacy labels, and required disclosures.

NativePHP gives Laravel developers a shorter path into mobile, not a pass to ignore mobile quality. Test real devices, handle permissions carefully, design offline states, and respect platform conventions.