前記事「はじめてのAppsFlyer: (2) iOS SDK実装/iOSシミュレーターでの動作確認」の続きの内容となります。
iOS SDKの実装においては、ATTフレームワークの考慮が必要です。AppsFlyer SDKを利用する際に、ATTフレームワーク実装において事前に考慮すべき点や、具体的な実装方法、iOSシミュレーターでの動作確認について解説します。
ATTフレームワークとは?
ATT (App Tracking Transparency) フレームワークとは、AppleがiOS14より導入したユーザープライバシー保護のための方式です。アプリがIDFAを取得するために、定型のポップアップを表示してユーザーに明示的な許可を得ることが必要になりました。以前は、ユーザーが設定でオプトアウトしていない限りはアプリはIDFAの取得ができたのですが、iOS 14.5以降、アプリがIDFAを取得するためにはポップアップでの許可が必須になりました。
ATTフレームワークの実装はオプションであり、IDFAを使わない場合にはこの実装は不要です。ただし、IDFAがないと広告の効果測定ができないアドネットワークもあるため、より正確にアトリビューションを行うことを目指すのであれば、ATTフレームワーク実装が必要となります。
AppsFlyerでのATTフレームワーク実装
ATTフレームワークを実装しない場合には、AppsFlyer SDK開始後、直ちにインストール計測が行われますが、ATTフレームワークを実装する場合には、AppsFLyer SDKは開始後すぐにインストール計測を行わずに、指定された「タイムアウト期間」はインストール計測を遅延させます。
このタイムアウト期間の間にユーザーからATT許諾を得られた場合には、その時点で直ちに取得したIDFAの情報を元にインストール計測を行います。
逆にユーザの"Appにトラッキングしないように要求"を選んだ場合や、タイムアウト期間内にユーザーがどちらも選択しなかった場合には、IDFAなしでインストール計測を行います。
ATTフレームワーク実装手順
ここからは具体的な実装方法について解説します。
- 前記事 のようなSDK実装が完了していることを前提として、ATTフレームワークを追加実装する方法となります。
- AppsFlyer SDKはATTフレームワークに対応しているv.6以上で実装されていることを前提とします。
1 - ATTポップアップのメッセージを定義する
Info.plist
内にNSUserTrackingUsageDescription
というパラメーターとして定義します。NSUserTrackingUsageDescription
と入力すると、Privacy - Tracking Usage Description
に自動的に置き換わりますが、この行のValueとして、メッセージを入力します。
例: 「パーソナライズされた広告を配信するためには許可を選んでください。」
備考
実際にアプリをリリースする際には、このメッセージをどのような文言にするのかは、結構重要なトピックであり、アプリの特性に合わせた考慮が必要です。
メッセージを検討する上で参考になりそうな情報のリンクを貼っておきます。
2 - requestTrackingAuthorizationの呼び出し
ATTポップアップを表示したい箇所でrequestTrackingAuthorization
を呼び出してください。
例えば、アプリ起動直後にATTポップアップを表示したい場合には、下記のようにdidBecomeActiveNotification
内のAppsFlyerLib.shared().start()
直後に呼び出します。
@objc func didBecomeActiveNotification() {
// start is usually called here:
// AppsFlyerLib.shared().start()
if #available(iOS 14, *) {
ATTrackingManager.requestTrackingAuthorization { (status) in
switch status {
case .denied:
print("AuthorizationSatus is denied")
case .notDetermined:
print("AuthorizationSatus is notDetermined")
case .restricted:
print("AuthorizationSatus is restricted")
case .authorized:
print("AuthorizationSatus is authorized")
@unknown default:
fatalError("Invalid authorization status")
}
}
}
}
アプリ内でスタートボタンを押したタイミングでATTポップアップを表示させたいなどの場合は、任意のアクションを定義して、その中で呼び出すことも可能です。
@IBAction func tapStart(_ sender: Any) {
if #available(iOS 14, *) {
ATTrackingManager.requestTrackingAuthorization { (status) in
switch status {
case .denied:
print("AuthorizationSatus is denied")
case .notDetermined:
print("AuthorizationSatus is notDetermined")
case .restricted:
print("AuthorizationSatus is restricted")
case .authorized:
print("AuthorizationSatus is authorized")
@unknown default:
fatalError("Invalid authorization status")
}
}
}
}
いずれの箇所で呼び出した場合にも、requestTrackingAuthorization
を記述したファイルではAppTrackingTransparency
のインポートが必要になりますので、こちらも忘れずに追加します。
import AppTrackingTransparency
参考: Apple Developer - requestTrackingAuthorization(completionHandler:)
3 - waitForATTUserAuthorizationの設定
AppDelegate.swift
のSDKの初期化の箇所で、waitForATTUserAuthorization
を呼び出してください。AppsFlyerLib.shared().start()
の前に呼び出されていることが必要になります。
AppsFlyerLib.shared().waitForATTUserAuthorization(timeoutInterval: 60)
timeoutInterval
の値には、SDK開始後、ATTの許諾ダイアログを表示してからユーザーが操作するまでに十分な時間が確保できるような値を秒数で指定してください。
timeoutInterval
の指定例:
- アプリの初回起動時にATTポップアップを表示する場合: 60秒程度
- 約2分のチュートリアルの完了後にATTポップアップを表示する場合: 180秒程度
注意
requestTrackingAuthorization
を実装していないのに、waitForATTUserAuthorization
だけ呼び出すのは避けてください。
無駄にタイムアウト期間分のみインストール計測を遅延させてしまうだけになります。
また、「いつATT許諾されるかわからないので、timeoutInterval
を例えば1時間後(3,600秒後)など大きな値を設定する」というのはアンチパターンです。
定義通りであれば「ユーザーからの回答が得られないままタイムアウト期間が過ぎた場合には、その時点でインストール計測される」のですが、そのアプリが非アクティベートされたら、アプリに実装されているSDKも動作しません。つまり、タイムアウト期間を過ぎた1時間後のタイミングでインストール計測される可能性は低く、その後もう一度アプリを起動したタイミングで初めてインストール計測されることになってしまいます。
結果的に実際のインストール数と乖離した計測結果になりうるので、このような実装は避けるべきです。
動作確認
上記の実装を行うと、ATTポップアップが表示され、IDFAが取得できることを確認できます。
requestTrackingAuthorizationの呼び出し
はアプリ内でスタートボタンを押したタイミングでATTポップアップを表示させる実装を行い、iOSシミュレータでの動作確認をし、デバッグログの中身を検証してみます。
1 - 「Appにトラッキングしないように要求」を選択した場合
ATTポップアップ表示後、「Appにトラッキングしないように要求」を選択し、そのデバッグログをみるとATT許諾のステータスがdenied
になったことが確認できます。
AuthorizationSatus is denied
2022-12-19 22:12:50.003118+0900 AdventTest[34984:3506825] [AppsFlyerSDK] [com.appsflyer.serial] [ATT] Tracking authorization update from `oldStatus`: 0 to `newStatus`: 2
2022-12-19 22:12:50.003550+0900 AdventTest[34984:3506825] [AppsFlyerSDK] [com.appsflyer.serial] Denied/Restricted
2022-12-19 22:12:50.003949+0900 AdventTest[34984:3506825] [AppsFlyerSDK] [com.appsflyer.serial] Denied/Restricted
また、IDFAを示すadvertiserId
がnullであることが確認できます。
{"timestamp":"1671455570.107637","uid":"1671455556104-2851091","bundlename":"","cell":
{"mcc":"tv|sim", ...,"att_status":2,...,"advertiserId":"", ...
2 - 「許可」を選択した場合
一度iOSシミュレータのアプリを削除し、もう一度アプリをデプロイし、アプリを起動するとATTポップアップ表示されます。
「許可」を選択すると、ATT許諾のステータスがauthorized
になったことが確認できます。
AuthorizationSatus is authorized
2022-12-19 22:16:11.097623+0900 AdventTest[37931:3520243] [AppsFlyerSDK] [com.appsflyer.serial] [ATT] Tracking authorization update from `oldStatus`: 0 to `newStatus`: 3
2022-12-19 22:16:11.139215+0900 AdventTest[37931:3520245] [AppsFlyerSDK] [com.appsflyer.serial] Dynamically loaded library: AdSupport
2022-12-19 22:16:11.146197+0900 AdventTest[37931:3520249] [AppsFlyerSDK] [com.appsflyer.serial] dlopen
2022-12-19 22:16:11.146506+0900 AdventTest[37931:3520248] [AppsFlyerSDK] [com.appsflyer.serial] dlopen
IDFAを示すadvertiserId
はALL0の値になってます。
これはiOSシミュレーターがIDFAを持たないためであり、実機デバイスで確認するとその端末のIDFAの値がみられます。
{"timestamp":"1671455766.846198","uid":"1671455761926-8537326","bundlename":"","cell":
{"mcc":"tv|sim", ...,"att_status":3,...,"advertiserId":"00000000-0000-0000-0000-000000000000", ...
3 - タイムアウト期間超過の場合
デバッグログ上では、AppsFlyer SDK開始のメッセージ後、ちょうど60秒後のタイムアウトのタイミングで"ATT timer expired"になったことが確認できます。
2022-12-19 22:06:27.719555+0900 AdventTest[31579:3491202] [AppsFlyerSDK] [com.apple.main-thread] AppsFlyer SDK version 6.9.1 started build (92)
...
2022-12-19 22:07:27.962460+0900 AdventTest[31579:3493682] [AppsFlyerSDK] [com.appsflyer.serial] [ATT.2] ATT timer expired. Preparing queued events: 2
2022-12-19 22:07:27.962871+0900 AdventTest[31579:3493681] [AppsFlyerSDK] [com.appsflyer.serial] NotDetermined
2022-12-19 22:07:27.963274+0900 AdventTest[31579:3493683] [AppsFlyerSDK] [com.appsflyer.serial] NotDetermined
denied
の場合と同様に、IDFAを示すadvertiserId
はnullになっています。
{"timestamp":"1671453713.383594","uid":"1671455185355-7453864","bundlename":"","cell":
{"mcc":"tv|sim", ...,"att_status":0,...,"advertiserId":"", ...
まとめ
この記事では、少し取っ付きづらいATTフレームワークの実装について解説しました。
これから実装される方の参考になればうれしいです。
前記事、この記事ではiOSシミュレーターでの検証まででした。次の記事では、これまで実装したアプリを利用して、実機デバイスを使った非オーガニックインストール計測のテスト方法を解説します。