ATT ダイアログをいつ出すか問題 — 起動直後の 1 秒遅延

| 開発記録 | QRリーダー

タグ: #iOS #ATT #App Store

ATT(App Tracking Transparency)ダイアログを「いつ表示するか」は、App Store のリジェクト要因にもなる繊細なテーマです。起動直後に出すと拒否率が上がる、出さないとリジェクト。1 秒遅延で落ち着いた話。

ATT ダイアログとは

iOS 14.5 以降、広告のためにユーザーの IDFA を使うには ATT ダイアログでの許可が必要です。表示しないと、広告 SDK が IDFA を取得できず、収益に影響します。

いつ出すかが意外と難しい

Appleのガイドラインでは「アプリを使い始める前後の自然なタイミング」で表示するよう求められています。が、実際の運用ではタイミング設計でハマるポイントが多々あります。

  • 起動直後すぎる: スプラッシュ画面の上に出てしまい、ダイアログが乗らない
  • 遅すぎる: ユーザーがすでにアプリを操作しており、ダイアログが唐突
  • 同意フローの最中: GDPR の UMP ダイアログと被ると地獄

試行錯誤の履歴

コミット履歴を見ると、ATT 表示は何度も調整しています。

  1. アプリ起動直後に表示 → 表示されないケース報告
  2. 1 秒の遅延を追加 → 安定して表示されるように
  3. 文言を全 14 言語に整備
Future.delayed(const Duration(seconds: 1), () {
  AppTrackingTransparency.requestTrackingAuthorization();
});

addPostFrameCallback の併用

Swift 側で直接 ATTrackingManager を呼ぶ場合も、起動直後の即時呼び出しは避け、UI が落ち着くまでわずかに遅らせるのが安定する印象です。

import AppTrackingTransparency

func requestAttIfNeeded() {
  guard #available(iOS 14.5, *) else { return }
  let delay: DispatchTime = .now() + 1.0
  DispatchQueue.main.asyncAfter(deadline: delay) {
    ATTrackingManager.requestTrackingAuthorization { status in
      switch status {
      case .authorized:
        Analytics.log("att_authorized")
      case .denied, .restricted, .notDetermined:
        Analytics.log("att_declined_\(status.rawValue)")
      @unknown default:
        break
      }
    }
  }
}

万華鏡アプリの方では、WidgetsBinding.instance.addPostFrameCallback 内でリクエストするようにしました。Widget ツリーが構築されたあとに呼ぶことで、ダイアログが確実にトップ画面の上に乗ります。

文言の重要性

ATT ダイアログ本体(OS が出す部分)の上に表示できる説明文は、アプリ側で記述します。「広告のために許可してください」とだけ書くと拒否率が高くなるので、「無料で提供を続けるために、関連性の高い広告を表示する目的で利用します」のような言い方に変えたら、許可率が改善しました。

サブタイトルから「価格表記」を外す

App Store 審査周りで関連する話として、「価格表記」をサブタイトルから外した修正もありました。Apple は「無料」「Free」のような表現をストア画面に置くのを嫌がります。これも審査リジェクト経験からの学びです。

まとめ

  • ATT は 1 秒遅延 + addPostFrameCallback の組み合わせが安定
  • 文言は丁寧に、機械翻訳のままにしない
  • 関連で UMP(GDPR 同意)の順序設計も忘れずに

小さなダイアログひとつに、ここまで考えることがあるのが App Store の現実です。