iOS/Androidのダウンロードリンクを1つにまとめる
はじめに
アプリのダウンロードリンクを作るとき、iOS用・Android用でURLやQRコードを2つ用意するのではなく、1つのURLを使って振り分けが可能です。
この記事では、外部サービスに依存せずに実現する方法をまとめます。
実現したい挙動:
- アプリをダウンロードするユーザーが 1つのURL にアクセスする
- アプリが インストール済み なら、アプリが 直接起動 する
- アプリが 未インストール なら、OSを判別して 適切なストアへ遷移 する
なるべくシンプルな実装例にしていますので、参考にしていただければ幸いです。
全体像
以下2つを用意することで実現します。
-
Universal Links (iOS) / App Links (Android)
ディープリンクと呼ばれる機能です。アプリがインストールされている場合、ブラウザを介さずにアプリが直接起動する処理を担います。 -
Webサーバー上のブリッジページ (HTML + JavaScript)
アプリが入っていない場合、ディープリンクは発動せず、通常のWebページとしてブラウザでアクセスされます。このページに配置したJavaScriptでOSを判定し、各ストアへリダイレクトさせます。
これにより、「アプリがあればOSが処理し、なければWeb(JS)が処理する」 という分岐を作ります。
実装例
実装は大きく分けて「サーバー設定」「アプリ設定」「Webページ作成」の3ステップです。
1: サーバー設定
まず、OSが「このドメインはアプリと紐付いている」と認識できるように、サーバーの所定の位置に関連付けファイルを設置します。これらはHTTPSでのアクセスが必須です!
iOS: apple-app-site-association
ドメインのルート、または .well-known/ 配下に apple-app-site-association というファイルを設置します。
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAM_ID.com.your-bundle.id",
"paths": [ "/app/*" ]
}
]
}
}
-
appID: Apple DeveloperのTeam IDとBundle IDをピリオドで繋いだもの記述します。 -
paths: アプリで開きたいURLパスを指定します。今回は/app配下へのアクセスをトリガーとします。
Android: assetlinks.json
同様に、.well-known/assetlinks.json を設置します。
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.your.package.name",
"sha256_cert_fingerprints": [
"XX:XX:XX:..."
]
}
}
]
-
sha256_cert_fingerprints: アプリ署名証明書のSHA-256フィンガープリントを記述します。確認方法は以下の2通りです。-
Google Play Console (Play アプリ署名を利用している場合)
[リリース] > [設定] > [アプリの署名] ページにある「アプリ署名鍵の証明書」のSHA-256フィンガープリントを使用します。 -
keytool コマンド (ローカルで生成)
キーストアファイル(.jksや.keystore)から確認する場合は、ターミナルで以下を実行します。keytool -list -v -keystore <キーストアへのパス> -alias <エイリアス名>実行結果に表示される
SHA256: XX:XX:XX...の部分を使用します。
-
2: アプリ設定
サーバー側の準備ができたら、アプリ側でも「このドメインのリンクを開く」という設定を行います。
iOS: Xcodeで設定
- Targetの Signing & Capabilities タブを開きます。
-
+ Capabilityから Associated Domains を追加します。 - Domainsリストに
applinks:your-domain.comを追加します。
Android: AndroidManifest.xml
起動対象としたいActivityの <intent-filter> に以下を追加します。
<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="https"
android:host="your-domain.com"
android:pathPrefix="/app" />
</intent-filter>
-
pathPrefixを設定することで、.../app/~ の時だけアプリを開く制御ができます。
3: Webページ作成
最後に、アプリ未インストールユーザーがたどり着くWebページ(/app/index.html)を作成します。
このページが表示されるということは、「OSによるアプリ起動(Universal Links/App Links)が実行されなかった」=「アプリが未インストールである」 と想定して準備します。
ここでは、単にOSを見てストアへ飛ばすだけのシンプルな実装例を記載します。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Redirecting...</title>
</head>
<body>
<p>アプリストアへ移動しています...</p>
<script>
const ANDROID_STORE = "https://play.google.com/store/apps/details?id=com.your.package";
const IOS_STORE = "https://apps.apple.com/jp/app/id123456789";
const ua = navigator.userAgent.toLowerCase();
const isAndroid = ua.indexOf('android') > -1;
if (isAndroid) {
// Androidの場合 -> Google Playへ
window.location.replace(ANDROID_STORE);
} else {
// Android以外(iOS, PC等) -> App Storeへ
// ※よりリッチにするならPC向けの分岐も検討してみてください!
window.location.replace(IOS_STORE);
}
</script>
</body>
</html>
これをサーバーの /app/index.html として配置すれば完了です。
まとめ
以上で、iOS/Android共用のダウンロードリンクを作成できました。
- インストール済みユーザー: OS機能でアプリが起動
- 未インストールユーザー: OSで振り分けてストアへ誘導
この実装例を土台にして、アプリ内ルーティングを拡充するなどにも役立てていただければ幸いです。ここまでお読みいただきありがとうございました!
Discussion