【Unity】Firebase Dynamic Linksの置き換え先候補 ~Branch.io紹介~

## Firebase Dynamic Linksとは？
Firebaseが提供する機能で、便利なリンクを発行できます。

Firebase Dynamic Linksを使えば、ユーザーがアプリをインストールしていない場合は、特定のリンクをクリックした際にアプリストアへ誘導し、インストール後はそのリンクに関連したコンテンツや機能に直接アクセスさせることができます。既にインストールしている場合にも、アプリが立ち上がって任意のコンテンツへの誘導可能なため、1つのリンクで状況に応じた誘導が可能です。

また、iOS/Androidそれぞれで仕様の異なるストアへの遷移を可能としており、ゲーム、メタバース、AR、便利系などジャンルを問わず、モバイルアプリにおいて強力なソリューションとして有名です。

## Firebase Dynamic Links廃止
Firebase Dynamic Linksは廃止が決定しており、2024年12月現在、あと8ヶ月の猶予となりました。

> 2025 年 8 月 25 日をもって、Firebase Dynamic Links はご利用いただけなくなります。 Firebase Dynamic Links が提供するすべてのリンク（カスタム ドメインと page.link のサブドメインの両方）は機能しなくなり、新しいリンクを作成できなくなります。

引用元：[Dynamic Links の非推奨に関するよくある質問](https://firebase.google.com/support/dynamic-links-faq?hl=ja&_gl=1)

## 乗り換え先候補
それぞれのサポート環境や詳細な料金などは省きますが、代替として以下のようなサービスがあります。

- [Adjust](https://www.adjust.com/)
- [AppFlyer](https://www.appsflyer.com/ja/)
- [Bitly](https://bitly.com/)
- [Kochava](https://www.kochava.com/)
- [Branch.io](https://www.branch.io/)

本記事ではBranch.ioについて紹介します。

## Branch.io
deep linkをベース機能とした、マーケティングツールを提供しています。
deep linkに関する話かどうかわかりませんが、世界で2000以上の企業、3億をこえるユーザーに提供中らしいです。

> With 2,000 tech partners and over 3 billion worldwide users, we’re excited to continue offering solutions that help brands build and measure more seamless, personalized mobile experiences.

引用元：[branch.io/about](https://www.branch.io/about/)

### 料金
基本無料でdeep linkを利用可能です。ただし、MAUの無料枠(10000)を超えた場合、1000MAUごとに5$の支払いが発生します。無料枠を大きく上回る利用が見込まれる場合、Branch.ioの営業担当に有料プランの相談を行うべきでしょう。

![スクリーンショット 2024-12-12 12.06.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/294ab85e-db84-2ad8-3821-f08348daf061.png)

引用元：[dashboard.branch.io](https://dashboard.branch.io/)

### Unity SDK
以下リポジトリからUnitySDKを取得可能です。iOS/Android向けSDKをネイティブプラグインとして抱えるような構造となっています。

リポジトリ：[unity-branch-deep-linking-attribution](https://github.com/BranchMetrics/unity-branch-deep-linking-attribution)


## ダッシュボード上での設定
Branch.ioは安定したdeep linkの挙動を実現するために、AppLink/UniversalLinkとURIスキームを状況に応じて使い分けしており、それらを駆使して正常に値を受け取るためには事前定義が必要です。

ここでは割愛しますが、UnitySDK単体で動くものではなく、ダッシュボード上の設定を行なって、その情報とUnity側の設定を統一させる必要があります。

参考リンク：[PLUGINS & SDK Wrappers - Unity](https://help.branch.io/developers-hub/docs/unity)


## バージョン情報
| ツール/SDK | バージョン |
|:-:|:-:|
| Unity  |  2022.3.46f1 |
|  Branch SDK |  2.0.0 |

## サンプルコード

DeepLink経由で受け取ったデータを取得するサンプルです。
クエリパラメーター付きリンクを読み取り、クエリ取得後にその値を表示します。


```CS
using System;
using System.Web;
using Newtonsoft.Json.Linq;
using TMPro;
using UnityEngine;

public class ReceiveDemo : MonoBehaviour
{
    [SerializeField] TMP_Text _debugText;

    private void Awake()
    {
        if (Application.isEditor) return;
        Branch.initSession(CallbackWithBranchUniversalObject);
    }

    private void CallbackWithBranchUniversalObject(
        BranchUniversalObject buo,
        BranchLinkProperties linkProps,
        string error)
    {
        if (error != null)
        {
            Debug.LogError("Error on CallbackWithBranchUniversalObject: " + error);
            return;
        }

        var link = GetLink(buo.ToJsonString());
        Debug.Log("Link: " + link);
        if (string.IsNullOrEmpty(link)) return;

        _debugText.text = GetQueryStrings(new Uri(link));
    }

    private string GetQueryStrings(Uri uri)
    {
        var result = "";
        var queryStrings = HttpUtility.ParseQueryString(uri.Query);
        for (var i = 0; i < queryStrings.Count; ++i)
        {
            if (string.IsNullOrEmpty(queryStrings.GetKey(i))) continue;
            result += $"Query{i}: {queryStrings.GetKey(i)}={queryStrings.Get(i)}\n";
        }

        return result;
    }

    private string GetLink(string jsonString)
    {
        // JSON文字列をオブジェクトにデシリアライズ
        var jsonObject = JObject.Parse(jsonString);

        // metadataフィールドを取得
        var metadata = (string)jsonObject["metadata"];
        if (metadata == null) return null;

        // metadataの中から~referring_linkを抜き出す
        var metadataObject = JObject.Parse(metadata);
        var referringLink = (string)metadataObject["~referring_link"];
        return referringLink;
    }
}
```

## デモ
以下リンクからアプリを起動した場合における挙動のサンプルです。
https://test-app.link/?test_query1=1234&test_query2=5678

![branch_qiita.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/dd6cfeef-0547-501f-dead-7ce266bf67b2.gif)

実行環境によっては余計な値がくっついてくるので、欲しい値だけ利用する工夫は必要です。

## 注意点
前提として、"Branch.ioのUnitySDKに関して、ほとんど情報が出てこない"というのが一番の注意点です。

---
### 押下が前提
これはFirebase Dynamic Linksの時も同じ(?)かもしれませんが、deepl linkはユーザーがクリック(モバイルならタップ)することを前提としています。そのため、ブラウザにペーストしたり、コードから任意のURLを開いたり、といった挙動に関しては保証されません。

参考リンク：[Deep links do not open the app](https://help.branch.io/faq/docs/deep-links-do-not-open-the-app)

---
### Firebase Dynamic Linksとの共存
以下にissueを立てた通り、iOSにおいてBranch.ioとFirebase Dynamic Linksの共存が困難となる致命的な不具合が発生します。(バージョン1.0.0時点で報告していましたが、2.0.0も同様かと思います)

issue：[Firebase SDK is not working with Branch SDK. (ios only)](https://github.com/BranchMetrics/unity-branch-deep-linking-attribution/issues/214)

そもそも共存させることはおかしな話に聞こえるかもしれませんが、置き換えとなると話は別で、"発行済みである既存のリンクの動作を保証しつつ、新しいリンクを発行する移行期間を設ける" といったシチュエーションが発生します。

この問題について、Firebase Dynamic Linksのissueに似たような不具合報告があったので試したところ、どちらも正常に動作するようになりました。

参考リンク：[DynamicLinkReceived never fired on iOS](https://github.com/firebase/quickstart-unity/issues/626)

ただ、この対応を行った後に何か別の不具合が発生した場合、問題の切り分けが複雑になったり、Branch.io側が想定していない状況のためサポートを求めても匙を投げられたりと、良くないことが起こり得るため、基本的に共存させることはおすすめしません。

---
### Unity SDKのサポート体制
[iOS](https://github.com/BranchMetrics/ios-branch-deep-linking-attribution)/[Android](https://github.com/BranchMetrics/android-branch-deep-linking-attribution)向けSDKの更新は結構な頻度で行われているのですが、肝心のUnity SDKへの反映はかなり少なめの更新頻度となっているので、その点には注意が必要です。

サポートやissueを通して、それなりの数のバグ報告を挙げているのですが、解決に向けた前のめりな反応はほとんどありません。ほとんどのバグを自力で解決することになりました。

Unity SDKのユーザーはまだ少なく、彼らの優先度としては低いのかもしれません。

---
### Deferred deep link の挙動確認
Deferred deep link(遅延ディープリンク)とは、アプリ未インストールの状態からアプリをインストールし、その後任意のコンテンツへ誘導するような挙動をするリンクのことを指します。

Androidであればストアの内部テスト、iOSであればTestFlightといった具合に事前チェックのための機能は十分に提供されています。しかし、これらはあくまでテスト用の環境であり、本番環境と完全に一致するわけではないことに注意が必要です。

よって、理想的なフローとして、以下を推奨します。

::: note
- Branch.ioを組み込んでデグレをテスト
- デグレがなければ、Branch.ioを組み込んだ状態でリリース
- リリース版ビルドでテストを実施
- テスト結果に問題がなければdeep linkを正式に発行

:::