iOS の Universal Links と Android の App Links は、どちらもドメインのルートに HTTPS で配信される JSON ファイルを要求します。iOS は /.well-known/apple-app-site-association。Android は /.well-known/assetlinks.json。localhost は、OS がアプリに関連づけるホスト名でどちらも配信できません。だからトンネルします。
各プラットフォームの実際の要件
iOS Universal Links
アプリのインストール時に OS が https://your-domain.com/.well-known/apple-app-site-association(または /apple-app-site-association)を取得します。アプリの associated domains エンタイトルメントと内容を照合します。取得は本物の HTTPS で成功する必要があります。iOS はこの目的で自己署名証明書を信頼せず、localhost も信頼しません。
Android App Links
Android は https://your-domain.com/.well-known/assetlinks.json を取得して App Links を検証します。ファイルにはアプリの SHA-256 フィンガープリントを列挙する必要があります。検証はインストール時と初回起動時に行われます。同じ制約:本物の HTTPS、本物のドメイン。
なぜ localhost では直接できないのか
mkcert がノート PC のブラウザーで信頼された HTTPS を与えても、モバイル OS はあなたのローカル CA を信頼しません。そして apple-app-site-association のドメインは、アプリのエンタイトルメントの associated-domain と一致する必要があり——それは localhost ではなく、DNS で解決可能な本物のドメインです。
専用の staging ドメインで回避するチームもあります。動きますが、反復ループが遅い。localhost トンネルは、モバイルデバイスが文句なく到達する本物のサブドメイン上の本物の HTTPS URL を与えます。
配線の仕方
- ローカル dev サーバーの
/.well-known/からapple-app-site-associationとassetlinks.jsonを配信。両ファイル。両ルート。 npx portpreview 3000(dev サーバーの使うポート)を実行。- トンネルのホスト名をメモ——
abc123.portpreview.devのような。 - iOS アプリの associated domains エンタイトルメントに
applinks:abc123.portpreview.devを追加。Android の intent filter に同じホストを。 - 実機でアプリをビルド・インストール(シミュレーターは Universal Link の挙動が変)。
- 別のアプリ——メモ、メール、QR コード——から URL を開き、ブラウザーではなくインストール済みアプリにルートされるのを見る。
ディープリンクのトンネリングの落とし穴:予約サブドメインがない限り、トンネルのホスト名はセッション間で変わります。ローテーションごとに、新しい associated-domain エントリでアプリを再ビルドする必要があります。ディープリンクの挙動を頻繁に反復するなら、予約サブドメインを取得しましょう。
apple-app-site-association では content-type が重要
iOS は拡張子なしのファイルと、content-type application/json(新しい iOS)または application/pkcs7-mime(古い、署名形式)を期待します。ほぼすべての現代アプリはプレーン JSON バリアントを使います。dev サーバーが正しい content-type を返すことを確認してください。さもないと iOS は有用なエラーもなく静かにファイルを拒否します。
まずデスクトップブラウザーからテスト:https://your-tunnel.portpreview.dev/.well-known/apple-app-site-association を開き、JSON がレンダリングされ、dev tools の content-type ヘッダーが正しいことを確認。間違っていれば、シミュレーターで Universal Link バグを追う前に直しましょう。
その他のディープリンクデバッグの罠
アプリエンタイトルメントの不一致
associated-domains エンタイトルメントが applinks:abc.portpreview.dev なのに apple-app-site-association が def.portpreview.dev を列挙していると、iOS は取得しません。ホスト名は一貫させる必要があります。
Safari 内からの Universal Link
Safari 内(タブのある同じアプリ)で Universal Link をタップすると、アプリではなく Safari で開くことがあります。これは仕様です——iOS は「ユーザーがリンクをクリックするたびにアプリを開く」というトリックを防ぎます。代わりにメモやメールからテストしてください。
Android App Links と digital asset links
Android は カスタム URL スキーム(yourapp://path)もサポートし、HTTPS や assetlinks.json は不要です。テストは簡単ですが安全性は低い——どのアプリも同じスキームを登録できます。本番品質のディープリンクなら、App Links が答えです。
私たちが使うモバイルテストフロー
ディープリンクつきで iOS と Android の両方を出荷するプロジェクトでは:
.well-knownファイルを配信するバックエンドを起動。npx portpreview 3000でトンネル。- トンネル URL がセッションで安定したら(または予約サブドメインを使う)、アプリの associated-domain エントリを更新してビルド。
- 実機で QA——新規インストールと更新の両方。
- OAuth とディープリンクの組み合わせ(アプリに戻ってリダイレクトするサインインプロバイダー)は OAuth コールバックテストと組み合わせる。
セットアップは初回は面倒です。その後、トンネル URL は Xcode と Gradle スキームのもう 1 つの env 変数にすぎません。
より広いモバイルテストパターンは localhost トンネルでのモバイルテストを参照。PortPreview のウェイトリストへ。