5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Flutter] Navigatorライブラリのroutemasterを紹介する

Last updated at Posted at 2022-01-22

FlutterのNavigatorイケてないなと思って探していたらroutemasterという良さげなライブラリ見つけたのでメモも兼ねて紹介します。

routemasterの特徴

routemasterはFlutterのNavigator2.0をラッピングしたライブラリで以下の特徴があります。

  • URLとページのマッピングをシンプルに定義できる
  • 使いやすくシンプルなAPI(例:routemaster.push('/page')
  • ネストされたタブにも、非常に簡単なやり方で対応できる
  • 複数のルートマッピングを定義できる (ログイン済みとログアウト済みのユーザを分けたり
  • Observerを設定し、ルートの変化を簡単に聞き取ることができる
  • 160個以上の Unit/Widget/Integrationテストで動作検証済み

インストール

flutter pub add routemaster

セットアップ

MaterialAppのrouterDelegateに設定する

  • contextありの設定
MaterialApp.router(
  routerDelegate: RoutemasterDelegate(
    routesBuilder: (context) => RouteMap(routes: {
      '/': (routeData) => MaterialPage(child: PageOne()),
      '/two': (routeData) => MaterialPage(child: PageTwo()),
    }),
  ),
  routeInformationParser: RoutemasterParser(),
)
  • contextなしの設定
final routeMap = RouteMap(
 routes: {
   '/': (route) => MaterialPage(child: PageOne()),
   '/two': (route) => MaterialPage(child: PageTwo()),
 },
);

final routemaster = RoutemasterDelegate(
  routesBuilder: (context) => routeMap,
);

MaterialApp.router(
  routerDelegate: routemaster,
  routeInformationParser: RoutemasterParser(),
)

遷移させる

あとは簡単遷移させるだけ

/// 特定のパスに遷移する 
Routemaster.of(context).push('/two')

/// 前のパスに戻る
Routemaster.of(context).pop

Routeにパラメータを持たせる

Path Parameterの場合

// Routemaster.of(context).push('products/123')で123がパラメータとして渡る
RouteMap(routes: {
  '/products/:id': (route) => MaterialPage(
        child: ProductPage(id: route.pathParameters['id']),
      ),
  '/products/myPage': (route) => MaterialPage(MyPage()),
})

Query Parameterの場合

// Routemaster.of(context).push('/search?query=hello')でhelloがパラメータとして渡る
RouteMap(routes: {
  '/search': (route) => MaterialPage(
        child: SearchPage(query: route.queryParameters['query']),
      ),
})

現在のパス情報の取得

// フルパスの'/product/123?query=param'が取得できる
RouteData.of(context).path;
// Path ParameterのKeyとValueがMapで取得できる → Map: {'id': '123'}
RouteData.of(context).pathParameters;
// Query ParameterのKeyとValueがMapで取得できる → Map: {'query': 'param'}
RouteData.of(context).queryParameters;

Navigationの監視

RoutemasterObserverを継承したクラスを作り、RoutemasterDelegateに設定するだけ

class MyObserver extends RoutemasterObserver {
  @override
  void didPop(Route route, Route? previousRoute) {
    print('ルートが戻ったよ');
  }
  @override
  void didChangeRoute(RouteData routeData, Page page) {
    print('新しいルートだよ: ${routeData.path}');
  }
}

MaterialApp.router(
  routerDelegate: RoutemasterDelegate(
    observers: [MyObserver()],
    routesBuilder: (_) => routeMap,
  ),
  routeInformationParser: RoutemasterParser(),
);

Routeガード

条件によってRouteの出し分けが可能です。

  • 条件に一致しない場合、デフォルトのnot foundページを表示する。
'/protected-route': (route) => 
    canUserAccessPage()
      ? MaterialPage(child: ProtectedPage())
      : NotFound()
  • 条件に一致しない場合別のURLにリダイレクトさせる
'/protected-route': (route) => 
    canUserAccessPage()
      ? MaterialPage(child: ProtectedPage())
      : Redirect('/no-access'),
  • 条件に一致しない場合別のURLにリダイレクトさせる(URLは変えない)
'/protected-route': (route) => 
    canUserAccessPage()
      ? MaterialPage(child: ProtectedPage())
      : MaterialPage(child: CustomNoAccessPage())

404ページ

定義されていないURLの場合にエラーページに遷移させるようにする

RouteMap(
    onUnknownRoute: (route, context) {
        return MaterialPage(child: NotFoundPage());
    },
    routes: {
        '/': (_) => MaterialPage(child: HomePage()),
    },
)

リダイレクト

404以外にもリダイレクトができます。

  • あるルートを別のルートにリダイレクトさせる
RouteMap(routes: {
    '/one': (routeData) => MaterialPage(child: PageOne()),
    '/two': (routeData) => Redirect('/one'),
})
  • 定義されていないRouteは全てTopに遷移させる
RouteMap(
  onUnknownRoute: (_) => Redirect('/'),
  routes: {
    '/': (_) => MaterialPage(child: LoginPage()),
  },
)
  • リダイレクト先にパラメータを引き渡す
RouteMap(routes: {
    '/user/:id': (routeData) => MaterialPage(child: UserPage(id: id)),
    '/profile/:uid': (routeData) => Redirect('/user/:uid'),
})

RouteMapの再構築

アプリ起動後の処理によってRouteMap自体を置き換えることができます。
ログイン前とログイン後でRouteが全くことなる場合など

final loggedOutMap = RouteMap(
  onUnknownRoute: (route, context) => Redirect('/'),
  routes: {
    '/': (_) => MaterialPage(child: LoginPage()),
  },
);

final loggedInMap = RouteMap(
  routes: {
    '/': (_) => MaterialPage(child: HomePage()),
  },
);

MaterialApp.router(
  routerDelegate: RoutemasterDelegate(
    routesBuilder: (context) {
      // AppStateの状態によってRouteMapを切り替える
      final appState = Provider.of<AppState>(context);
      return appState.isLoggedIn ? loggedInMap : loggedOutMap;
    },
  ),
  routeInformationParser: RoutemasterParser(),
);

最後に

READMEを記載しただけになってしまいましたが、いかがでしょうか。
必要な機能はすべて揃っているかなと個人的に思います。
全て実装して試したわけではないので、また必要があれば更新します。
ディープリンクに関しても、対応しているようなので別の記事でまとめてみようと思います。

参考

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?