【Flutter】Deep Links(Universal Links)が効かない
TL;DR
原因は、RunnerProfile.entitlements
だけでなくRunner.entitlements
にも「Associated Domains」の設定追加が必要だったこと。
はじめに
FlutterアプリへのDeepLinks(Universal Links(ユニバーサルリンク))の導入で2日間くらい詰んだので、備忘する。
⭐️最後にUniversal Links導入用の見直しチェックリストもあるよ⭐️
前提
ナビゲーションはgo_routerを採用
内容
公式Doc通りに、iOSとAndroidそれぞれ設定を行った。
しかし、Androidはうまく機能するが、iOSはwebブラウザが開かれてapple-app-site-association
をホストしているサーバーにアクセスして404エラーになるだけで、アプリは起動しない。
何か設定に不備があるのだろうとFlutterとAppleの公式Doc、Qiita、Zenn、StackOverflowを漁りまくったが、どれを見直したり試したりしても解消されない。
ふとした時に、「そういえばentitlements
ファイルが2個あるな〜〜〜」と思って中身をのぞいたところ、なんと差異があるやないか。どっちがiOSビルドで使われてるか知らんけどさすがによろしくないやろ。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- AppleSignInの要素しかない -->
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- AppleSignInとAssociatedDomainsの2つの要素がある -->
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:exapmle.com</string>
</array>
</dict>
</plist>
ってことで、Runner.entitlements
にもAssociated Domainsを追加して再ビルドしたらうまくいった。
Flutter公式Docの「Other editors」じゃなくて「Xcode」で設定した人はけっこう陥っているかも?
たぶんXcodeから設定するとRunnerProfile.entitlements
が新規作成されてそっちに設定が記述されるのかな?
iOSエンジニア→Flutterエンジニアの人だと容易に気づけるのかもしれない。(私はwebからの人なので2日間かかった)
見直しチェックリスト
2日間でいろんな見直しをしたので今後のためにもそれをリスト化した。
-
info.plist
にFlutterDeepLinkingEnabledをtrueで追加したか - AppleDeveloperの対象IdentifiersのCapabilitiesにもAssociated Domainsのチェックは入っているか
- AppleDeveloperのProfilesに対象アプリのプロビジョニングプロファイルはあるか?かつ、iOSになっているか?有効期限は切れていないか?
-
apple-app-site-association
はホスティングサーバーに「<ウェブドメイン>/.well-known/apple-app-site-association」の構造でデプロイされているか? -
apple-app-site-association
ファイルの拡張子は無いか?「.json」になってしまってないか? - ホスティングサーバーの
apple-app-site-association
へリクエストした際のレスポンスのstatusCodeは200か?content-typeはapplication/jsonになっているか?- 「curl -v」で試行するとよい
- application/jsonでない場合はホスティングサーバーの設定でjsonを返すように設定してあげる必要がある
- Firebase Hostingを使っている場合は
firebase.json
に下記を追記すればOK。Apacheはhttp.conf
かな?Nginxは知らん。firebase.json"headers": [ { "source": "/.well-known/apple-app-site-association", "headers": [ { "key": "Content-Type", "value": "application/json" } ] }, // Androidも対応する場合は下記も設定しておく { "source": "/.well-known/assetlinks.json", "headers": [ { "key": "Content-Type", "value": "application/json" } ] } ]
- Firebase Hostingを使っている場合は
- AppleのCDNはすでに
apple-app-site-association
をキャッシュしてくれているか?- 下記コマンドを実行して200でファイル内容が返って来ればOK
curl -v https://app-site-association.cdn-apple.com/a/v1/{ホスティングサーバーのドメイン}
- 下記コマンドを実行して200でファイル内容が返って来ればOK
- テストしている環境はIP制限がかかってないか?
- かかっている場合はアプリインストール時にAppleのCDNから
apple-app-site-association
を取得できないのでmode=developerでドメインを追加する必要がある
- かかっている場合はアプリインストール時にAppleのCDNから
- いろいろ設定を更新したあとは、アプリをアンインストール後に再インストールしてテストしているか?(シミュレータも新しくすると尚良し)
- テストはブラウザにURLを直打ちしていないか?
- ブラウザ直打ちは機能しないので、何らかのアプリでURLをタップするか、ターミナルから下記コマンドでシミュレータにURLを開かせるかでテストする
xcrun simctl openurl booted {任意のUnivesalLinksのURL}
- ブラウザ直打ちは機能しないので、何らかのアプリでURLをタップするか、ターミナルから下記コマンドでシミュレータにURLを開かせるかでテストする
補足
- GoRouterクラスはmain.dartから切り出して別ファイル化しててもOK
- GoRouterクラスはProvider化して、runAppしているウィジェットで
routerConfig: ref.read(goRouterProvider),
で設定しててもOK
Discussion