Firebase Dynamic Links で既存のユーザーだけでなく、潜在的ユーザーにも体験を提供したい!

iOSDC Japan 2020

Sansan株式会社
Sansan事業部 プロダクト開発部
中川 泰夫

自己紹介

  • 🍎 iOS Engineer@Sansan
  • ⌨️ bat43 / yosino58
  • 🔍 After iOSDC Japan 2020

h:320

アジェンダ

  1. Firebase Dynamic Links で実現できること
  2. 類似技術との比較
  3. Firebase Dynamic Links の導入方法
  4. 事例紹介
  5. まとめ

Firebase Dynamic Links で

実現できること

Firebase Dynamic Links

で実現できること

Firebase Dynamic Links は、
アプリのインストールの有無に
かかわらず、複数のプラット
フォームで機能するリンクです。

類似技術との比較

Custom URL Scheme Universal Links
Availability iOS 2.0+ iOS 9.0+
Vulnerability Hijacking Safety
Limitation - 同一ドメイン上での URL 遷移
の場合、アプリを開けない
Firebase Dynamic Links
Availability iOS 8.0+
Vulnerability Open-Redirect (ホワイトリスト機能で防御可能)
Limitation -

※ どの技術でも利用可能なアクションはユーザーのデータを
危険にさらすことのないものに制限しましょう 🛡

類似技術 (Universal Links / Custom URL Scheme) と比べた際のメリット

  1. 一つのリンクで複数プラットフォームの動作を定義できる
  2. アプリがインストールされていないときの動作を定義できる
  3. ディープリンクに関する統計情報を確認できる

類似技術 (Universal Links / Custom URL Scheme) と比べた際のメリット

  1. 一つのリンクで複数プラットフォームの動作を定義できる
  2. アプリがインストールされていないときの動作を定義できる
  3. ディープリンクに関する統計情報を確認できる

一つのリンクで

複数プラットフォームの動作を定義できる

類似技術 (Universal Links / Custom URL Scheme) と比べた際のメリット

  1. 一つのリンクで複数プラットフォームの動作を定義できる
  2. アプリがインストールされていないときの動作を定義できる
  3. ディープリンクに関する統計情報を確認できる

アプリがインストール

されていないときの

動作を定義できる

  • アプリの App Store ページに
    飛ばす
  • 代替の Web ページへ飛ばす

類似技術 (Universal Links / Custom URL Scheme) と比べた際のメリット

  1. 一つのリンクで複数プラットフォームの動作を定義できる
  2. アプリがインストールされていないときの動作を定義できる
  3. ディープリンクに関する統計情報を確認できる

ディープリンクに関する統計情報を確認できる

  • イベント数
  • トリガーしたユーザー数
  • ユーザーあたりのイベント数
  • etc

Firebase Dynamic Links の

導入方法

Firebase Dynamic Links の

導入方法

  1. Firebase コンソールで設定する
  2. アプリに Firebase を追加する
  3. ダイナミックリンクを作成する
  4. アプリでダイナミックリンクを開く

Firebase Dynamic Links の

導入方法

  1. Firebase コンソールで設定する
  2. アプリに Firebase を追加する
  3. ダイナミックリンクを作成する
  4. アプリでダイナミックリンクを開く

Firebase コンソールで設定する

  • Firebase コンソールで [Dynamic Links] セクションを開きます。

Firebase コンソールで設定する

  • 始める をクリック

Firebase コンソールで設定する

  • URL 接頭辞を追加します
    • ※画像では Google 提供の
      ドメインを利用しています
    • ブランディングのために用意したドメインを使用することも可能です

Firebase コンソールで設定する

  • 問題なければ、画像のような
    画面が表示されるので、
    終了 をクリック

Firebase コンソールで設定する

  • 推奨: ディープリンクや
    フォールバックリンクで
    許可する URL パターンを
    指定する
    • メニューを開いて、URL パターンをホワイトリストに登録 をクリック

Firebase コンソールで設定する

  • 不正なユーザーが管理しているドメインからフィッシングサイトへリダイレクトするようなダイナミックリンクを作成できないようにしましょう 💪

Firebase コンソールで設定する

  • 最初のパターンは公開している Android アプリのパッケージ名が iosdcjapan2020sample だった場合のパターン

Firebase コンソールで設定する

  • 二番目のパターンは公開している iOS アプリの ID が id123456 だった場合の
    パターン

Firebase コンソールで設定する

  • 最後のパターンはディープリンクやフォールバックリンクで
    利用する URL が
    https://iosdcjapan2020sample.com/ だった場合の
    パターン

Firebase コンソールで設定する

  • アプリの App Store ID と
    チーム ID がアプリの設定で指定されていることを確認します
    • Firebase の [設定] ページへ移動します

Firebase コンソールで設定する

  • App Store ID とチーム ID を
    設定する

Firebase コンソールで設定する

  • App Store ID は
    App Store Connect の
    App情報の Apple ID

Firebase コンソールで設定する

  • チーム ID は Apple Developer
    の Certificates, Identifiers & Profiles の Identifires
    のアプリのページに表示される
    App ID Prefix

Firebase Dynamic Links の

導入方法

  1. Firebase コンソールで設定する
  2. アプリに Firebase を追加する
  3. ダイナミックリンクを作成する
  4. アプリでダイナミックリンクを開く

アプリに Firebase を追加する

  • Podfile で次の Pod をインクルードします
    • ※事前に CocoaPods の導入を済ませておいてください
pod 'Firebase/Analytics'
pod 'Firebase/DynamicLinks'
  • pod install を実行し、 .xcworkspace ファイルを
    開きます

アプリに Firebase を追加する

  • Firebase モジュールを UIApplicationDelegate
    インポート
import Firebase

アプリに Firebase を追加する

  • FirebaseApp 共有インスタンスを構成
    • 通常はアプリの application:didFinishLaunchingWithOptions:
      メソッド
// Use Firebase library to configure APIs
FirebaseApp.configure()

Firebase Dynamic Links の

導入方法

  1. Firebase コンソールで設定する
  2. アプリに Firebase を追加する
  3. ダイナミックリンクを作成する
  4. アプリでダイナミックリンクを開く

ダイナミックリンクを

作成する

  • Firebase コンソールで [Dynamic Links] セクションを開きます。

ダイナミックリンクを

作成する

  • 新しいダイナミックリンク をクリック

ダイナミックリンクを

作成する

  • 短縮 URL のリンク設定をする
    • ※画像では自動生成された
      文字列を使用します
    • 分かりやすい URL に変える
      ことも出来ます

ダイナミックリンクを

作成する

  • ダイナミックリンクの設定を
    する
    • ※ディープリンク URL へ
      PC でアクセスした場合、
      ディープリンク URL へ移動
      します

ダイナミックリンクを

作成する

  • iOS 用のリンク動作の定義を
    する
    • このとき、もし、 iOS アプリ
      を用意できてなかった場合は
      ブラウザでディープリンクの URL を開くにしておくと、
      Web へ誘導できます

ダイナミックリンクを

作成する

  • iOS 用のリンク動作の定義を
    する
    • ディープリンクを iOS アプリで開くを選択した場合、開く
      アプリを選択します

ダイナミックリンクを

作成する

  • iOS 用のリンク動作の定義を
    する
    • アプリがインストールされて
      いない場合のユーザーの移動
      先を選択します

ダイナミックリンクを

作成する

  • iOS 用のリンク動作の定義を
    する
    • iPad アプリがある場合は
      iPad アプリを開いたり
    • デフォルトの
      カスタム URL スキームを
      オーバーライドしたり

ダイナミックリンクを

作成する

  • Android 用のリンク動作の定義
    をする
    • Android アプリがある場合、
      iOS 用のリンクと同じように
      設定を行うことが出来ます

ダイナミックリンクを

作成する

  • その他オプションの設定を
    行い、 作成 ボタンを
    クリックする
    • ソーシャルメタタグを追加
      したり、キャンペーン
      トラッキング用の情報を付与したり…

ダイナミックリンクを

作成する

完成 🎉

Firebase Dynamic Links の

導入方法

  1. Firebase コンソールで設定する
  2. アプリに Firebase を追加する
  3. ダイナミックリンクを作成する
  4. アプリでダイナミックリンクを開く

アプリでダイナミック

リンクを開く

  • アプリのターゲットの [Info] タブでダイナミックリンクに使用する新しい URL タイプを作成する

アプリでダイナミック

リンクを開く

  • [Identifier] フィールドに一意
    の値を設定し、[URL scheme]
    フィールドにはバンドル ID を
    設定
    • バンドル ID は、ダイナミック
      リンクにより使用される
      デフォルトの URL スキームに
      なる

アプリでダイナミック

リンクを開く

  • アプリの Xcode プロジェクト
    の [Signing & Capabilities]
    タブで[Associated Domains]を追加し、
    [Domains] リストに
    ダイナミックリンクの
    ドメインを追加
applinks:your_dynamic_links_domain

アプリでダイナミックリンクを開く

  • application:continueUserActivity:restorationHandler: メソッドを使用して、アプリがインストールされている場合にユニバーサルリンクとして受信されるリンクを処理します (iOS 9 以降)
func application(_ application: UIApplication, continue userActivity: NSUserActivity,
  restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
  let handled = DynamicLinks.dynamicLinks()
  .handleUniversalLink(userActivity.webpageURL!) { dynamiclink, error in
    // 特定画面への遷移処理 etc...
  }

  return handled
}

アプリでダイナミックリンクを開く

  • 最後に、 application:openURL:sourceApplication:annotation: メソッド(iOS 8 以前)と application:openURL:options: メソッド(iOS 9 以降)で、アプリのカスタム URL スキームを通して受信したリンクを処理します。

アプリでダイナミックリンクを開く

@available(iOS 9.0, *)
func application(_ app: UIApplication, open url: URL, 
  options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
  return application(
    app, open: url,
    sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
    annotation: ""
  )
}

func application(_ application: UIApplication, open url: URL,
  sourceApplication: String?, annotation: Any) -> Bool {
  if let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) {
    // Handle the deep link. For example, show the deep-linked content or
    // apply a promotional offer to the user's account.
    // ...
    return true
  }
  return false
}

事例紹介

事例紹介

  1. QR コードから「新機能を含んだアプリがインストール済みだったら、アプリを起動して、未インストールだったら、ストアのインストールページへ画面遷移」させる
  2. Web サイトのリンクから「新機能を含んだアプリがインストール済みだったら、アプリを起動して、未インストールだったら、特定の Web サイトを開く」

事例紹介

  1. QR コードから「新機能を含んだアプリがインストール済みだったら、アプリを起動して、未インストールだったら、ストアのインストールページへ画面遷移」させる
  2. Web サイトのリンクから「新機能を含んだアプリがインストール済みだったら、アプリを起動して、未インストールだったら、特定の Web サイトを開く」

フローチャート

ダイナミックリンクの

設定

  • アプリ自体がインストールされていないケースは設定するだけで 🆗

アプリでのハンドリング

  • 新機能が含んでいるかどうかそのダイナミックリンクをハンドリングできるかどうか に言い換えられます
  • application:continueUserActivity:restorationHandler: メソッドに処理を追加します

アプリでの

ハンドリング

  • 実コードを使って
    解説します
  • 前提: Sansan では
    VIPER を採用しています

アプリでのハンドリング

guard let webPageUrl = userActivity.webpageURL else { return true }

DynamicLinks.dynamicLinks().handleUniversalLink(webPageUrl, completion: {
  [weak self] dynamicLink, error in
    guard error == nil else { return }
    self?.dynamicLinkPresenter?.dynamicLinkDidReceive(dynamicLink)
})
  • DynamicLink を生成したあとは Presenter へ処理を
    移してます

アプリでのハンドリング

func dynamicLinkDidReceive(_ dynamicLink: DynamicLink?) {
  // (中略)

  if interactor.isSatisfiedAppVersionFrom(
    dynamicLinkMinimumAppVersion: dynamicLink.minimumAppVersion) {
    // (中略: 次のスライドで説明します)
  } else {
    router.navigate(to: .appStore)
  }
}
  • アプリバージョンがダイナミックリンクが要求する
    最低バージョンを満たせてない場合、ストアへ遷移させる

アプリでのハンドリング

if interactor.isSatisfiedAppVersionFrom(
  dynamicLinkMinimumAppVersion: dynamicLink.minimumAppVersion) {
  guard let destination = interactor.classify(from: dynamicLink.url) else {
    let error = DynamicLinkClassifyError(dynamicLink)
    CrashlyticsErrorRecorder().record(error: error)
    return
  }

  router.navigate(to: destination)
}
  • アプリバージョンがダイナミックリンクが要求する
    最低バージョンを満たしている場合、 URL を判別して、
    適切な遷移先へ遷移させる
  • もし、判別に失敗したら、気付けるように Crashlytics へ Non Fatal Issue で送出する

アプリでの体験

  • アプリがインストール済みの
    場合

アプリでの体験

  • アプリが未インストール、
    または、必要なバージョンを
    満たしていない場合

事例紹介

  1. QR コードから「新機能を含んだアプリがインストール済みだったら、アプリを起動して、未インストールだったら、ストアのインストールページへ画面遷移」させる
  2. Web サイトのリンクから「新機能を含んだアプリがインストール済みだったら、アプリを起動して、未インストールだったら、特定の Web サイトを開く」

フローチャート

ダイナミックリンクの設定

  • 動的パラメータを含んでいるため、 Web 側で動的に
    ダイナミックリンクを生成してもらっています
  • Firebase コンソールで設定したドメインに
    以下のようなフォーマットで渡すと
    ダイナミックリンクとして機能します

https://your_subdomain.page.link/?link=your_deep_link&ibi=bundle_id[&imv=minimum_version][&ifl=fallback_link][&efr=1]

利用したパラメータ

名前 説明
ibi リンクを開くために使う iOS アプリのバンドル ID
ifl アプリがインストールされていない場合に開くリンク
imv リンクを開くことが出来るアプリの最小バージョン
efr 「1」の場合、プレビューページをスキップ

アプリでのハンドリング

事例1で説明したものと同等で 🆗 👍

アプリでの体験

  • アプリがインストール済みの
    場合

アプリでの体験

  • アプリが未インストール、
    または、必要なバージョンを
    満たしていない場合

まとめ

まとめ

  • 最小限の変更で多くのことが実現できた
    • 複数プラットフォームでの同一の体験の提供
    • アプリがインストールされていないときの体験の提供
    • ディープリンクに関する分析

# はじめに スライドの QR -> Twitter のプロフィールページに飛べる 本トークのスライドをつぶやいている 手元の環境で見たい方はチェック # iOS Engineer@Sansan # キーボード ものを作ることが好きで最近は自作キーボード沼にはまっている 右下の画像はリモートワーク用とプライベート用のキーボード # After iOSDC Japan 2020 9/29 19:00~ Sansan(株)、note(株)、(株)ZOZOテクノロジーズの3社による合同イベント Firebase In-App Messaging オンラインでの開催 -> 気軽に参加

# 本トークのアジェンダ

# スライドの動画 QR コードを読み取り、アプリへ遷移する 左側はアプリがすでにインストール済みの場合 右側はアプリが未インストールの場合

# 表の説明 上から Availability - どの iOS バージョンから利用可能か Vulnerability - 脆弱性 Limitation - 制限 # Custom URL Scheme ## iOS 2.0+ 古くからアプリ内のコンテンツへのリンクを用意するために利用されてきた ## Hijacking 問題として複数のアプリで同じ Custom URL Scheme を定義できたため、ハイジャックが可能であること Apple は iOS 11 から Custom URL Scheme で起動するアプリを先にインストールしたアプリに制限することで対処しましたが、利用の仕方によっては攻撃者から悪用されるため注意が必要 # Universal Links ## iOS 9.0+ Custom URL Scheme に変わる技術として登場した 起動確認ダイアログを表示せずにシームレスに起動したり、アプリ未インストール時にリンク先の URL をブラウザで表示できるようになったりとユーザー体験の面で大きく改善した ## Safety HTTPS サーバーに設定ファイルを置き、アプリにも HTTPS サーバーのドメインを紐付けるため、ハイジャックは難しくなり、安全に利用できる。 ## Limitation ただし、制限として「同一ドメイン上での URL 遷移の場合、アプリを開けない」 Apple はユーザーの意図を尊重するためと説明していますが、プロダクト提供者からすると、 Web の体験よりネイティブアプリの体験の方が良い場合にとても困る。

# Firebase Dynamic Links ## iOS 8.0+ 他の2つの類似技術と比べた際のメリットは次のスライドで説明します。 ## Open-Redirect 不正なユーザーがあなたが管理しているドメインから管理外のサイトへリダイレクトするような Dynamic Link を作成することで Open-Redirect 脆弱性を突くことができます。 ドキュメントではホワイトリストを設定することで防御することを推奨しています。

PC で Dynamic Link へアクセスがあった場合は Dynamic Link に設定されたディープリンクの URL を開くことが出来ます

# Custom URL Scheme ページが開けませんダイアログが表示される # Universal Links 設定した URL しか開けない # Frebase Dynamic Links アプリの App Store ページに 飛ばす 別の Web ページに飛ばすことも可能

# 何が嬉しいか リンクからどの割合のユーザがアプリインストールに遷移して、体験が中断されたかが分かったり 再起動数を見ることでそのリンクが日常的に利用されているか分かる ↓ どの部分の体験を改善していったら良いか判断軸に利用できます

私が1から設定を行ってみた手順になるため、実際に導入をする際にスライドを見ながら、導入してもらえると嬉しいです。 今回はトークの都合上、早回しでお送りします。

補足: Firebase コンソールで設定するで実施した URL 接頭辞がこちらで追加するドメインになります。

補足: Firebase Dynamic Links は類似技術である Universal Links や Custom URL Sceheme を利用している技術のため、それぞれの delegate にてハンドリングをします。 記載のメソッドを利用して、アプリがインストールされている場合にユニバーサルリンクとして受信されるダイナミックリンクをハンドリングします。

記載のメソッドを利用して、アプリの Custom URL Scheme を通して受信したダイナミックリンクをハンドリングします。

挙げたのは iOS に関わるパラメーターだけで Android についてのパラメーターももちろんありますし、 Firebase コンソール上で設定できるものはすべて利用可能です。

# スライドの動画 Sansan のオンライン名刺の受け取りの体験の動画です。 Sansanに登録をタップすると、アプリがインストール済みの場合、アプリで受け取りが完了します。

# スライドの動画 アプリが未インストール、または、必要なバージョンを満たしていない場合は Web で受け取りが完了しています。

# まとめ Firebase Dynamic Links を利用することで、最小限の変更で多くのことを実現できました。 これらを上手く活用することでアプリの既存ユーザーだけでなく、潜在的なユーザーへもアプローチが容易になると思います。