iOS 30days Album

Universal Links のサーバ側の対応をやってみた

iOS 30days Album

写真共有サービス 30days Album の開発チームでサーバサイドエンジニアとして活動している @june29 です。

これは Pepabo Advent Calendar 2015 の6日目のエントリになります。今回は iOS 9 から導入された「Universal Links」の概要と、それに対応するための「サーバ側」の作業について書きます。「クライアント(iOS アプリ)側」のお話については、後日、別の者から紹介があります。

(※なお、このエントリは2015年12月4日までの情報を元に作成しています。今後、Universal Links の仕組み自体が変わっていくかもしれませんので、日が経ってから参照される方はその点をご留意ください)

ご存知の方も多いかとは思いますが、ここで Apple のウェブサイトを見て概要だけ確認しておきます。

Universal links let you replace custom URL schemes with standard HTTP or HTTPS links. Universal links work for all users: If users have your app installed, the link takes them directly into your app; if they don’t have your app installed, the link opens your website in Safari.

What's New in iOS - iOS 9.0

「Universal Links は、これまでのカスタム URL スキームを HTTP/HTTPS のリンクで置き換えるものである」「リンクを開こうとしたとき、アプリをインストールしている人はアプリが起動し、そうでない人はこれまで通りに Safari でリンクを開く」と、そういったものです。

私たちが開発している 30days Album では、URL を受け渡しして写真アルバムを共有できます。たとえば、アルバムページの URL として http://30d.jp/june29/29 をメールで受け取ってタップしたときに、iPhone に 30days Album のアプリがインストールされていればすぐにアプリが起動してアルバムのビューを操作できるわけです。これは便利!

いくつか対応作業をこなす必要があり、大きくは「サーバ側の対応」と「クライアント側の対応」にわけることができます。このエントリでは前者についてのみ語ります。

まずは Apple が提供するドキュメントを確認してみましょう。

Adding support for universal links is easy. There are three steps you need to take:

  • Create an apple-app-site-association file that contains JSON data about the URLs that your app can handle.
  • Upload the apple-app-site-association file to your HTTPS web server.
  • Prepare your app to handle universal links.

Always use actual devices to test universal links. Simulator doesn’t support universal links.

App Search Programming Guide: Support Universal Links

ここに示される3つの作業のうち、上2つがサーバ側の作業になります。

設定ファイル apple-app-site-association の作成と配置

iOS アプリとウェブサイトの関連を定義する「apple-app-site-association」ファイルを用意します。拡張子は付けず、このままの名前のファイルです。ドキュメントから例を引用してきましたので、項目を順に見ていきましょう。

{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "9JA89QQLNQ.com.apple.wwdc",
                "paths": [ "/wwdc/news/", "/videos/wwdc/2015/*" ]
            },
            {
                "appID": "TeamID.BundleID2",
                "paths": [ "*" ]
            }
        ]
    }
}

まず apps は必須の項目で、値には「空の配列」を指定しましょう、とのことです。どういった意味を持つのかはよくわかりませんが、ひとまず次に進みます。

続いては details です。値には「連想配列の配列」を指定します。ひとつの連想配列は、ひとつのアプリに対応します。この例のひとつめの連想配列は「このウェブサイトの /wwdc/news//videos/wwdc/2015/ へのアクセスは、WWDC のアプリで受け持つ」といった意味に解釈できます。details の中にある appID には、アプリの「team ID」と「bundle ID」から成る文字列を指定します。もうひとつの項目 paths は、アプリがハンドリングを担当するページ群のパスのパターンを指定する配列を指定します。paths についてのドキュメントには、下記のように記載されています。

There are various ways to specify the website paths that you want your app to support. For example, you can:

  • Support your entire website by specifying *
  • Support a particular link by including a specific URL, such as /wwdc/news/
  • Support a section of your website by appending * to a specific URL, such as /videos/wwdc/2015/*
  • In addition to using * to match any substring, you can also use ? to match any single character. You can combine both wildcards in a single path, such as /foo/\*/bar/201?/mypage.

App Search Programming Guide: Support Universal Links

固定パスはそのまま書いて、特殊記法としては「*」「?」の2種類が用意されているとのことです。

さて、設定ファイルを記述できたら、あとはこのファイルをウェブサイトのルートディレクトリに配置します。私たちのサービスの場合であれば https://30d.jp/apple-app-site-association になります。

apple-app-site-association に関する注意点

apple-app-site-association ファイルは、リダイレクトなしで提供することが求められています。

また、もしウェブサーバが HTTPS ではなく HTTP で apple-app-site-association を配信する場合、あるいは、iOS 8 で導入された Handoff や Shared Web Credentials の設定も使用している場合は、このファイルを TLS 証明書で署名しておく必要があります。

すべての要件は公式ドキュメントに掲載されていますので、うまくいかない場合は、関連ドキュメントに一通り目を通してみるとよいと思います。

実際には、四苦八苦しました

ここまで、公式ドキュメントばかりを参照しながらお行儀よく書いてきましたが、これは試行錯誤のあとの今だから書ける後出しジャンケンです。実際のところは、いろいろな記事を読んだり、いろいろな実例を眺めてみたり、いろいろと試してみたりもしました。これから Universal Links のサーバ側の対応作業にあたる人が私と同じ苦労をせずに済むように、失敗談やボヤキも含めて公開しておきます。

以下には、公式ドキュメントにて明示されている「仕様」ではなく、私が確認してみた限りにおいてはそのように見えたという「挙動」のお話がふんだんに盛り込まれています。参考にはなると思って載せますが、実際に作業される際には、必ず各自でご確認いただくことを強くおすすめいたします 😁

  • Apple 提供の設定チェックツールが便利 App Search API Validation Tool - Apple Developer
    • これでいろいろなサービスの設定状況を見たりしました
    • ここにドメインを入れると、Applebot が設定ファイルを取りにきます
    • そのときの User-Agent は Go 1.1 package http でした
  • Universal Links 対応しているサービスまとめ 34 iOS 9 Apps That Support Universal Links (updated 11-19) — Jack's Place
    • 2015年12月4日時点で、34のサービスが列挙されていて便利です 🙏🏻
    • apple-app-site-association の実例を拝見できるので便利です 🙏🏻
  • Twitter の apple-app-site-association を見て、夢を見ました
    • Twitter はユーザページが / 直下なので paths* にするしかないようです
    • これだと全ページが Universal Links に反応してしまうから、どのように対応しているのだろうと興味を持ちました
    • twitter.com の apple-app-site-association を拝見してみると NOT /faq などの記述を見つけました
    • NOT で除外パスを指定できるのか!」と思ってテンションが上がりましたが、そのような記法はないようでした… 😇
  • アプリが apple-app-site-association を取得しにくるのは、アプリのインストール完了時に見えました
    • そのときの User-Agent は swcd (unknown version) (Shared Web Credentials の略でしょうか)
    • インストール完了時に参照して、以降はずっとキャッシュするとしたら落とし穴になりそうですね… 👾
    • apple-app-site-association は高頻度で更新するものではない、と捉えておくのが吉と見ています

今のところ対応事例はそれほど多くないようで、私が把握できていないこともたくさんありそうなので、このエントリを読んでくださった方、フィードバックをいただけたらとてもうれしいです。

まとめ

Pepabo Advent Calendar 2015 の6日目のエントリとして、写真共有サービス 30days Album で Universal Links 対応作業をしてみたお話を書きました。明日7日は、今度は「クライアント(iOS アプリ)側」の対応作業のお話を私と同じチームの @kuroyam が書いてくれます。

App Search API Validation Tool - Apple Developer を見るとよくわかる通り、Universal Links は「iOS 9 Search APIs」という大きなくくりの中の一要素です。これに対応しておくことで、30days Album の iOS アプリを iOS そのものと統合してよりよい体験を提供できるようになると目論んでいるので、引き続き、これらの動向をチェックし、いい形でサービスに取り入れていきたいと思います。

実は、まだ Universal Links 対応版アプリはリリースされていなくて「ぜひご利用ください!」と言えないのが心苦しいのですが、近いうちに対応しますのでどうぞよろしくお願いします!