flutter-setup-declarative-routing について
go_router を使ったルーティングとディープリンクの実装ガイドです。Flutter 開発者向けに、ルーター設定、プラットフォームリンク、ネストナビゲーションを説明します。
主な機能
- 01GoRouter のルートツリー設定
- 02Web のパス URL 戦略設定
- 03Android と iOS のディープリンク設定
- 04StatefulShellRoute によるネストナビゲーション
- 05拡張メソッドによるプログラムナビゲーション
活用シーン
- 01Flutter アプリの宣言的ルーティング設定
- 02プラットフォームリンクから特定画面を開く
- 03状態を保持するボトムナビゲーション分岐の作成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ flutter/ agent-plugins --skill flutter-setup-declarative-routingインストール後、Claude Code で/flutter-setup-declarative-routingを入力して読み込まれたか確認します。
詳細
ルーティングとディープリンクの実装
目次
基本概念
Flutter で宣言型ルーティングを行うには、go_router パッケージを使用します。複雑なルーティングシナリオ、ディープリンク、ネストされたナビゲーションに対応する堅牢な API を提供します。
- GoRouter:アプリケーションのルートツリーを定義する中心的な設定オブジェクトです。
- GoRoute:URL パスを Flutter の画面にマッピングする標準的なルートです。
- ShellRoute / StatefulShellRoute:子ルートを永続的な UI シェル(例:
BottomNavigationBar)でラップします。StatefulShellRouteは、並列ナビゲーションブランチの状態を保持します。 - Path URL Strategy:Web URL からデフォルトの
#フラグメントを削除します。これは、プラットフォーム間でクリーンなディープリンクを実現するために不可欠です。
ワークフロー:アプリケーションとルーターの初期化
このワークフローに従って、go_router を使用する新しい Flutter アプリケーションを初期化し、ルートルーティングの仕組みを設定します。
タスクの進捗
- Flutter アプリケーションを作成します。
-
go_router依存関係を追加します。 - Web/ディープリンク用の URL 戦略を設定します。
-
GoRouterの設定を実装します。 - ルーターを
MaterialApp.routerにバインドします。
1. アプリケーションのひな形を作成する
次のコマンドを実行して、アプリを作成し、必要なルーティングパッケージを追加します。
flutter create <app-name>
cd <app-name>
flutter pub add go_router
2. ルーターを設定する
トップレベルの GoRouter インスタンスを定義します。redirect パラメーターを使用して、認証や状態に基づくルーティングを処理します。
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter_web_plugins/url_strategy.dart';
void main() {
// Use path URL strategy to remove the '#' from web URLs
usePathUrlStrategy();
runApp(const MyApp());
}
final GoRouter _router = GoRouter(
initialLocation: '/',
routes: [
GoRoute(
path: '/',
builder: (context, state) => const HomeScreen(),
routes: [
GoRoute(
path: 'details/:id',
builder: (context, state) => DetailsScreen(id: state.pathParameters['id']!),
),
],
),
],
errorBuilder: (context, state) => ErrorScreen(error: state.error),
);
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: _router,
title: 'Routing App',
);
}
}
ワークフロー:プラットフォームのディープリンク設定
ネイティブプラットフォームを設定して、特定の URL を検知し、Flutter アプリケーションにルーティングします。
タスクの進捗
- 対象プラットフォーム(iOS、Android、または両方)を決定します。
- Android 用の条件付き設定を適用します(Manifest + Asset Links)。
- iOS 用の条件付き設定を適用します(Plist + Entitlements + AASA)。
- バリデーターを実行 -> エラーを確認 -> 修正します。
Android を設定する場合:
AndroidManifest.xmlを変更する:.MainActivityの<activity>タグ内にインテントフィルターを追加します。
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" android:host="yourdomain.com" />
<data android:scheme="https" />
</intent-filter>
assetlinks.jsonをホストする:次の JSON をhttps://yourdomain.com/.well-known/assetlinks.jsonで提供します。
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.yourcompany.yourapp",
"sha256_cert_fingerprints": ["YOUR_SHA256_FINGERPRINT"]
}
}]
iOS を設定する場合:
Info.plistを変更する:Flutter のデフォルトのディープリンクハンドラーを有効にします。 注:サードパーティのディープリンクプラグイン(例:app_links)を使用する場合は、競合を防ぐためにNOに設定してください。
<key>FlutterDeepLinkingEnabled</key>
<true/>
Runner.entitlementsを変更する:関連付けられたドメインを追加します。
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:yourdomain.com</string>
</array>
apple-app-site-associationをホストする:次の JSON(.json拡張子なし)をhttps://yourdomain.com/.well-known/apple-app-site-associationで提供します。
{
"applinks": {
"apps": [],
"details": [{
"appIDs": ["TEAM_ID.com.yourcompany.yourapp"],
"paths": ["*"],
"components": [{"/": "/*"}]
}]
}
}
検証ループ
バリデーターを実行 -> エラーを確認 -> 修正します。
- Android:ADB を使用してテストします。
adb shell 'am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://yourdomain.com/details/123"' com.yourcompany.yourapp - iOS:起動済みのシミュレーターで
xcrunを使用してテストします。xcrun simctl openurl booted https://yourdomain.com/details/123
ワークフロー:ネストされたナビゲーションの実装
StatefulShellRoute を使用して、子ルートの状態を保持する永続的な UI シェル(ボトムナビゲーションバーなど)を実装します。
タスクの進捗
-
GoRouterの設定でStatefulShellRoute.indexedStackを定義します。 - 各ナビゲーションタブ用に
StatefulShellBranchインスタンスを作成します。 -
StatefulNavigationShellを使用してシェルウィジェットを実装します。
final GoRouter _router = GoRouter(
initialLocation: '/home',
routes: [
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) {
return ScaffoldWithNavBar(navigationShell: navigationShell);
},
branches: [
StatefulShellBranch(
routes: [
GoRoute(
path: '/home',
builder: (context, state) => const HomeScreen(),
),
],
),
StatefulShellBranch(
routes: [
GoRoute(
path: '/settings',
builder: (context, state) => const SettingsScreen(),
),
],
),
],
),
],
);
例
高忠実度のシェルウィジェット実装
StatefulNavigationShell を使用してブランチの切り替えを処理する UI シェルを実装します。
class ScaffoldWithNavBar extends StatelessWidget {
const ScaffoldWithNavBar({
required this.navigationShell,
super.key,
});
final StatefulNavigationShell navigationShell;
void _goBranch(int index) {
navigationShell.goBranch(
index,
// Support navigating to the initial location when tapping the active tab.
initialLocation: index == navigationShell.currentIndex,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: navigationShell,
bottomNavigationBar: NavigationBar(
selectedIndex: navigationShell.currentIndex,
onDestinationSelected: _goBranch,
destinations: const [
NavigationDestination(icon: Icon(Icons.home), label: 'Home'),
NavigationDestination(icon: Icon(Icons.settings), label: 'Settings'),
],
),
);
}
}
プログラムによるナビゲーション
go_router が提供する context.go() および context.push() 拡張メソッドを使用します。
// Replaces the current route stack with the target route (Declarative)
context.go('/details/123');
// Pushes the target route onto the existing stack (Imperative)
context.push('/details/123');
// Navigates using a named route and path parameters
context.goNamed('details', pathParameters: {'id': '123'});
// Pops the current route
context.pop();
コメント
Markdown 対応