TWAのアドレスバーが消えない?中学生でもわかる「アップロード鍵」と「アプリ署名鍵」
こんにちは、非エンジニアのRyoです。今回は TWA(Trusted Web Activity) でアプリを公開しようとしたときに直面した「アドレスバーが消えない」問題について、書きました。ちなみに僕も最初は「設定コピペするだけで終わりでしょ?」って思ってたんですが、マジで甘かった……。でも原因が分かれば、解決は意外とシンプル。この記事を読めば、あなたも同じ沼にハマらずに済むはずです。
💡 この記事の狙い
・中学生でも「なるほど!」と膝を打てるレベルで理解できるように書く
・エンジニアでなくても手順どおり進めれば必ず成功できるように構成
・TWAだけでなく、Androidの鍵管理の基本もまとめておさらい
・読み物としても退屈しないよう、例え話・図解イメージ・Q&Aも盛り込む
TWAってそもそも何?
Trusted Web Activity(以下TWA)は、ざっくり言うと「WebサイトをほぼそのままAndroidアプリとして配信できる魔法の仕組み」です。普通ネイティブアプリを作るにはKotlinやJavaでゴリゴリ書く必要がありますが、TWAを使えば PWA(Progressive Web App) をベースに、Chromeが全画面でWebコンテンツを描画してくれるのでフロントを書き直す必要がありません。
- メリット
- Webの知識でアプリが出せる
- 同一コードベースでWebとアプリを保守できる
- APK/AABサイズが小さい
- 更新が楽(Webをデプロイするだけ)
- デメリット
- Chromeエンジンに依存する
- 一部ネイティブAPIは使えない
- assetlinks.jsonの設定をミスると今回のようなトラブルが起きる
🚀 ワンポイント:TWAはAndroid 7.0(Nougat)以降でサポート。古い端末だと動かないので対象OSを要確認。
今回起きたトラブルの概要
内部テストトラックにAABをアップして端末にインストールしたところ、Chromeのアドレスバー がしっかり表示されてしまい、全画面化されない現象が発生。「え、TWAなのに普通のカスタムタブじゃん!」とガッカリ。
原因を探るためにやったことは以下のとおり。
- Play Console側の設定を確認
- AndroidManifestのIntentFilterを再確認
- サーバー側の
/.well-known/assetlinks.json
を取得して中身を比較 - Digital Asset Links API でレスポンスを確認
- Twitter・Qiita・StackOverflowを徘徊して同様の事例を漁る
最終的に分かったのは「assetlinks.jsonにアップロード鍵のフィンガープリントを書いていた」という超単純ミスでした。マジで自分に突っ込みたくなるレベルの凡ミス…。でも同じ落とし穴にハマる人が後を絶たないので、この記事で完全に理解しておきましょう。
assetlinks.jsonとは?
assetlinks.json
はサイトのルート直下(https://example.com/.well-known/assetlinks.json
)に配置する JSON形式の宣言ファイル です。Android側はこのファイルを読み取って、アプリが特定サイトのURLを安全にハンドルして良いかを検証します。
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.app",
"sha256_cert_fingerprints": [
"11:22:33:44:...:FF"
]
}
}
]
要点は sha256_cert_fingerprints
。ここに書く値が違うと、Androidは「このアプリは信頼に足る証明書を持っていない」と判断し、TWAの全画面モードを許可しません。その結果、アドレスバーが残ってしまうわけです。
鍵が2種類ある理由
AndroidアプリをPlayストア経由で配信する場合、「アップロード鍵」と「アプリ署名鍵」 の2種類が存在します。これが話をややこしくする元凶ですが、Googleが採用する App Signing by Google Play という仕組みを理解するとスッキリ整理できます。
キーの種類 | 説明 | 管理者 | 実際の配布APKに使われる? |
---|---|---|---|
アップロード鍵 | 開発者がAABをPlay Consoleにアップロードする際に使う | 開発者 | ❌ 使われない |
アプリ署名鍵 | Googleがストア配信用のAPKを再署名するときに使う | ✅ 使われる |
📜 歴史背景:昔は開発者が1つのキーストアをずっと管理する方式でした。ところが「鍵を紛失してバージョンアップ不能」「鍵が流出して改ざんAPKが野放し」といった事故が多発。そこでGoogleが公式に鍵を預かり、開発者はアップロード用の鍵だけ保持すれば良い仕組みに移行しました。
アップロード鍵とアプリ署名鍵の違い
ここで再度表にまとめてみましょう。
項目 | アップロード鍵 | アプリ署名鍵 |
---|---|---|
用途 | Play ConsoleにAABを提出する署名 | ユーザーに配信されるAPKの正式署名 |
SHA-256を取得する場所 | keystore を keytool で解析 | Play Console → アプリの完全性 |
assetlinks.jsonで使う? | ❌ 絶対ダメ | ✅ 必須 |
紛失時の対処 | Googleに再登録申請可能 | 不可(基本的に永続) |
ここが混同されがちですが、assetlinks.json に書くのはアプリ署名鍵 のSHA-256一択です。アップロード鍵の値を書いた瞬間にTWAはフルスクリーンになりません。
例え話で理解する2つの鍵
🏫 学校の答案用紙たとえ
- あなた(開発者)はテスト答案を「提出袋」に入れて先生(Google)に渡す。この提出袋に貼るシールが アップロード鍵。
- 先生は提出された答案を採点し、公印スタンプを押してクラスに返却する。このスタンプが アプリ署名鍵。
- 生徒(ユーザー)は「公印がある答案」を見て本物だと信頼する。
assetlinks.json に書くのは当然「先生の公印(アプリ署名鍵)」ですよね? 提出袋のシールが貼ってあっても、生徒はそんなの見ません。
これでイメージは完璧。アップロード鍵=途中経由の本人確認用、アプリ署名鍵=最終的な公式証明書 と覚えてください。
Play Consoleで鍵を確認する手順
- Play Consoleにログインし対象アプリを開く。
- 左メニュー 「アプリの完全性」 → 「アプリ署名」 を選択。
- 「SHA-256 証明書フィンガープリント」の項目をコピー。
- メモ帳などに貼り付けて桁数(64文字)と「:(コロン)」で区切られているかを確認。
✅ ポイント:SHA-256は
AA:BB:CC:...:FF
の形式で58個のコロンがある64バイト(+コロン)文字列。1文字でも欠けると無効になるので要注意。
assetlinks.jsonを正しい値に書き換える
# 例: public/.well-known/assetlinks.json を開く
nano public/.well-known/assetlinks.json
JSON内 "sha256_cert_fingerprints": ["..."]
を アプリ署名鍵のSHA-256 に置き換えたら保存してデプロイ。
Netlifyの場合
git add public/.well-known/assetlinks.json
git commit -m "fix: correct SHA-256 for Play Store"
git push
🔄 キャッシュ注意:DNSやCDNのキャッシュが残っていると古いファイルを返す場合があります。
curl -H "Cache-Control: no-cache"
で強制取得すると確実。
Digital Asset Links APIで動作確認
Google公式APIを叩くと設定が正しいか即座に分かります。
curl "https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://example.com&relation=delegate_permission/common.handle_all_urls"
source.web.site
に自分のドメインを指定- レスポンスに
"target": {"namespace": "android_app"...}
が返り、SHA-256が一致していればOK
もし不一致エラーが出たら?
- サーバーに配置したファイルが最新か確認
https://example.com/.well-known/assetlinks.json
をブラウザで直接開いて内容をチェック- JSON構文エラー(,(カンマ)忘れ など)がないかバリデータを通す
よくあるエラーと対処法
症状 | 原因 | 対処法 |
---|---|---|
アドレスバーが消えない | assetlinks.jsonのSHA-256がアップロード鍵 | アプリ署名鍵に書き換え |
JSONが404 | 配置パスが間違い / ドメイン違い | /.well-known/ 直下に設置 + https有効化 |
403 Permission Denied | サーバーの閲覧制限 | publicアクセス可能に設定 |
Invalid Relation | relationの配列が誤字 | サンプルをコピペし再確認 |
AABアップ後に署名が変わった | Googleが鍵ローテーションを自動実行 | 新しいSHA-256を再取得・更新 |
鍵管理の落とし穴とベストプラクティス
- キーストアのバックアップ
・アップロード鍵は失効・再発行可能とはいえ、プロセスが面倒。
・クラウドストレージに暗号化して二重バックアップ推奨。 - 権限分離
・法人の場合、アップロード専用アカウントを作り、署名鍵へ誤アクセスできないように。 - CI/CDの導入
・GitHub Actionsでkeystoreを扱う場合、Secretsに環境変数として登録し、公開リポジトリには絶対にコミットしない。 - 鍵ローテーション
・Google Play は2021年以降自動ローテーション機能を提供。年1回チェックしよう。 - 監査ログ
・Play Consoleの「デベロッパーアカウント」→「アクティビティログ」で不審操作を検出。
Q&A:よくある疑問10連発
Q1. assetlinks.jsonって複数行書ける?
A. 書けます。別パッケージ名や別証明書を追加するときは要素を増やします。Q2. ドメインがwwwあり/なしで2つある場合は?
A. 両方に同じJSONを置くか、リダイレクトで統一を。Q3. iOSのUniversal Linksとも共存できる?
A. 可能ですがapple-app-site-association
ファイルも用意が必要。Q4. 開発用のdebug.keystoreではテストできない?
A. ローカルで直接APKをインストールするだけなら可能。ただしストア経由では無理。Q5. AABを上げ直す必要は?
A. assetlinks.json 修正だけなら不要。Q6. 一度公開した鍵を変更したい
A. Googleに申請し鍵ローテーション対応を待つ。Q7. Webサーバーがサブディレクトリ配信の場合?
A. ルートドメイン保持者でないとダメ。サブドメインを使うなど配置場所を確保。Q8. Firebase Hostingでも動く?
A.public/.well-known/
をルート直下に作れば動作。Q9. JSONのContent-Typeは必須?
A. application/json を設定するのが望ましいが、多くのブラウザはtext/plainでも解析可能。Q10. Windowsサーバーでパスがうまく行かない
A. 「.well-known」をドットから始めるのを許可する設定をIISで追加。
僕が実際にやらかした失敗談
失敗1:SHA-256をコピペするときに空白が混入
Play Consoleからコピーするとき、改行コードや不可視文字が混ざる場合があります。JSONバリデータは通るのにAndroid側でエラーになり、原因特定まで半日溶け ました。
失敗2:テストトラックだけキーを変え忘れ
内部テスト用に別パッケージ名を使ったのに assetlinks.json
を本番と共用。結果、テスターから「アドレスバー見えてるぞ」と即フィードバック。環境ごとにJSONを出し分けましょう。
失敗3:CDNキャッシュ地獄
Netlifyのキャッシュが強力過ぎて、正しいJSONに置き換えたのに古いファイルが配信され続けました。?v=timestamp
ハックでやり過ごしつつ、最終的にキャッシュパージAPIを叩いて解決。
一歩先へ:鍵ローテーションとセキュリティ強化
Googleは2023年以降、Key Rotation を正式サポートしました。万が一アプリ署名鍵が危険に晒された場合、以下のフローで安全に新鍵へ移行可能です。
- Play Consoleで鍵ローテーションのリクエストを送信
- Googleの審査(数日〜数週間)
- 新しい署名鍵が発行され、旧鍵から段階的に切替
- 新しいSHA-256をassetlinks.jsonに追記(古い鍵はしばらく併記)
☝️ 注意:ローテーション後は必ず全ユーザーにアップデートを促すリリースを行いましょう。旧鍵のみを信頼する古いバージョンが存在するとリンク検証に失敗します。
まとめとチェックリスト
チェック項目 | やった? |
---|---|
Play Consoleでアプリ署名鍵のSHA-256を取得 | ✅ |
assetlinks.jsonを更新しサーバーに配置 | ✅ |
Digital Asset Links APIで検証 | ✅ |
アプリを再インストールしてフルスクリーン化確認 | ✅ |
キャッシュをクリアして再確認 | ✅ |
これだけ押さえれば アドレスバーが消えない問題は99.9%解決 します。マジで悩んでた時間が嘘みたいに一瞬で終わるので、ぜひ実践してみてください。
付録A:コマンドリファレンス
# keystoreからSHA-256を抽出
keytool -list -v -keystore upload-keystore.jks -alias upload -storepass pass -keypass pass | grep "SHA256"
# assetlinks.jsonをローカルで確認
cat public/.well-known/assetlinks.json | jq
# Digital Asset Links API (要JQ)
curl -s "https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://example.com&relation=delegate_permission/common.handle_all_urls" | jq
付録B:用語集
- AAB: Android App Bundle。APKに代わる配布形式。
- PWA: Progressive Web App。Web技術でネイティブに近い体験を提供。
- Keystore: 鍵と証明書を格納するファイル。
- Fingerprint: 証明書のハッシュ値。ここではSHA-256を指す。
- Delegate Permission: Androidが外部アプリへURLハンドリング権を委譲する権限。