結論
setUrlStrategy(PathUrlStrategy());
を設定するとOK!
やりたいこと
Flutterで go_router
等でルーティングすると、Webでは以下のようなURLになりますね。
https://example.com/#/pages/1
Flutter Webをホスティングし上記URLをクリックすると、URLがハンドリングされ go_router
で設定したパスに飛びます。同一のFlutterアプリをモバイル向けに公開している場合、アプリインストール済の端末ではブラウザではなく、アプリ側で開いてほしいということがあります。
http[s]から始まるURLをアプリでハンドリングするには、iOSでは「universal link」、Androidでは「app link」という仕組みを利用する必要があります。
アプリリンクやユニバーサルリンクの設定方法については下記参照してください。Androidは AndroidManifest.xml
、 iOSは info.plist
を編集する必要があります。また、Androidは assetlinks.json
、iOSは apple-app-site-association
をホスティングする必要があります。詳細は今回は割愛。ここまでは設定できているとします。
何が動かないか
ところが、上記設定してもうまくリンクは動いてくれませんでした。アプリは開くのですが、その後のハンドリングがうまくいかず、どのパスを設定してもアプリトップが開いてしまうのです。Githubを眺めると、 go_router
ではfragmentとURLのパスは区別するとありました。すなわち https://example.com/#/pages/1
と https://example.com/pages/1
を区別するということです。
これは困りました。 #
なしではアプリ側は問題ないかもしれませんが、今度はWeb側が動作しなくなるからです。
#
を消す
実はWebのパスから #
を消去するオプションがありました。 巷では setUrlStrategy(PathUrlStrategy());
を使えとよく言われますが、これはモバイル版ではビルドすることができません。様々なワークアラウンドがありますが、実は最終的には公式ドキュメントにある usePathUrlStrategy();
を用いればモバイルでもビルドができました。
void main() {
usePathUrlStrategy();
runApp(ExampleApp());
}
これを用いて下記リンクを開くと..
https://example.com/pages/1
Webでは当該ページがブラウザで開き、インストール済端末からだとアプリで開くことができるようになりました!
これを使ったアプリ
上記使ったアプリを公開しております。割り勘を行うことができるアプリです!
その他TIPS
Web側はFirebaseでホスティングしているのですが、 firebase.json
を下記のようにしておくと、 assetlinks.json
と apple-app-site-association
を web/.well-knwon
におくだけでこれらをホスティングすることができます。あまりWebになかったので、ぜひどうぞ!
{
"hosting": {
"public": "build/web",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"headers": [
{
"source": "/.well-known/assetlinks.json",
"headers": [
{
"key": "Content-Type",
"value": "application/json"
}
]
},
{
"source": "/.well-known/apple-app-site-association",
"headers": [
{
"key": "Content-Type",
"value": "application/json"
}
]
}
],
"rewrites": [
{
"source": "/.well-known/assetlinks.json",
"destination": "/.well-known/assetlinks.json"
},
{
"source": "/.well-known/apple-app-site-association",
"destination":"/.well-known/apple-app-site-association"
},
{
"source": "**",
"destination": "/index.html"
}
]
}
}