Basics

Router

Introduzione

Le rotte ti permettono di definire le diverse pagine nella tua app e navigare tra di esse.

Usa le rotte quando hai bisogno di:

  • Definire le pagine disponibili nella tua app
  • Navigare gli utenti tra le schermate
  • Proteggere le pagine dietro l'autenticazione
  • Passare dati da una pagina all'altra
  • Gestire i deep link dagli URL

Puoi aggiungere rotte all'interno del file lib/routes/router.dart.

appRouter() => nyRoutes((router) {

  router.add(HomePage.path).initialRoute();

  router.add(PostsPage.path);

  router.add(PostDetailPage.path);

  // add more routes
  // router.add(AccountPage.path);

});

Suggerimento: Puoi creare le tue rotte manualmente o utilizzare lo strumento CLI Metro per crearle automaticamente.

Ecco un esempio di creazione di una pagina 'account' utilizzando Metro.

metro make:page account_page
// Adds your new route automatically to /lib/routes/router.dart
appRouter() => nyRoutes((router) {
  ...
  router.add(AccountPage.path);
});

Potresti anche aver bisogno di passare dati da una vista all'altra. In Nylo Website, questo e possibile utilizzando NyStatefulWidget (un widget con stato che integra l'accesso ai dati di rotta). Approfondiremo questo argomento per spiegare come funziona.

Aggiungere rotte

Questo e il modo piu semplice per aggiungere nuove rotte al tuo progetto.

Esegui il comando seguente per creare una nuova pagina.

metro make:page profile_page

Dopo aver eseguito il comando sopra, verra creato un nuovo Widget chiamato ProfilePage e aggiunto alla directory resources/pages/. Verra anche aggiunta la nuova rotta al file lib/routes/router.dart.

File: /lib/routes/router.dart

appRouter() => nyRoutes((router) {
  ...
  router.add(HomePage.path).initialRoute();

  // My new route
  router.add(ProfilePage.path);
});

Navigare verso le pagine

Puoi navigare verso nuove pagine utilizzando l'helper routeTo.

void _pressedSettings() {
    routeTo(SettingsPage.path);
}

Rotta iniziale

Nei tuoi router, puoi definire la prima pagina che deve caricarsi utilizzando il metodo .initialRoute().

Una volta impostata la rotta iniziale, sara la prima pagina che si carica quando apri l'app.

appRouter() => nyRoutes((router) {
  router.add(HomePage.path);

  router.add(SettingsPage.path);

  router.add(ProfilePage.path).initialRoute();
  // new initial route
});

Rotta Iniziale Condizionale

Puoi anche impostare una rotta iniziale condizionale utilizzando il parametro when:

appRouter() => nyRoutes((router) {
  router.add(OnboardingPage.path).initialRoute(
    when: () => !hasCompletedOnboarding()
  );

  router.add(HomePage.path).initialRoute(
    when: () => hasCompletedOnboarding()
  );
});

Navigare alla Rotta Iniziale

Usa routeToInitial() per navigare alla rotta iniziale dell'app:

void _goHome() {
    routeToInitial();
}

Questo navighera alla rotta contrassegnata con .initialRoute() e cancellera lo stack di navigazione.

Rotta di Anteprima

Durante lo sviluppo, potresti voler visualizzare rapidamente una pagina specifica senza cambiare permanentemente la tua rotta iniziale. Usa .previewRoute() per rendere temporaneamente qualsiasi rotta la rotta iniziale:

appRouter() => nyRoutes((router) {
  router.add(HomePage.path).initialRoute();

  router.add(SettingsPage.path);

  router.add(ProfilePage.path).previewRoute(); // This will be shown first during development
});

Il metodo previewRoute():

  • Sovrascrive qualsiasi impostazione esistente di initialRoute() e authenticatedRoute()
  • Rende la rotta specificata la rotta iniziale
  • Utile per testare rapidamente pagine specifiche durante lo sviluppo

Attenzione: Ricorda di rimuovere .previewRoute() prima di rilasciare la tua app!

Rotta Autenticata

Nella tua app, puoi definire una rotta come rotta iniziale quando un utente e autenticato. Questo sovrascrivera automaticamente la rotta iniziale predefinita e sara la prima pagina che l'utente vede quando effettua il login.

Per prima cosa, il tuo utente dovrebbe essere autenticato utilizzando l'helper Auth.authenticate({...}).

Ora, quando aprono l'app, la rotta che hai definito sara la pagina predefinita fino a quando non effettuano il logout.

appRouter() => nyRoutes((router) {

  router.add(IntroPage.path).initialRoute();

  router.add(LoginPage.path);

  router.add(ProfilePage.path).authenticatedRoute();
  // auth page
});

Rotta Autenticata Condizionale

Puoi anche impostare una rotta autenticata condizionale:

router.add(ProfilePage.path).authenticatedRoute(
  when: () => hasCompletedSetup()
);

Navigare alla Rotta Autenticata

Puoi navigare alla pagina autenticata utilizzando l'helper routeToAuthenticatedRoute():

routeToAuthenticatedRoute();

Vedi anche: Autenticazione per i dettagli sull'autenticazione degli utenti e la gestione delle sessioni.

Rotta Sconosciuta

Puoi definire una rotta per gestire scenari 404/non trovato utilizzando .unknownRoute():

appRouter() => nyRoutes((router) {
  router.add(HomePage.path).initialRoute();

  router.add(NotFoundPage.path).unknownRoute();
});

Quando un utente naviga verso una rotta che non esiste, verra mostrata la pagina della rotta sconosciuta.

Route guard

I route guard proteggono le pagine da accessi non autorizzati. Si eseguono prima che la navigazione venga completata, permettendoti di reindirizzare gli utenti o bloccare l'accesso in base a condizioni.

Usa i route guard quando hai bisogno di:

  • Proteggere le pagine da utenti non autenticati
  • Verificare le autorizzazioni prima di consentire l'accesso
  • Reindirizzare gli utenti in base a condizioni (es. onboarding non completato)
  • Registrare o tracciare le visualizzazioni di pagina

Per creare un nuovo Route Guard, esegui il comando seguente.

metro make:route_guard dashboard

Successivamente, aggiungi il nuovo Route Guard alla tua rotta.

// File: /routes/router.dart
appRouter() => nyRoutes((router) {
  router.add(HomePage.path);

  router.add(LoginPage.path);

  router.add(DashboardPage.path,
    routeGuards: [
      DashboardRouteGuard() // Add your guard
    ]
  ); // restricted page
});

Puoi anche impostare route guard utilizzando il metodo addRouteGuard:

// File: /routes/router.dart
appRouter() => nyRoutes((router) {
    router.add(DashboardPage.path)
            .addRouteGuard(MyRouteGuard());

    // or add multiple guards

    router.add(DashboardPage.path)
            .addRouteGuards([MyRouteGuard(), MyOtherRouteGuard()]);
})

Ciclo di Vita NyRouteGuard

Nella v7, i route guard utilizzano la classe NyRouteGuard con tre metodi del ciclo di vita:

  • onBefore(RouteContext context) - Chiamato prima della navigazione. Restituisce next() per continuare, redirect() per andare altrove, o abort() per fermarsi.
  • onAfter(RouteContext context) - Chiamato dopo la navigazione riuscita verso la rotta.

Esempio Base

File: /routes/guards/dashboard_route_guard.dart

class DashboardRouteGuard extends NyRouteGuard {
  DashboardRouteGuard();

  @override
  Future<GuardResult> onBefore(RouteContext context) async {
    // Perform a check if they can access the page
    bool userLoggedIn = await Auth.isAuthenticated();

    if (userLoggedIn == false) {
      return redirect(LoginPage.path);
    }

    return next();
  }

  @override
  Future<void> onAfter(RouteContext context) async {
    // Track page view after successful navigation
    Analytics.trackPageView(context.routeName);
  }
}

RouteContext

La classe RouteContext fornisce accesso alle informazioni di navigazione:

Proprieta Tipo Descrizione
context BuildContext? Contesto di build corrente
data dynamic Dati passati alla rotta
queryParameters Map<String, String> Parametri query dell'URL
routeName String Nome/percorso della rotta
originalRouteName String? Nome originale della rotta prima delle trasformazioni
@override
Future<GuardResult> onBefore(RouteContext context) async {
  print('Navigating to: ${context.routeName}');
  print('Query params: ${context.queryParameters}');
  print('Route data: ${context.data}');

  return next();
}

Metodi Helper dei Guard

next()

Prosegui verso il guard successivo o verso la rotta:

@override
Future<GuardResult> onBefore(RouteContext context) async {
  return next(); // Allow navigation to continue
}

redirect()

Reindirizza verso una rotta diversa:

@override
Future<GuardResult> onBefore(RouteContext context) async {
  if (!isLoggedIn) {
    return redirect(
      LoginPage.path,
      data: {'returnTo': context.routeName},
      navigationType: NavigationType.pushReplace,
    );
  }
  return next();
}

Il metodo redirect() accetta:

Parametro Tipo Descrizione
path Object Percorso della rotta o RouteView
data dynamic Dati da passare alla rotta
queryParameters Map<String, dynamic>? Parametri query
navigationType NavigationType Tipo di navigazione (predefinito: pushReplace)
transitionType TransitionType? Transizione di pagina
onPop Function(dynamic)? Callback quando la rotta viene rimossa

abort()

Ferma la navigazione senza reindirizzare:

@override
Future<GuardResult> onBefore(RouteContext context) async {
  if (isMaintenanceMode) {
    showMaintenanceDialog();
    return abort(); // User stays on current route
  }
  return next();
}

setData()

Modifica i dati passati ai guard successivi e alla rotta:

@override
Future<GuardResult> onBefore(RouteContext context) async {
  final user = await fetchUser();
  setData({'user': user, ...?context.data});
  return next();
}

Guard Parametrizzati

Usa ParameterizedGuard quando hai bisogno di configurare il comportamento del guard per ogni rotta:

class RoleGuard extends ParameterizedGuard<List<String>> {
  RoleGuard(super.params);

  @override
  Future<GuardResult> onBefore(RouteContext context) async {
    final user = await Auth.user();
    if (!params.any((role) => user.hasRole(role))) {
      return redirect('/unauthorized');
    }
    return next();
  }
}

// Usage:
router.add(AdminPage.path, routeGuards: [
  RoleGuard(['admin', 'moderator'])
]);

Stack di Guard

Componi piu guard in un singolo guard riutilizzabile utilizzando GuardStack:

// Create reusable guard combinations
final adminGuards = GuardStack([
  AuthGuard(),
  RoleGuard(['admin']),
  AuditLogGuard(),
]);

router.add(AdminPage.path, routeGuards: [adminGuards]);

Guard Condizionali

Applica guard condizionalmente basandoti su un predicato:

router.add(DashboardPage.path, routeGuards: [
  ConditionalGuard(
    condition: (context) => context.routeName.startsWith('/admin'),
    guard: AdminGuard(),
  )
]);

Passaggio di dati a un'altra pagina

In questa sezione, mostreremo come puoi passare dati da un widget all'altro.

Dal tuo Widget, usa l'helper routeTo e passa i data che vuoi inviare alla nuova pagina.

// HomePage Widget
void _pressedSettings() {
    routeTo(SettingsPage.path, data: "Hello World");
}
...
// SettingsPage Widget (other page)
class _SettingsPageState extends NyPage<SettingsPage> {
  ...
  @override
  get init => () {
    print(widget.data()); // Hello World
    // or
    print(data()); // Hello World
  };

Altri esempi

// Home page widget
class _HomePageState extends NyPage<HomePage> {

  _showProfile() {
    User user = new User();
    user.firstName = 'Anthony';

    routeTo(ProfilePage.path, data: user);
  }

...

// Profile page widget (other page)
class _ProfilePageState extends NyPage<ProfilePage> {

  @override
  get init => () {
    User user = widget.data();
    print(user.firstName); // Anthony

  };

Gruppi di Rotte

I gruppi di rotte organizzano le rotte correlate e applicano impostazioni condivise. Sono utili quando piu rotte necessitano degli stessi guard, prefisso URL o stile di transizione.

Usa i gruppi di rotte quando hai bisogno di:

  • Applicare lo stesso route guard a piu pagine
  • Aggiungere un prefisso URL a un insieme di rotte (es. /admin/...)
  • Impostare la stessa transizione di pagina per rotte correlate

Puoi definire un gruppo di rotte come nell'esempio seguente.

appRouter() => nyRoutes((router) {
  ...
  router.group(() => {
    "route_guards": [AuthRouteGuard()],
    "prefix": "/dashboard",
    "transition_type": TransitionType.fade(),
  }, (router) {
    router.add(ChatPage.path);

    router.add(FollowersPage.path);
  });

Impostazioni opzionali per i gruppi di rotte sono:

Impostazione Tipo Descrizione
route_guards List<RouteGuard> Applica route guard a tutte le rotte del gruppo
prefix String Aggiunge un prefisso a tutti i percorsi delle rotte del gruppo
transition_type TransitionType Imposta la transizione per tutte le rotte del gruppo
transition PageTransitionType Imposta il tipo di transizione della pagina (deprecato, usa transition_type)
transition_settings PageTransitionSettings Imposta le impostazioni di transizione

Utilizzo dei Parametri delle Rotte

Quando crei una nuova pagina, puoi aggiornare la rotta per accettare parametri.

class ProfilePage extends NyStatefulWidget<HomeController> {
  static RouteView path = ("/profile/{userId}", (_) => ProfilePage());

  ProfilePage() : super(child: () => _ProfilePageState());
}

Ora, quando navighi verso la pagina, puoi passare l'userId

routeTo(ProfilePage.path.withParams({"userId": 7}));

Puoi accedere ai parametri nella nuova pagina in questo modo.

class _ProfilePageState extends NyPage<ProfilePage> {

  @override
  get init => () {
    print(widget.queryParameters()); // {"userId": 7}
  };
}

Parametri Query

Quando navighi verso una nuova pagina, puoi anche fornire parametri query.

Vediamo come.

  // Home page
  routeTo(ProfilePage.path, queryParameters: {"user": "7"});
  // navigate to profile page

  ...

  // Profile Page
  @override
  get init => () {
    print(widget.queryParameters()); // {"user": 7}
    // or
    print(queryParameters()); // {"user": 7}
  };

Nota: Finche il tuo widget di pagina estende NyStatefulWidget e la classe NyPage, puoi chiamare widget.queryParameters() per ottenere tutti i parametri query dal nome della rotta.

// Example page
routeTo(ProfilePage.path, queryParameters: {"hello": "world", "say": "I love code"});
...

// Home page
class MyHomePage extends NyStatefulWidget<HomeController> {
  ...
}

class _MyHomePageState extends NyPage<MyHomePage> {

  @override
  get init => () {
    widget.queryParameters(); // {"hello": "World", "say": "I love code"}
    // or
    queryParameters(); // {"hello": "World", "say": "I love code"}
  };

Suggerimento: I parametri query devono seguire il protocollo HTTP, Es. /account?userId=1&tab=2

Transizioni di Pagina

Puoi aggiungere transizioni quando navighi da una pagina modificando il tuo file router.dart.

import 'package:page_transition/page_transition.dart';

appRouter() => nyRoutes((router) {

  // bottomToTop
  router.add(SettingsPage.path,
    transitionType: TransitionType.bottomToTop()
  );

  // fade
  router.add(HomePage.path,
    transitionType: TransitionType.fade()
  );

});

Transizioni di Pagina Disponibili

Transizioni Base

  • TransitionType.fade() - Dissolve la nuova pagina in entrata mentre dissolve la vecchia pagina in uscita
  • TransitionType.theme() - Usa il tema delle transizioni di pagina del tema dell'app

Transizioni a Scorrimento Direzionale

  • TransitionType.rightToLeft() - Scorre dal bordo destro dello schermo
  • TransitionType.leftToRight() - Scorre dal bordo sinistro dello schermo
  • TransitionType.topToBottom() - Scorre dal bordo superiore dello schermo
  • TransitionType.bottomToTop() - Scorre dal bordo inferiore dello schermo

Transizioni Scorrimento con Dissolvenza

  • TransitionType.rightToLeftWithFade() - Scorre e dissolve dal bordo destro
  • TransitionType.leftToRightWithFade() - Scorre e dissolve dal bordo sinistro

Transizioni di Trasformazione

  • TransitionType.scale(alignment: ...) - Scala dal punto di allineamento specificato
  • TransitionType.rotate(alignment: ...) - Ruota attorno al punto di allineamento specificato
  • TransitionType.size(alignment: ...) - Cresce dal punto di allineamento specificato

Transizioni Congiunte (Richiede il widget corrente)

  • TransitionType.leftToRightJoined(childCurrent: ...) - La pagina corrente esce a destra mentre la nuova pagina entra da sinistra
  • TransitionType.rightToLeftJoined(childCurrent: ...) - La pagina corrente esce a sinistra mentre la nuova pagina entra da destra
  • TransitionType.topToBottomJoined(childCurrent: ...) - La pagina corrente esce verso il basso mentre la nuova pagina entra dall'alto
  • TransitionType.bottomToTopJoined(childCurrent: ...) - La pagina corrente esce verso l'alto mentre la nuova pagina entra dal basso

Transizioni Pop (Richiede il widget corrente)

  • TransitionType.leftToRightPop(childCurrent: ...) - La pagina corrente esce a destra, la nuova pagina resta ferma
  • TransitionType.rightToLeftPop(childCurrent: ...) - La pagina corrente esce a sinistra, la nuova pagina resta ferma
  • TransitionType.topToBottomPop(childCurrent: ...) - La pagina corrente esce verso il basso, la nuova pagina resta ferma
  • TransitionType.bottomToTopPop(childCurrent: ...) - La pagina corrente esce verso l'alto, la nuova pagina resta ferma

Transizioni Material Design Shared Axis

  • TransitionType.sharedAxisHorizontal() - Transizione con scorrimento e dissolvenza orizzontale
  • TransitionType.sharedAxisVertical() - Transizione con scorrimento e dissolvenza verticale
  • TransitionType.sharedAxisScale() - Transizione con scala e dissolvenza

Parametri di Personalizzazione

Ogni transizione accetta i seguenti parametri opzionali:

Parametro Descrizione Predefinito
curve Curva di animazione Curve specifiche della piattaforma
duration Durata dell'animazione Durate specifiche della piattaforma
reverseDuration Durata dell'animazione inversa Uguale a duration
fullscreenDialog Se la rotta e un dialogo a schermo intero false
opaque Se la rotta e opaca false
// Home page widget
class _HomePageState extends NyPage<HomePage> {

  _showProfile() {
    routeTo(ProfilePage.path,
      transitionType: TransitionType.bottomToTop()
    );
  }
...

Tipi di Navigazione

Durante la navigazione, puoi specificare uno dei seguenti se stai utilizzando l'helper routeTo.

Tipo Descrizione
NavigationType.push Inserisce una nuova pagina nello stack delle rotte della tua app
NavigationType.pushReplace Sostituisce la rotta corrente, eliminando la rotta precedente una volta che la nuova rotta e completata
NavigationType.popAndPushNamed Rimuove la rotta corrente dal navigatore e inserisce una rotta nominata al suo posto
NavigationType.pushAndRemoveUntil Inserisce e rimuove le rotte fino a quando il predicato restituisce true
NavigationType.pushAndForgetAll Naviga verso una nuova pagina e elimina qualsiasi altra pagina nello stack delle rotte
// Home page widget
class _HomePageState extends NyPage<HomePage> {

  _showProfile() {
    routeTo(
      ProfilePage.path,
      navigationType: NavigationType.pushReplace
    );
  }
...

Navigare indietro

Una volta che sei nella nuova pagina, puoi utilizzare l'helper pop() per tornare alla pagina precedente.

// SettingsPage Widget
class _SettingsPageState extends NyPage<SettingsPage> {

  _back() {
    pop();
    // or
    Navigator.pop(context);
  }
...

Se vuoi restituire un valore al widget precedente, fornisci un result come nell'esempio seguente.

// SettingsPage Widget
class _SettingsPageState extends NyPage<SettingsPage> {

  _back() {
    pop(result: {"status": "COMPLETE"});
  }

...

// Get the value from the previous widget using the `onPop` parameter
// HomePage Widget
class _HomePageState extends NyPage<HomePage> {

  _viewSettings() {
    routeTo(SettingsPage.path, onPop: (value) {
      print(value); // {"status": "COMPLETE"}
    });
  }
...

Navigazione Condizionale

Usa routeIf() per navigare solo quando una condizione e soddisfatta:

// Only navigate if the user is logged in
routeIf(isLoggedIn, DashboardPage.path);

// With additional options
routeIf(
  hasPermission('view_reports'),
  ReportsPage.path,
  data: {'filters': defaultFilters},
  navigationType: NavigationType.push,
);

Se la condizione e false, non avviene alcuna navigazione.

Cronologia delle Rotte

In Nylo Website, puoi accedere alle informazioni sulla cronologia delle rotte utilizzando gli helper seguenti.

// Get route history
Nylo.getRouteHistory(); // List<dynamic>

// Get the current route
Nylo.getCurrentRoute(); // Route<dynamic>?

// Get the previous route
Nylo.getPreviousRoute(); // Route<dynamic>?

// Get the current route name
Nylo.getCurrentRouteName(); // String?

// Get the previous route name
Nylo.getPreviousRouteName(); // String?

// Get the current route arguments
Nylo.getCurrentRouteArguments(); // dynamic

// Get the previous route arguments
Nylo.getPreviousRouteArguments(); // dynamic

Aggiornare lo Stack delle Rotte

Puoi aggiornare lo stack di navigazione programmaticamente utilizzando NyNavigator.updateStack():

// Update the stack with a list of routes
NyNavigator.updateStack([
  HomePage.path,
  SettingsPage.path,
  ProfilePage.path,
], replace: true);

// Pass data to specific routes
NyNavigator.updateStack([
  HomePage.path,
  ProfilePage.path,
],
  replace: true,
  dataForRoute: {
    ProfilePage.path: {"userId": 42}
  }
);
Parametro Tipo Predefinito Descrizione
routes List<String> obbligatorio Lista dei percorsi delle rotte verso cui navigare
replace bool true Se sostituire lo stack corrente
dataForRoute Map<String, dynamic>? null Dati da passare a rotte specifiche

Questo e utile per:

  • Scenari di deep linking
  • Ripristino dello stato di navigazione
  • Costruzione di flussi di navigazione complessi

Deep Linking

Il deep linking consente agli utenti di navigare direttamente a contenuti specifici all'interno della tua app utilizzando URL. Questo e utile per:

  • Condividere link diretti a contenuti specifici dell'app
  • Campagne di marketing che mirano a funzionalita specifiche nell'app
  • Gestione di notifiche che dovrebbero aprire schermate specifiche dell'app
  • Transizioni fluide dal web all'app

Configurazione

Prima di implementare il deep linking nella tua app, assicurati che il tuo progetto sia configurato correttamente:

1. Configurazione della Piattaforma

iOS: Configura i link universali nel tuo progetto Xcode

Android: Configura gli app link nel tuo AndroidManifest.xml

2. Definisci le Tue Rotte

Tutte le rotte che dovrebbero essere accessibili tramite deep link devono essere registrate nella configurazione del router:

// File: /lib/routes/router.dart
appRouter() => nyRoutes((router) {
  // Basic routes
  router.add(HomePage.path).initialRoute();
  router.add(ProfilePage.path);
  router.add(SettingsPage.path);

  // Route with parameters
  router.add(HotelBookingPage.path);
});

Utilizzo dei Deep Link

Una volta configurata, la tua app puo gestire URL in arrivo in vari formati:

Deep Link Base

Navigazione semplice verso pagine specifiche:

https://yourdomain.com/profile       // Opens the profile page
https://yourdomain.com/settings      // Opens the settings page

Per attivare queste navigazioni programmaticamente all'interno della tua app:

routeTo(ProfilePage.path);
routeTo(SettingsPage.path);

Parametri del Percorso

Per rotte che richiedono dati dinamici come parte del percorso:

Definizione della Rotta

class HotelBookingPage extends NyStatefulWidget {
  // Define a route with a parameter placeholder {id}
  static RouteView path = ("/hotel/{id}/booking", (_) => HotelBookingPage());

  HotelBookingPage({super.key}) : super(child: () => _HotelBookingPageState());
}

class _HotelBookingPageState extends NyPage<HotelBookingPage> {
  @override
  get init => () {
    // Access the path parameter
    final hotelId = queryParameters()["id"]; // Returns "87" for URL ../hotel/87/booking
    print("Loading hotel ID: $hotelId");

    // Use the ID to fetch hotel data or perform operations
  };

  // Rest of your page implementation
}

Formato dell'URL

https://yourdomain.com/hotel/87/booking

Navigazione Programmatica

// Navigate with parameters
routeTo(HotelBookingPage.path.withParams({"id": "87"}), queryParameters: {
              "bookings": "active",
            });

Parametri Query

Per parametri opzionali o quando sono necessari piu valori dinamici:

Formato dell'URL

https://yourdomain.com/profile?user=20&tab=posts
https://yourdomain.com/hotel/87/booking?checkIn=2025-04-10&nights=3

Accesso ai Parametri Query

class _ProfilePageState extends NyPage<ProfilePage> {
  @override
  get init => () {
    // Get all query parameters
    final params = queryParameters();

    // Access specific parameters
    final userId = params["user"];            // "20"
    final activeTab = params["tab"];          // "posts"

    // Alternative access method
    final params2 = widget.queryParameters();
    print(params2);                           // {"user": "20", "tab": "posts"}
  };
}

Navigazione Programmatica con Parametri Query

// Navigate with query parameters
routeTo(ProfilePage.path.withQueryParams({"user": "20", "tab": "posts"}));

// Combine path and query parameters
routeTo(HotelBookingPage.path.withParams({"id": "87"}), queryParameters: {
              "checkIn": "2025-04-10",
              "nights": "3",
            });

Gestione dei Deep Link

Puoi gestire gli eventi di deep link nel tuo RouteProvider:

class RouteProvider implements NyProvider {
  @override
  setup(Nylo nylo) async {
    nylo.addRouter(appRouter());

    // Handle deep links
    nylo.onDeepLink(_onDeepLink);
    return nylo;
  }

  _onDeepLink(String route, Map<String, String>? data) {
    print("Deep link route: $route");
    print("Deep link data: $data");

    // Update the route stack for deep links
    if (route == ProfilePage.path) {
      NyNavigator.updateStack([
        HomePage.path,
        ProfilePage.path,
      ], replace: true, dataForRoute: {
        ProfilePage.path: data,
      });
    }
  }

  @override
  boot(Nylo nylo) async {
    nylo.initRoutes();
  }
}

Test dei Deep Link

Per lo sviluppo e il test, puoi simulare l'attivazione dei deep link utilizzando ADB (Android) o xcrun (iOS):

# Android
adb shell am start -a android.intent.action.VIEW -d "https://yourdomain.com/profile?user=20" com.yourcompany.yourapp

# iOS (Simulator)
xcrun simctl openurl booted "https://yourdomain.com/profile?user=20"

Suggerimenti per il Debug

  • Stampa tutti i parametri nel tuo metodo init per verificare il parsing corretto
  • Testa diversi formati di URL per assicurarti che la tua app li gestisca correttamente
  • Ricorda che i parametri query vengono sempre ricevuti come stringhe, convertili nel tipo appropriato secondo necessita

Pattern Comuni

Conversione del Tipo dei Parametri

Poiche tutti i parametri URL vengono passati come stringhe, spesso avrai bisogno di convertirli:

// Converting string parameters to appropriate types
final hotelId = int.parse(queryParameters()["id"] ?? "0");
final isAvailable = (queryParameters()["available"] ?? "false") == "true";
final checkInDate = DateTime.parse(queryParameters()["checkIn"] ?? "");

Parametri Opzionali

Gestisci i casi in cui i parametri potrebbero mancare:

final userId = queryParameters()["user"];
if (userId != null) {
  // Load specific user profile
} else {
  // Load current user profile
}

// Or check hasQueryParameter
if (hasQueryParameter('status')) {
  // Do something with the status parameter
} else {
  // Handle absence of the parameter
}

Avanzato

Verificare se una Rotta Esiste

Puoi verificare se una rotta e registrata nel tuo router:

if (Nylo.containsRoute("/profile")) {
  routeTo("/profile");
}

Metodi NyRouter

La classe NyRouter fornisce diversi metodi utili:

Metodo Descrizione
getRegisteredRouteNames() Ottieni tutti i nomi delle rotte registrate come lista
getRegisteredRoutes() Ottieni tutte le rotte registrate come mappa
containsRoutes(routes) Verifica se il router contiene tutte le rotte specificate
getInitialRouteName() Ottieni il nome della rotta iniziale
getAuthRouteName() Ottieni il nome della rotta autenticata
getUnknownRouteName() Ottieni il nome della rotta sconosciuta/404

Ottenere gli Argomenti della Rotta

Puoi ottenere gli argomenti della rotta utilizzando NyRouter.args<T>():

class _ProfilePageState extends NyPage<ProfilePage> {
  @override
  Widget build(BuildContext context) {
    // Get typed arguments
    final args = NyRouter.args<NyArgument>(context);
    final userData = args?.data;

    return Scaffold(...);
  }
}

NyArgument e NyQueryParameters

I dati passati tra le rotte sono incapsulati in queste classi:

// NyArgument contains route data
NyArgument argument = NyArgument({'userId': 42});
print(argument.data); // {'userId': 42}

// NyQueryParameters contains URL query parameters
NyQueryParameters params = NyQueryParameters({'tab': 'posts'});
print(params.data); // {'tab': 'posts'}