lasciva blog

開発して得た知見やwebビジネスのストック

iOSアプリのユニバーサルリンクの仕組み

落とし穴だらけだが、案外いい感じにまとまってる記事があまりなかったので、まとめた。

仕組み

先に全体の処理の流れを示しておく。

  1. iOSアプリがダウンロードorアップデートされる
    • このときに、iOSのプロジェクトで指定したドメインApple App Site Association fileを参照して端末側で保持する
  2. iOS端末で、safariなどの他のアプリでユニバーサルリンクをタップする
  3. 1でダウンロードしたデータを参照して、pathがマッチした場合にアプリを開く
    • このとき、サーバにリクエストを送らない

注意点

Apple App Site Association file

このあたりが公式になる。

Enabling Universal Links | Apple Developer Documentation

Setting Up an App’s Associated Domains | Apple Developer Documentation

記述方法

1,2年前に調査した際には色々記述方法が新旧あって、なかなか動かなかった。
最終的には、メジャーな動いてるアプリのサイトを参考に実装進めた。
開発環境のschemeをどう切り分けてるのかとか推測できて面白い。

https://www.mercari.com/apple-app-site-association

{
  applinks: {
    apps: [],
    details: [
      {
        appID: "2CCV6DZ29E.com.kouzoh.ios.mercari",
        paths: [
          "/jp/",
          "/jp/m?????????/",
          "/jp/m???????????/",
          "/jp/transaction/order_status/*",
          "/jp/sell/",
          "/jp/u/*",
          "/jp/area/*",
          "/jp/category/*",
          "/jp/brand/*",
          "/jp/search/*",
          "/jp/launch/*",
          "/jp/cartune/*"
        ]
      },
      {
        appID: "K69VE4UMZN.com.kouzoh.ios.production.mercari",
        paths: [
          "/jp/",
          "/jp/m?????????/",
          "/jp/m???????????/",
          "/jp/transaction/order_status/*",
          "/jp/sell/",
          "/jp/u/*",
          "/jp/area/*",
          "/jp/category/*",
          "/jp/brand/*",
          "/jp/search/*",
          "/jp/launch/*",
          "/jp/cartune/*"
        ]
      },
      {
        appID: "2CCV6DZ29E.com.mercariapp.ios.mercari",
        paths: [
          "/r/"
        ]
      },
      {
        appID: "2CCV6DZ29E.com.mercariapp.ios.dev.mercari",
        paths: [
          "/r/"
        ]
      },
      {
        appID: "K69VE4UMZN.com.mercariapp.ios.development.mercari",
        paths: [
          "/r/"
        ]
      },
      {
        appID: "2CCV6DZ29E.uk.mercariapp.ios.mercari",
        paths: [
          "/uk/u/*",
          "/uk/m?????????/",
          "/uk/m???????????/",
          "/uk/category/*",
          "/uk/brand/*",
          "/uk/search/*",
          "/uk/mypage/*",
          "/uk/instantsales/",
          "/uk/explore/*",
          "/uk/inbox/*",
          "/uk/sell/"
        ]
      }
    ]
  }
}

ファイルの設置場所

以下の2種類のうち、どちらかあればよい。

参照されるタイミング

ダウンロードされたときか、アップデートされたときに参照される。

以下注意点

  1. 広告ガンガン打つと、インストールする度にリクエストが来るので少しだけ要注意。
    • 2回リクエストが来る(.well-known配下とルート配下)
  2. httpsでないといけない
  3. インストールのときにエラーを返すと、そのユーザはアップデート等するまでユニバーサルリンクが使えない

ユニバーサルリンクの発動する条件

  1. ユーザがタップしたすること
    • タップされた際は、短縮URLなどでリダイレクトしても問題ない
    • jsでシステム的にredirectしてもダメ
    • 忘れたので正確でないが、タップ後に、サーバ側でリダイレクトされた場合は大丈夫だったような気もしなくもない
  2. URLのドメインが変わること
    • example.comのサイトを閲覧中の場合、サブドメイン(app.example.comなど)を変えるとか工夫しないといけない
    • 対応しないといけないのは、他のアプリ内ブラウザで見ているときに、「アプリで開く」のようなボタンを設置する際など
  3. アプリ側で特殊なハンドリングがなされてないこと。
  4. アプリの実装によっては、対応不可の場合もある

ユニバーサルリンクのON/OFFの切り替え

バージョンによって挙動が異なる。。
iOS11以降は大分改善されたが、ややこしい。

iOS10以前

iOS10以前はなかなかのクソ仕様で、開発者以外わからないと思う。。
ユーザに切り替えてもらうのも、なかなか伝わらないと思う。

OFFにする方法 OFFにした後にONにする方法 選択する方法
操作 ユニバーサルリンクで遷移後のアプリ内の右上のドメインを押す 下に引っ張るとブラウザ上部に出てくる 開くを押す 長押しして選択
f:id:hacking15dog:20190305174946p:plain f:id:hacking15dog:20190305174903p:plain f:id:hacking15dog:20190305174843p:plain

iOS11以降

意図的に設定しないとOFFにならない仕様になったので、まぁまぁマシになった。

OFFにした後にONにする方法 選択する方法
操作 下に引っ張るとブラウザ上部に出てくる 開くを押す 長押しして選択
f:id:hacking15dog:20190305180142p:plain f:id:hacking15dog:20190305180202p:plain

safariのプライベートブラウズ

プライベートブラウズのときも挙動が若干異なるので注意。
案外女性で使っている人が多い。

iOS10以前

非プライベートブラウズのときと同じ挙動をする。

iOS11以降

基本的な動きは上述した、非プライベートブラウズのときと同じ挙動をする。
但し、ユニバーサルリンクで開くときに、ダイアログが出る。

f:id:hacking15dog:20190305180921p:plain

カスタムURLスキームとの比較

基本的には、アプリを起動させる際には、ユニバーサルリンクで対応した方が良いと思う。

  1. ブラウザでダイアログが表示される。
    • ユーザ体験的に微妙
  2. セキュリティ的に微妙
    • ユニバーサルリンクは、アプリ側で指定したhttpsドメインを参照しにいく仕組みのため、開発者が一致していることが、ほぼ保証される。
    • それに対して、カスタムURLスキームは第三者の悪意あるアプリ側でも、カスタムURLスキームを登録できてしまうので、開発者の設定したカスタムURLスキームから、悪意のあるアプリが開けてしまう。