麦芽を支える技術

麦芽(ばくが、英語:malt)とは、麦、特に大麦の種子を発芽させたもので、ビール、ウイスキー、水飴の原料となる。(Wikipediaより)

iOS Universal Linksの設定とFirebase Hostingでの簡単お試し方法

今更といえば今更なんですが、業務でiOSアプリのUniversal Links対応する際に、この辺りを自分なりに整理したので、その内容をメモっておきます。

iOSのDeep Link技術の整理

本題に入る前に、iOSにおけるDeep Link技術について整理しておきます。

ディープリンク(Deep Link, Deep Linking)とは

Mobile deep linking - Wikipedia日本語ページでは、なんかモバイルではなくWeb全般を捉えたページしか無い)

モバイルアプリ文脈では「URLを用いてアプリ内の特定の場所(画面)にリンクすること」をディープリンクと呼びます。

iOSのDeep Linkパターン

1. カスタムスキーマ起動

  • iOSアプリにおけるDeep Linkの方法の1つ
  • http/httpsスキーマの代わりにアプリ独自のスキーマを定義し、そのスキーマを検知してアプリを起動させる
    • ex.) URL: {custom_scheme}://~
  • AppDelegateの application(_:open:options:) でハンドリング
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
        // `url` にリンクされたURLが入ってくるのでハンドリング
        ...
        return true
    }

2. Universal Links

  • iOSアプリにおけるDeep Linkの方法の1つ(ただしiOS9.0以降のみ対応)
  • Webブラウジングにおいて一般的なhttpsスキーマを検知してアプリを起動させる
    • ex.) URL: https:/{your_host_name}/path/to~
  • あくまでトリガーが一般的なWebサイトのURL形式であり、対象アプリが未インストールの場合は通常通りWebブラウザで遷移する。
  • AppDelegateの application(_:continue:restorationHandler:) でハンドリング
    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
        if userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL {
            // `url` にリンクされたURLが入ってくるのでハンドリング
            ...
        }
        return true
    }

(余談)Firebase Dynamic Links

  • Firebaseが提供するサービスの1つ
  • 名前で混同しがちであり、Webからアプリを開かせるときに使う点は似ているが、上記と並ぶDeep Link技術では無い
  • ユーザ環境(OS、アプリインストール有無など)に応じた適切なリンク先を選択し、提供してくれる
  • 提供されたリンク先を元に、アプリ側でどう振る舞うかは各OSのDeep Link実装に準ずる

Universal Links設定

大きく分けると以下の作業が必要となります。

  • apple-app-site-association ファイルをWeb上に配置
  • iOSアプリ側プロジェクト設定でAssociated Domainsの設定
  • アプリ起動時に入ってくるURLのハンドリング処理を実装

1. apple-app-site-association ファイルをWeb上に配置

apple-app-site-association とは、「このサイト(site)はxxxアプリ(apple-app)と紐づいている(association)よ」ということを示すファイルとなります。

具体的には以下のようなJSONファイルが実体となります。

{
  "applinks": {
       "apps": [],
        "details": [
           {
               "appID":"{APP_ID_PREFIX}.{APP_ID}",
               "paths":[ "*" ]
           }
         ]
    }
}
  • appID :Dev Centerに登録済みの内容を設定
  • paths :対象とするURLパス(ホスト部以降)

これをWebサイト側に設置する必要があるのですが、設置に際しては以下のような設置要件があります。

  • httpsでアクセス可能
  • そのドメインのルート or .well-known サブディレクトリに配置
  • Content-Typeが application/json で返却されること

ちょっとお試しで操作確認したい場合にこの環境用意するのはやや手間なので、簡単なセットアップ方法はこのエントリの後半にて。

2. iOSアプリ側プロジェクト設定でAssociated Domainsの設定

これはここのことですね。

f:id:asmz0:20190217205547p:plain:w600

applinks: の後に続けて 1. のファイルを設置したサーバURLの「ドメイン部」を記載します。サブディレクトリのような指定はできないので注意。

あと、Dev Center上で対象のAppIDのAssociated Domainsもちゃんと有効になっている必要があります。

3. アプリ起動時に入ってくるURLのハンドリング処理を実装

これは上の方でもサンプルコード軽く書きましたが、AppDelegateの application(_:continue:restorationHandler:) でURLを捕捉して、任意のハンドリングを行ってください。

スキーマ起動とUniversal Linksを共存させる場合は、URLからのパス切り出し処理は共通化しておくのが良いですね。

Firebase Hostingで簡単にapple-app-site-association ファイル配置

先ほど説明したapple-app-site-association ファイルの設置と軽い動作確認は、Firebase Hosting使うと便利です。

こんな感じ(firebase-toolsは入っている前提)

$ # firebase hostingの初期設定する
$ firebase init
 
$ # こんな構成でファイルを置く
$ tree
.
├── firebase.json
└── public
    ├── 404.html
    ├── apple-app-site-association
    └── index.html
 
$ # firebase.jsonでContent-Typeを application/jsonにしておく
$ cat firebase.json
{
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "headers": [
      {
        "source": "/apple-app-site-association",
        "headers": [{"key": "Content-Type", "value": "application/json"}]
      }
    ]
  }
}
 
$ # デプロイ
$ firebase deploy

まず、Firebase Hostingは自動でhttpsになります。 また、上記デプロイするとhttps://xxxxx.firebaseapp.com の直下に apple-app-site-association が配置され、アクセスするとContent-Typeが application/json のレスポンスが返却されます。

よって先に記載した設置要件を全て満たしたことになります!

おわりに

以上がiOS Universal Linksの基本的な設定方法と、簡単なお試し手順の紹介となります。

遷移時に確認ダイアログが表示されるスキーマ起動と違い、Universal LinksはWebからアプリへの遷移がシームレスなので、Webとアプリをうまく融合させたサービスの作りにしたい場合などに有効ですね。