iOS 13以降の Universal Links について紹介します。
Universal Linksとは
iOS 9からサポートされて、Apple が正式に提供したディープリンク技術です。
簡単にいうと、通常の HTTP リンクで設定すると、その URL を踏んだ時に、端末のデフォルトブラウザで Web サイトを開く代わりに、アプリを起動してページへ遷移することができます。
URL スキームと似ている機能ですが、主に下記の違いがあると思います。
- Custom URL スキームが不要です。
hoge://
みたいなスキームではなく、 通常の HTTP リンクのスキームhttps://
でアプリが起動できるので、 Web サイトとアプリ両方同じURLで遷移できます。 - Web サーバーにアプリの起動条件を記載する apple-app-site-association を配置する必要がある。URL のパスやパラメータなど設定することで、アプリに遷移させたいリンクのみ指定可能です。
- 直接にブラウザにURLを入力した場合、アプリが起動しません。同一ドメイン内で Web 回遊中の時にも、アプリが起動しません。
アプリ側の設定
Associated Domainsの設定
ドメインを追加する
フォーマットは applinks:<fully qualified domain>
になります。サブドメインで対応する場合、サブドメインを含めて設定する必要があります。
Alternate Mode
iOS 14から、OSは直接 Web サーバーからではなく、 Apple の CDN を経由して apple-app-site-association をダウンロードします。 CDNへの反映は最大24時間かかるらしいです。また、IP 制限がある開発環境で、CDN からのアクセスできない場合もあるので、開発の際、Alternate Modeを developer
に設定すると、CDNを経由せず 直接 Web サーバーから apple-app-site-association をダウンロードできます。
先ほど追加したドメインにパラメータ mode=developer
を追加するだけで設定完了です。 applinks:example.com?mode=developer
のようにになります。
この場合、テスト端末の Associated Domains Development
を有効にする必要があります。
なお、 MDM アプリの場合、 mode= managed
で設定すると、 Apple の CDN も回避できるようです。
詳細は Associated Domains Entitlement ご確認ください。
ipa で確認する
アプリを配布する際、 ipa の設定は大丈夫だろう?と思ったら ipa を展開して確認しましょう。
unzip -d work hoge.ipa
codesign -d --entitlements - work/Payload/hoge.app
アプリ側の設定がこれで完了です。
apple-app-site-association
iOS 13から apple-app-site-association のフォーマットが新しくなりました。これから紹介する apple-app-site-association は、 iOS 12 以前では発動しないので、ご注意ください。
apple-app-site-association の書き方
Apple の公式ドキュメント applinks のサンプル json を見てみましょう。
{
"applinks":
{
"details":
[
{
"appIDs":
[
"ABCDE12345.com.example.app",
"ABCDE12345.com.example.app2"
],
"components":
[
{
"#": "no_universal_links",
"comment": "フラグメント#no_universal_linksが付いている場合Universal Links発動しない",
"exclude": true
},
{
"/": "/buy/*",
"comment": "パスが/buy/からスタートしたURLはUniversal Links発動する"
},
{
"/": "/help/website/*",
"comment": "パスが/help/website/からスタートしたURLはUniversal Links発動しない",
"exclude": true
},
{
"/": "/help/*",
"?":
{
"articleNumber": "????"
},
"comment": "パスが/help/からスタートしたURL、かつパラメータarticleNumberが4桁の文字列の場合Universal Links発動する"
}
]
}
]
}
}
全体の説明
項目名 | 説明 |
---|---|
applinks | 固定オブジェクト |
applinks.details | Universal Linksのアプリ情報と発動条件の配列 |
applinks.details.appIDs | 対象アプリの情報の配列 フォーマットは <team id>.<bundle id> になる |
applinks.details.components | Universal Linksの発動条件の配列 優先順位は上から適用される |
components の説明
項目名 | 説明 |
---|---|
"#": "" | フラグメントの条件 |
"/": "" | URLパスの条件 |
"?": { "": "" } | パラメータの条件 |
"exclude": true | trueで設定すると該当条件は発動しない |
"comment": "" | コメント 必須ではない |
components の各種条件の組み合わせで細かく発動条件が設定できます。
SubstitutionVariables
iOS 13.5 から SubstitutionVariables という、代替変数の機能が追加されました。
$(alpha)
、 $(digit)
など固定の変数があり、こちらのように自前の定義を追加することも可能です。
{
"applinks": {
"substitutionVariables": {
"food": [ "burrito", "pizza", "sushi", "samosa" ]
},
"details": [{
"appIDs": [ ... ],
"components": [
{ "/" : "/$(lang)_$(region)/$(food)/" }
]
}]
}
}
サーバー側の設定
apple-app-site-associationを作成したらそれを Web サーバーに配置します。ここではいくつのポイントがあります。
- apple-app-site-association ファイルは拡張子なしで、 MIME タイプが application/json になっていること
- .well-known ディレクタリー直下に apple-app-site-association ファイルが配置されていること
-
リダイレクトなしで、
https://<fully qualified domain>/.well-known/apple-app-site-association
へアクセスできること
疎通確認
apple-app-site-association の設置が終わったら、正常にアクセスできるか確認しましょう。App Search API Validation Tool から確認も可能ですが、こちらの curl を叩くと CDN への反映状況などより詳細な情報を入手できます。
curl -v https://app-site-association.cdn-apple.com/a/v1/example.com
キャッシュの生存時間があとどのくらいあるかなどの情報も確認できるので、疎通確認の際非常に役立ちます。
疎通確認が成功したら、設定したURLを踏むとアプリが起動できると思います。
ただし、 iOS では、アプリの新規インストール、アップデート、または**システムのタイミング(平均的に1週間1回らしい)**でapple-app-site-associationが更新されるので、端末に最新のapple-app-site-associationが反映されるまでタイムラックがあります。
アプリの実装
最後に、アプリ側で受け取ったURLを処理します。
AppDelegate
の application(_:continue:restorationHandler:)
が最初の入り口になります。
func application(_ application: UIApplication, continue continueUserActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
// appLinksの場合、activityTypeがNSUserActivityTypeBrowsingWebになる
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL else { return false }
if canHandle(url) {
// do something
} else {
// 処理できないURLはブラウザで開く
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
return true
}
以上、 Universal Links の紹介でした。