ATT対応とUnityAdsを併用したらリジェクトを食らった話と、その解決法

# はじめに
iOSアプリを作成する上では避けては通り難い、ご存知iOS14からのATT(App Tracking Transparency)対応。
自分も今回拙作「二枚残す道場」に組み込んでみました。
アプリはこちら↓（宣伝）

https://play.google.com/store/apps/details?id=com.ScreenPocket.Two

https://apps.apple.com/jp/app/id1567787247

最初の実装の際に参考にさせて頂いたのはこちら↓

https://hirokuma.blog/?p=3003

# 不意のリジェクト
さて、何度かバージョン更新した所、不意にリジェクトが…。

```
Guideline 5.1.2 - Legal - Privacy - Data Use and Sharing

We noticed you collect data to track after the user selects "Ask App Not to Track" on the App Tracking Transparency permission request.
Specifically, we noticed your app accesses web content you own and collects cookies for tracking after the user asked you not to track them.

Next Steps
To resolve this issue, please revise your app so that you do not collect data for tracking purposes if the user does not give permission for tracking.

Resources
- Tracking is linking data collected from your app with third-party data for advertising purposes, or sharing the collected data with a data broker. Learn more about tracking.
- See Frequently Asked Questions about the new requirements for apps that track users.

Please see attached screenshot for details.
```
「ATTダイアログで収集を【許可しない】を選択したにも関わらずCookieを収集しているぞ」との通知。
慌ててスクリーンショットを確認した所、どうやらUnityAdsがCookie収集しているようでした。

なるほど、ということは2つの対応をしなければなりません。

* **ATTダイアログでユーザが選択した結果を取得する**
* **ユーザが選択した結果に合わせてUnityAdsの表示方法を変える**

さてどうしたものか。

# iOS 14 Advertising Supportを発見→実装

ユーザのATT選択状況を取得する上で良い方法はないかなーと色々調査した結果、どうやら2021年5月辺りにUnityのパッケージに**「iOS 14 Advertising Support」**というパッケージが追加されたようでした。
![スクリーンショット 2021-07-19 23.17.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61266/5d161375-cf93-3f68-6bce-9764147c7952.png)
パッケージマネージャからインストールし、サンプルを読んで実装します。サンプルにはご丁寧に**ATTダイアログ直前に表示するダイアログ**もついてきました。

とりあえず仕上がったコードとしてはこちら↓

```cs:Main.csのStart()関連処理抜き出し
private IEnumerator Start()
{
            :
    yield return SetupAttAndAdAsync();
            :
    //タイトル開始
    SetState<MainStateTitle>();
}

/// <summary>
/// ATTとAdの準備
/// </summary>
/// <returns></returns>
private IEnumerator SetupAttAndAdAsync()
{
    //IOSはUnityAds初期化前にATT対応を終わらせておく
#if UNITY_IPHONE || UNITY_IOS
    // check with iOS to see if the user has accepted or declined tracking
    var status = ATTrackingStatusBinding.GetAuthorizationTrackingStatus();

    //まだATT方針を決めていないなら
    if (status == ATTrackingStatusBinding.AuthorizationTrackingStatus.NOT_DETERMINED)
    {
        ここに、ダイアログを表示して、完了したら
　　　　　　　　　　　　　　　　OnClickCenterButtonAttDialog()
        を呼ぶ処理を書く
        iOS 14 Advertising Supportのサンプルが参考になるかと。
    }

    //実機の時だけ完了待ちをする
#if !UNITY_EDITOR
    while (status == ATTrackingStatusBinding.AuthorizationTrackingStatus.NOT_DETERMINED)
    {
        status = ATTrackingStatusBinding.GetAuthorizationTrackingStatus();
        yield return new WaitForEndOfFrame();
    }
#endif

#else
    Debug.Log("Unity iOS Support: App Tracking Transparency status not checked, because the platform is not iOS.");
#endif

    //広告の初期化
#if UNITY_ANDROID || UNITY_IPHONE || UNITY_IOS
    Advertisement.AddListener(this);
    //gameId,testModeはご自身のアプリに合わせて
    Advertisement.Initialize(gameId, testMode);
    //バナーの初期化はご自身で実装してください↓
    yield return RequestBannerAsync();
#else
    yield break;
#endif
}

private void OnClickCenterButtonAttDialog()
{
#if UNITY_IPHONE || UNITY_IOS
    Debug.Log("Unity iOS Support: Requesting iOS App Tracking Transparency native dialog.");
    ATTrackingStatusBinding.RequestAuthorizationTracking();
#else
    Debug.LogWarning("Unity iOS Support: Tried to request iOS App Tracking Transparency native dialog, but the current platform is not iOS.");
#endif
}
```
ポイントは

* **ATTrackingStatusBinding.RequestAuthorizationTracking();でATTダイアログが呼べる！**
* **ATTrackingStatusBinding.GetAuthorizationTrackingStatus()でATTの状態を取得できる！**
* **yield return でstate変更の完了待ち！**

でしょうか。
RequestAuthorizationTracking()を使用すれば、**最初に貼ったリンクのDLLImport対応などが不要になる**ので随分楽になりました。
またyield return new WaitForEndOfFrame();は、yield return null;でも良いかも。
自分が実装した時はnew WaitWhile()やnew WaitUntil()ではどうにも上手くいかなかったので、もし情報あれば頂けるとありがたいです。

# UnityAdsのCookie収集表記を切り替える

さて、上記のiOS 14 Advertising SupportパッケージでATTの状態取得はできるようになりました。
次は「その情報を元にUnityAdsの表示切り替えをする」
ということで調査した所、下記のスレッドを発見しました。

https://forum.unity.com/threads/app-rejected-because-unity-ads-own-data-collection-permission-request-violates-att-guidelines.1103065/

記事曰く**「GDPRの表示をさせないようにすれば良い」**とのこと。
また、そのためには**「Advertisingの初期化前にGDPRに値(false)を設定すれば良い」**とのこと。
コードとしてはこんな感じで↓

```cs
var gdprMetaData = new MetaData("gdpr");
gdprMetaData.Set("consent", ”false”);//falseは文字列で渡す
Advertisement.SetMetaData(gdprMetaData);
```

ということで、先程のコードを修正します。

```cs:Main.csのStart()関連処理抜き出し(GDPR対応版)
private IEnumerator Start()
{
            :
    yield return SetupAttAndAdAsync();
            :
    //タイトル開始
    SetState<MainStateTitle>();
}

/// <summary>
/// ATTとAdの準備
/// </summary>
/// <returns></returns>
private IEnumerator SetupAttAndAdAsync()
{
    //IOSはUnityAds初期化前にATT対応を終わらせておく
#if UNITY_IPHONE || UNITY_IOS
    // check with iOS to see if the user has accepted or declined tracking
    var status = ATTrackingStatusBinding.GetAuthorizationTrackingStatus();

    //まだATT方針を決めていないなら
    if (status == ATTrackingStatusBinding.AuthorizationTrackingStatus.NOT_DETERMINED)
    {
        ここに、ダイアログを表示して、完了したら
　　　　　　　　　　　　　　　　OnClickCenterButtonAttDialog()
        を呼ぶ処理を書く
        iOS 14 Advertising Supportのサンプルが参考になるかと。
    }

    //実機の時だけ完了待ちをする
#if !UNITY_EDITOR
    while (status == ATTrackingStatusBinding.AuthorizationTrackingStatus.NOT_DETERMINED)
    {
        status = ATTrackingStatusBinding.GetAuthorizationTrackingStatus();
        yield return new WaitForEndOfFrame();
    }
#endif

　　//追加部分ここから！！！！！！
　　//ATT対応の結果を持って、Adを初期化しておかないとCookieの収集を行ってしまいリジェクトを食らってしまう
    var gdprMetaData = new MetaData("gdpr");
    //許可の時だけ true
    var isGdpr = ATTrackingStatusBinding.GetAuthorizationTrackingStatus() == ATTrackingStatusBinding.AuthorizationTrackingStatus.AUTHORIZED;
    gdprMetaData.Set("consent", isGdpr.ToString());
    Advertisement.SetMetaData(gdprMetaData);
    //追加部分ここまで！！！！！！

#else
    Debug.Log("Unity iOS Support: App Tracking Transparency status not checked, because the platform is not iOS.");
#endif

    //広告の初期化
#if UNITY_ANDROID || UNITY_IPHONE || UNITY_IOS
    Advertisement.AddListener(this);
    //gameId,testModeはご自身のアプリに合わせて
    Advertisement.Initialize(gameId, testMode);
    //バナーの初期化はご自身で実装してください↓
    yield return RequestBannerAsync();
#else
    yield break;
#endif
}

private void OnClickCenterButtonAttDialog()
{
#if UNITY_IPHONE || UNITY_IOS
    Debug.Log("Unity iOS Support: Requesting iOS App Tracking Transparency native dialog.");
    ATTrackingStatusBinding.RequestAuthorizationTracking();
#else
    Debug.LogWarning("Unity iOS Support: Tried to request iOS App Tracking Transparency native dialog, but the current platform is not iOS.");
#endif
}
```

これで、**ATT許可の時だけGDPRにtrueが渡され、それ以外ではfalseが渡される**ようになりました。
そもそも許可の時は値を設定しなくても良いかもですが、その辺りは良い感じに修正してもらう方向で…。

# おわりに
という事で、上記のコードを加えて審査に提出する事でレビューを通すことができました。
もしかするといずれはUnityAds内で勝手に対応してもらえる時が来るかもしれませんが、
なかなか調査に時間がかかったので念の為記事化しておきます。