Migrate to PAM Native 0.6
PAM Native 0.6 keeps the lower-level navigation surface source-compatible, so an application can migrate one root navigator at a time. New applications should start with named routes.
Upgrade the artifacts together
Section titled “Upgrade the artifacts together”PHP, Rust, Android, and iOS artifacts share an append-only protocol and must be
updated as one compatible set. Protocol version remains 1, but 0.6 adds node
and property IDs used by Canvas, press scaling, and shared transitions. An old
host can decode existing frames; it cannot execute a new capability it does not
contain.
After the dependency update, regenerate the host and run the platform build and tests before changing application routes.
Replace an anonymous stack
Section titled “Replace an anonymous stack”Previous lower-level declaration:
$navigator = Router::stack('home') ->route('home', fn () => $home) ->route('product', fn (RouteContext $route) => new ProductScreen( $route->integer('productId'), )) ->build();Named-route declaration:
use Pam\Native\Routing\Route;
$navigator = Route::stack('main', initial: 'home', routes: function (): void { Route::screen('home', HomeScreen::class); Route::screen('product', ProductScreen::class);});The screen constructor becomes the typed parameter boundary:
final class ProductScreen extends Component{ public function __construct(public readonly int $productId) { }}Low-level infrastructure may continue to use Navigator, Router,
NavigationContainer, typed actions, and navigation events directly.
Migrate component actions
Section titled “Migrate component actions”Remove injected Navigator properties from ordinary components and use their
application navigation scope:
$this->pushRoute('product', productId: 42);$this->navigateRoute('account');$this->replaceRoute('login');$this->popRoute();Migrate call sites after registering the equivalent named destinations. This keeps every intermediate commit runnable.
Separate route names from URLs
Section titled “Separate route names from URLs”An internal route name is not a URL path. Declare a deep-link pattern only for a destination that accepts an external URL:
Route::screen('product', ProductScreen::class) ->deepLink('/products/{productId}');Test cold-start and warm-start links after migrating because both enter the same typed route constructor through different host lifecycle paths.
Adopt production capabilities
Section titled “Adopt production capabilities”The capability additions are backward-compatible. Existing string permission
calls remain available, but new code should use the integer-backed
PermissionKind enum.
- Android FCM projects place their client configuration at
.pam/google-services.jsonor project-rootgoogle-services.json. PAM owns the messaging service; a custom service may keep forwarding receives. - iOS adds the relevant usage descriptions and forwards notification delegate callbacks to the PAM host.
- iOS hosts may provide the optional runtime diagnostic callback.
- WebView roots accept
https,http, andfile; inline HTML is unchanged. - SQLite results above 1,000 rows or 256 columns require pagination.
- File imports stop after 64 MiB.
- Media pauses with the host lifecycle and resumes only when it was previously playing.
Migration verification
Section titled “Migration verification”Before shipping, verify:
- The application uses one compatible PHP/Rust/Android/iOS artifact set.
- Every named screen can be constructed from its declared parameters.
- Back, replace, reset, auth guards, and restored navigation state behave as they did before the migration.
- Cold and warm deep links resolve to the same screen and typed parameters.
- Permission denial and cancellation have visible recovery paths.
- Large SQLite queries and file imports respect the new bounds.
- Background/foreground transitions pause and restore media correctly.
See Navigation for the complete named-route surface and Platform capabilities for host setup and limits.