iOS アプリで Google AdMob UMP(同意管理)を統合する
Google Mobile Ads SDK と一緒に UMP(User Messaging Platform) を組み込み、GDPR(EEA・英国・スイス)と米国州法(CCPA など)の同意要件を満たすための実装と AdMob コンソール作業のまとめ。Swift / SwiftUI を前提とするが、考え方は UIKit でも同じ。
目次
1. UMP とは / 何を解決するか
UMP(User Messaging Platform)は Google が提供する 同意管理 SDK で、AdMob・Google 広告を使うアプリが各地域の同意要件を自動で満たすための仕組み。
- GDPR(EEA / 英国 / スイス): パーソナライズ広告 / Cookie / アナリティクス使用への明示同意
- 米国州法(CCPA / VCDPA など): 「データの販売・共有を拒否する権利」の提示
- Apple ATT: iOS の IDFA トラッキング許諾(UMP とは別だが連携可能)
ポイント: UMP は 地域判定をランタイム(IP ベース)で行うので、単一バイナリで全地域に対応できる。EU 向けに別ビルドを作る必要はない。
UMP を使わないとどうなるか
- EEA ユーザーへの広告配信が止まる、または非パーソナライズ広告のみ(eCPM 大幅減)
- 米国対象州での広告開示要件違反となる可能性
- App Store / Google Play の審査で指摘されることがある
2. 全体フロー
アプリ起動
└─ ConsentManager.requestConsentInfoUpdate() ← UMP に問い合わせ
├─ 必要なら同意フォーム表示(地域判定済み)
└─ 取得後 MobileAds.start() ← 広告 SDK 初期化
設定画面
└─ 「広告データの設定」ボタン
└─ presentPrivacyOptionsForm() ← EEA / 米国州ユーザーが同意を変更
順序が重要: 同意取得が 完了してから MobileAds.start() を呼ぶこと。逆順だと「同意なしで初期化」したことになり Google ポリシー違反扱いになりうる。
3. SDK 導入(SPM)
Xcode → File → Add Package Dependencies で以下のいずれかを追加。
| パッケージ | 含まれる SDK |
|---|---|
github.com/googleads/swift-package-manager-google-mobile-ads | GoogleMobileAds + GoogleUserMessagingPlatform(UMP は依存で同梱) |
github.com/googleads/swift-package-manager-google-user-messaging-platform | UMP のみ(UserMessagingPlatform) |
広告も配信するアプリなら前者でまとめて入る。SDK のライブラリ名は パッケージ経由で GoogleUserMessagingPlatform、単独パッケージで UserMessagingPlatform と異なる点に注意。両対応するなら canImport でガードする:
#if canImport(UserMessagingPlatform)
import UserMessagingPlatform
#elseif canImport(GoogleUserMessagingPlatform)
import GoogleUserMessagingPlatform
#endif
4. コード実装
4.1. ConsentManager の責務分離
UMP API を直接 View / App から呼ぶと条件付きコンパイルや状態管理が散らかる。専用クラス(ConsentManager など)にラップするのが定石。
import Foundation
import os
import Observation
#if canImport(UIKit)
import UIKit
#endif
#if canImport(UserMessagingPlatform)
import UserMessagingPlatform
#elseif canImport(GoogleUserMessagingPlatform)
import GoogleUserMessagingPlatform
#endif
@Observable
final class ConsentManager {
static let shared = ConsentManager()
private init() {}
/// 設定画面で「広告データの設定」ボタンを表示すべきか
var canPresentPrivacyOptions: Bool = false
#if os(iOS)
static func keyRootViewController() -> UIViewController? {
UIApplication.shared.connectedScenes
.compactMap { ($0 as? UIWindowScene)?.windows.first?.rootViewController }
.first
}
/// アプリ起動時に呼ぶ。完了後に completion を呼ぶ。
func requestConsentIfNeeded(from rootVC: UIViewController?,
completion: @escaping () -> Void) {
#if canImport(UserMessagingPlatform) || canImport(GoogleUserMessagingPlatform)
let params = RequestParameters()
// 子ども向けアプリの場合のみ true。それ以外は false(既定)
// params.isTaggedForUnderAgeOfConsent = true
ConsentInformation.shared.requestConsentInfoUpdate(with: params) { [weak self] error in
if let error {
// ログだけ残して続行(オフライン時など)
self?.refreshAvailability()
completion()
return
}
guard let rootVC else {
self?.refreshAvailability()
completion()
return
}
ConsentForm.loadAndPresentIfRequired(from: rootVC) { [weak self] _ in
self?.refreshAvailability()
completion()
}
}
#else
completion()
#endif
}
func presentPrivacyOptionsForm(from rootVC: UIViewController) {
#if canImport(UserMessagingPlatform) || canImport(GoogleUserMessagingPlatform)
ConsentForm.presentPrivacyOptionsForm(from: rootVC) { _ in }
#endif
}
private func refreshAvailability() {
#if canImport(UserMessagingPlatform) || canImport(GoogleUserMessagingPlatform)
canPresentPrivacyOptions =
ConsentInformation.shared.privacyOptionsRequirementStatus == .required
#endif
}
#endif
}
API 名のリネームに注意: Google Mobile Ads SDK 13.x 以降の UMP は Objective-C 由来の UMP プレフィックス API(UMPConsentInformation など)から Swift 命名(ConsentInformation.shared、params.isTaggedForUnderAgeOfConsent)にリネームされている。古い記事のコードはそのまま動かない。
4.2. 起動時フロー
SwiftUI なら WindowGroup 配下のルート View に .task を付け、UMP → 広告 SDK の順で起動する:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
RootView()
.task { startConsentAndAds() }
}
}
private func startConsentAndAds() {
if AdService.shared.isInitialized { return }
#if os(iOS)
let rootVC = ConsentManager.keyRootViewController()
ConsentManager.shared.requestConsentIfNeeded(from: rootVC) {
AdService.shared.configure() // ここで MobileAds.start
}
#else
AdService.shared.configure()
#endif
}
}
App.init()から呼ばない — まだUIWindowSceneが確立していないのでrootVCがnilになる- 多重起動を防ぐ —
isInitializedガードで再入を弾く(タブ切り替えで.taskが再発火する SwiftUI のクセ対策)
4.3. 設定画面のエントリポイント
GDPR / 米国州法は「ユーザーが同意を後から変更できる導線」を要求する。設定画面に「広告データの設定」「プライバシー設定」などのボタンを置き、UMP のフォームを再表示できるようにする:
Section("プライバシー") {
if ConsentManager.shared.canPresentPrivacyOptions {
Button {
guard let rootVC = ConsentManager.keyRootViewController() else { return }
ConsentManager.shared.presentPrivacyOptionsForm(from: rootVC)
} label: {
Label("広告データの設定", systemImage: "hand.raised")
}
}
}
canPresentPrivacyOptions(=privacyOptionsRequirementStatus == .required)で出し分けることで、EEA / 米国対象州のユーザーにだけ表示される。日本ユーザーには表示されない。
4.4. 子ども向けアプリの注意点
13 歳未満をターゲットとするアプリ(Apple Kids Category / Family Designed for Kids)では:
params.isTaggedForUnderAgeOfConsent = trueを渡す- Google Mobile Ads SDK 側で
tagForChildDirectedTreatment = true、tagForUnderAgeOfConsent = true、maxAdContentRating = .generalを設定(COPPA) - UMP はサーバ側で under-age 用の最小限の同意 UI に切替、または非表示にする
- ATT(IDFA)は使わない —
NSUserTrackingUsageDescriptionもInfo.plistに入れない
5. AdMob コンソール側の作業
コードだけでは不十分で、AdMob 管理画面で同意メッセージを作成・公開する必要がある。場所は:
AdMob 左メニュー └─ プライバシーとメッセージ ├─ 欧州の規制(GDPR) ← 作成 / 公開 ├─ 米国の州の規制(CCPA 等) ← 作成 / 公開 └─ IDFA 説明メッセージ ← ATT 使うときのみ
5.1. 米国の州メッセージ
- 「米国の州の規制」→ 「作成」
- テンプレート(My data preferences)から「同意のみ」または「Don't sell or share my data」を選択
- 対象アプリを選択(後述の「アプリを選択」ダイアログでプライバシーポリシー URL も入力)
- 言語を追加(日本語 + 英語など)
- 公開
- 「エントリ ポイント」タブは触らなくて OK(§7 参照)
5.2. GDPR メッセージ
- 「欧州の規制」→ 「作成」
- 標準は IAB TCF v2.2 形式(200 社超のパートナー一覧)。子ども向けアプリでも UMP がサーバ側で under-age 用に切り替えるのでこのテンプレで OK
- 右パネル「ユーザーの選択」で 「同意しない」を必ずオン(CNIL 解釈で実質必須)
- 「アプリを選択」ダイアログでアプリ選択 + プライバシーポリシー URL を入力
- デフォルト言語と追加言語を設定
- 右上「公開」ボタンが青くなったらクリック
5.3. GDPR アカウント設定(メッセージとは別)
欧州の規制 → 「設定」タブには、メッセージとは別のアカウント全体の挙動を制御する項目がある。子ども向け / 厳格運用なら:
| 項目 | 推奨 | 理由 |
|---|---|---|
| 正当な利益のコントロール | オフ | 明示同意のみで運用。CNIL 等で安全 |
| 広告目的の同意モード | オン | UMP SDK と Google 広告サービスの連携に必須 |
| 特殊機能 2(デバイススキャン) | オフ | 子ども向けやプライバシー重視なら不要 |
| 同意の同期 | オフ | 複数アプリで同期しないなら off |
| 広告パートナーを自動的に追加 | オン | 収益機会を逃さない |
6. App Store Connect 側
- Privacy Policy URL: App Information → Privacy Policy URL に入れる。AdMob 側のメッセージからもこれを参照させる運用が一般的
- App Privacy Labels: 「広告」カテゴリのデータ収集を正確に申告
- Privacy Manifest(PrivacyInfo.xcprivacy): 2024 年春以降、サードパーティ SDK を使うアプリで必須。Google Mobile Ads SDK の
NSPrivacyAccessedAPIType(UserDefaults・FileTimestamp など)を宣言 - EU 配信時の Trader 宣言: DSA 要件で 2024 年 2 月〜必須。個人開発でも EU に配信するなら宣言する
7. ハマりどころ・トラブルシューティング
TS-1: プライバシーポリシー URL は AdMob のどこに入れるか
設定場所: プライバシーとメッセージ → 欧州の規制(または 米国の州の規制) → メッセージ編集 → 全般設定 → アプリ → 「アプリを選択」ボタン → 開いたダイアログ内に、アプリごとの行に「プライバシー ポリシーの URL」列がある。ここに URL を入れる。
誤探索しやすい場所:
- メッセージ編集画面の「設定」タブ(GDPR アカウント設定)→ ここには無い
- 左メニュー → アプリ → 個別アプリ → 「アプリの設定」ページ → ここにも無い
AdMob はプライバシーポリシー URL を「アプリ単位、メッセージ編集時の選択ダイアログ内」で管理している。
TS-2: 「エントリ ポイント」タブで「実装する必要があります」表示が消えない
コード側で presentPrivacyOptionsForm を SettingsView に組み込んでも、AdMob のエントリポイントタブが「未実装」表示のまま。
結論: このタブは SDK のランタイム通信ベースで Google が検知するが、反映に大幅なラグがある。ストア公開も必須ではない。表示が消えなくてもメッセージの公開は可能。実装完了の判定にはこのタブを使えない。
TS-3: 「公開」ボタンが灰色のまま押せない
必須項目の未入力で公開ボタンが活性化しない。よくある原因:
- 「同意しない」が
選択 ▼のまま → オンに変更 - アプリを選択していない → 「アプリを選択」で選ぶ
- 言語が未設定
TS-4: SDK API リネームでビルドエラー
古い記事のコードをコピーすると UMPRequestParameters など Obj-C 由来の名前で書かれており、現行 SDK ではビルドが通らない。Xcode のリネーム提案に従って:
| 旧 API(Obj-C) | 新 API(Swift) |
|---|---|
UMPRequestParameters | RequestParameters |
params.tagForUnderAgeOfConsent | params.isTaggedForUnderAgeOfConsent |
UMPConsentInformation.sharedInstance | ConsentInformation.shared |
UMPConsentForm.loadAndPresentIfRequired | ConsentForm.loadAndPresentIfRequired |
UMPConsentForm.presentPrivacyOptionsForm | ConsentForm.presentPrivacyOptionsForm |
TS-5: import UserMessagingPlatform でビルド失敗
SPM で GoogleMobileAds 経由で UMP が入ると、ライブラリ名が GoogleUserMessagingPlatform になる。import UserMessagingPlatform 単独だと解決できないことがある。
対応: 両方の canImport でガードする(§3)。
TS-6: 子ども向けアプリで IAB TCF v2.2 を出してよいか
IAB TCF テンプレは「200 社超のパートナーへのデータ共有」を求める文言。子ども向けには不適切に見える。
結論: UMP は isTaggedForUnderAgeOfConsent = true を受け取ると、サーバ側で under-age ユーザーに対して最小限の表示か非表示に切り替える。テンプレ自体はそのままでよい。ただしアカウント設定で「正当な利益オフ / 特殊機能 2 オフ」にして厳格化しておくと安心。
8. 動作確認のコツ
日本のシミュレーターでは UMP フォームが出ないので、デバッグ設定で地域を強制する:
let debug = DebugSettings()
debug.geography = .EEA // .EEA / .other / .disabled
debug.testDeviceIdentifiers = ["XXXX-XXXX-..."] // Xcode コンソールに出る ID
params.debugSettings = debug
- テストデバイス ID: 初回起動時に SDK が
<UMP SDK>ログでハッシュを出す。それをコピペ - 同意状態をリセット:
ConsentInformation.shared.reset()をデバッグメニューから呼べるようにしておくと検証が楽 - 本番では debugSettings を外す — テスト ID が含まれたままだと挙動が変わる