iOS14【ベストプラクティス】IDFAオプトインの事前説明プロンプトをサクッと対応する方法


## 概要
アプリにAdMobを導入している場合は「Google Funding Choices」を利用すると

**IDFA許諾の事前説明プロンプト提示後に → App Tracking Transparency(ATT)プロンプト**

というフローを簡単に実装出来る。その手順。

## 「Google Funding Choices」とは？

簡単な操作でユーザーにメッセージと選択肢を提示し

- IDFA
- EU 一般データ保護規則（GDPR
- カリフォルニア州消費者プライバシー法（CCPA

など、義務付けられた同意やオプトアウトをスムーズに得られるソリューション。

- プロンプトUIやメッセージのカスタマイズ、ローカライズ
- レポーティング

などの機能がある。

## 「Google Funding Choices」をIDFA許諾で使うメリット

**IDFA許諾率を上げる為のベストプラクティス**として
ユーザにIDFA取得についての事前説明を行った後に、オプトインを求めるATTプロンプトを出す方法が推奨されている。

このフローを**別途UIなどの実装をすることなく**簡単に作れる。

## AdMobでの手順

まずダッシュボードへログイン

- 「プライバシーとメッセージ」タブ
- 「ファンディング チョイスに移動」ボタン
- 規約同意を行う
- 「アプリ」タブ
- 対象のアプリを選択
- 「作成」をクリック
- IDFAメッセージを選択
- メッセージのタイトル（管理用）とデフォルト言語設定
- 対応言語をチェックボックス選択
- 「続行」

→ メッセージやUI編集を行う

最後は「保存」で終了。

※ この時点では、メッセージは「非公開」ステータス。全ての準備が終わったら公開する。

## アプリ側

### AdMob SDKをインストール

例）CocoaPods

```bash
pod 'Google-Mobile-Ads-SDK'
```

### 「Info.plist」

- AdMobのAppIDを設定

```xml
<key>GADApplicationIdentifier</key>
<string>YOUR-ADMOB-APP-ID</string>
```

- App Tracking Transparency カスタムメッセージ
- 
ここで設定するメッセージは、**ATTアラートで本体で出すメッセージ**となる。
（Funding Choicesで作成したメッセージとは別）

```xml
<key>NSUserTrackingUsageDescription</key>
<string>This identifier will be used to deliver personalized ads to you.</string>
```

### AppTrackingTransparency framework

- Xcode＞TARGETS＞BuildPhases＞Link Binary with Libraries

    AppTrackingTransparency frameworkを追加する

## 実装

### 事前説明フォームのリクエスト

```swift
func requestPrompt(){
        
        // UMPRequestParameters
        let parameters = UMPRequestParameters()
        // 許諾年齢未満であるか？ IDFAの場合はFalse固定で良いと思われる
        parameters.tagForUnderAgeOfConsent = false
        
        // 事前許諾プロンプトの提示状況をリクエスト
        // メインスレッドで呼ぶ必要あり
        UMPConsentInformation.sharedInstance.requestConsentInfoUpdate(
            with: parameters,
            completionHandler: { error in
                
            if error != nil {
                debugPrint(error?.localizedDescription ?? "any error")
            } else {
                // 事前許諾プロンプトが利用可能かチェック
                let formStatus = UMPConsentInformation.sharedInstance.formStatus
//                UMPFormStatus.unknown：0 不明
//                UMPFormStatus.available：1 利用可能
//                UMPFormStatus.unavailable：2 利用不可
                debugPrint("Pre Permission Form Status \(formStatus.rawValue)")
                if formStatus == .available {
                    DispatchQueue.main.async {
                        // プロンプトをロード
                        self.loadForm()
                    }
                }
            }
        })
    }
```

### 事前説明フォームの読み込み

```swift
private func loadForm() {
        // メインスレッドで呼ぶ必要あり
        UMPConsentForm.load { (form, loadError) in
            if loadError != nil{
                debugPrint(loadError?.localizedDescription ?? "any error")
            }else{
                // プロンプトの読み込み完了
                // 事前許諾の提示ステータスをチェック（※ATTステータスではない
//                UMPConsentStatus.unknown：0 不明
//                UMPConsentStatus.required：1 提示が必要
//                UMPConsentStatus.notRequired：2 提示の必要なし
//                UMPConsentStatus.obtained：3 提示済み（プロンプト内アクション済み
                debugPrint("UMPConsentInformation.sharedInstance.consentStatus >> \(UMPConsentInformation.sharedInstance.consentStatus.rawValue)")
                if UMPConsentInformation.sharedInstance.consentStatus == .required {
                    // プロンプトの提示が必要
                    guard let vc = UIViewController.getFrontViewController() else {
                        return
                    }
                    form?.present(from: vc, completionHandler: { dismissError in
                        // ATTのプロンプト決定後コールバックされる
                        self.updateATTStatus()
                    })
                }
            }
        }
    }
```

### ATTプロンプト決定後、許諾ステータスを確認する

```swift
private func updateATTStatus(){
        let status = ATTrackingManager.trackingAuthorizationStatus
        switch status {
        case .notDetermined, .restricted, .denied:
            debugPrint("ATT >> .notDetermined, .restricted, .denied")
        case .authorized:
            debugPrint("ATT >> authorized")
        @unknown default:
            debugPrint("ATT >> unknown")
        }
 }
```

## 参考

- IDFA メッセージの作成
[Create an IDFA message](https://support.google.com/fundingchoices/answer/9997151)

- User Messaging Platformでの同意の取得
[Obtaining Consent with the User Messaging Platform | UMP SDK for iOS](https://developers.google.com/admob/ump/ios/quick-start#update_your_infoplist)