🤳

iOS/Androidのダウンロードリンクを1つにまとめる

に公開

はじめに

アプリのダウンロードリンクを作るとき、iOS用・Android用でURLやQRコードを2つ用意するのではなく、1つのURLを使って振り分けが可能です。

この記事では、外部サービスに依存せずに実現する方法をまとめます。

実現したい挙動:

  • アプリをダウンロードするユーザーが 1つのURL にアクセスする
  • アプリが インストール済み なら、アプリが 直接起動 する
  • アプリが 未インストール なら、OSを判別して 適切なストアへ遷移 する

なるべくシンプルな実装例にしていますので、参考にしていただければ幸いです。

全体像

以下2つを用意することで実現します。

  1. Universal Links (iOS) / App Links (Android)
    ディープリンクと呼ばれる機能です。アプリがインストールされている場合、ブラウザを介さずにアプリが直接起動する処理を担います。
  2. 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通りです。

    1. Google Play Console (Play アプリ署名を利用している場合)
      [リリース] > [設定] > [アプリの署名] ページにある「アプリ署名鍵の証明書」のSHA-256フィンガープリントを使用します。

    2. keytool コマンド (ローカルで生成)
      キーストアファイル(.jks.keystore)から確認する場合は、ターミナルで以下を実行します。

      keytool -list -v -keystore <キーストアへのパス> -alias <エイリアス名>
      

      実行結果に表示される SHA256: XX:XX:XX... の部分を使用します。

2: アプリ設定

サーバー側の準備ができたら、アプリ側でも「このドメインのリンクを開く」という設定を行います。

iOS: Xcodeで設定

  1. Targetの Signing & Capabilities タブを開きます。
  2. + Capability から Associated Domains を追加します。
  3. 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