IDFAの実装について(トラッキング関連)


広告のトラッキングの実装についてIDFAの実装が必要となります。
簡易的な方法となりますが、下記の実装方法があります。

※実装前にプロジェクトのコピー(バックアップ)をとってから実装することをお勧めします。

IDFA対応コードの実装
No必須・任意実装概要
1必須追加する広告の実装
2必須フレームワークの追加
3必須Info.plistの項目追加
4任意多言語化対応
5必須IDFAコード実装

1.追加する広告の実装
開発者ごとに異なると思います。
実装方法は各広告媒体会社にお問い合わせください。

2.フレームワークの追加
※下の画像をご覧ください。
(1) プロジェクトを選択します。
(2) TARGETSを選択します。
(3) Generalタブを選択します。
(4) 下方向にスクロールをすると
(5) 「Framework」の項目が見えます。
(6) +ボタンでフレームワークを追加します。


下記の2点のフレームワークを追加します。
(1)AdSupport.framework
(2)AppTrackingTransparency.framework

3.Info.plistの項目追加

「Info.plist」に次の項目を追加してください。
KeyPrivacy - Tracking Usage Description
Valueメッセージに表示する内容を入力します。
※xmlに直接追加する場合は「NSUserTrackingUsageDescription」となるはずです。

4.多言語化対応
多言語化処理は任意の情報となります。
日本語のみでなく、英語などの複数言語を公開している場合は
そのユーザに対応した言語を表示したいケースがあると思います。
その方法として「info.plist.stringの多言語化」があります。


4-1. 言語の追加

(1)プロジェクトを選択します。
(2)PROJECTを選択します。
(3)Infoタブを選択します。
(4)下にスクロールしていき、「Localizations」の項目の+ボタンを選択します。
(5)Japanese(ja)を選択します。

4-2.Strings Fileの追加

(1)プロジェクトを選択して「New File...」を選択します。
(2)iOSタブを選択して下方向にスクロールし、「Resource」グループの「Strings File」を選択します。
(3)Save Asテキストボックスに「InfoPlist.strings」を入力してCreateボタンを選択します。
※この名称を間違えると失敗するようですので、気をつけて入力してください。

4-3. Localizeの追加

(1)「Localize...」ボタンを選択します。
(2)追加する言語を選択します。

4-4. 多言語化のメッセージを追加

図のように言語ごとに表示するメッセージを入力してください。

5. IDFAコード実装
下記にコードの実装サンプルを記載します。
開発者の開発により、実装に適した実装にしてください。

今までは、下記のタイミングで実装していたと思います。
(1)AppDelegate
(2)SceneDelegate
(3)viewDidLoad
しかし、広告の実装を済ませてから、IDFAを実行するのが正規手順となったようで
iOS15からは上記(1)から(3)に実装しているとIDFAのメッセージダイアログが表示されません。

そのためにも、「UIApplicationStateActive」の値がtrueになっている場所での実装が必要となります。
(例)
if (UIApplication.sharedApplication.applicationState == UIApplicationStateActive)
{
    NSLog(@"UIApplicationStateActive is true.");
}


例えば、下記に記したviewDidAppearイベントではなく、
ボタンをタップしたタイミングで実装する開発者の方もいらっしゃるようです。

[コード実装例]
※Objective-C
-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self requestIDFA];
}

-(void)requestIDFA
{
    ASIdentifierManager *identifierManager = [ASIdentifierManager sharedManager];
    if (@available(iOS 14, *))
    {
        // iOS14以降の処理
        //IDFAダイアログを表示したいタイミングで次のコードを実行します。
        //この時にNSUserTrackingUsageDescriptionにメッセージの内容を追加しておく必要があります。
        [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status)
        {
            //広告の取得開始方法
            [GADMobileAds.sharedInstance startWithCompletionHandler:^(GADInitializationStatus * _Nonnull status) 
            {
                //ここで広告をリロードするなどしてください
            }];
            if (status == ATTrackingManagerAuthorizationStatusAuthorized
                || status == ATTrackingManagerAuthorizationStatusNotDetermined)
            {
                //ユーザがプライバシー設定で「トラックしない」を選択していない(オプトイン)
                //もしくはrequestTrackingAuthorizationWithCompletionHandlerでダイアログをまだ表示していません。
                //NSString *idfa = identifierManager.advertisingIdentifier.UUIDString;
                //NSLog(@"idfa:%@",idfa);
                // 取得したIDFAで何かするコード
            }
            else if (status == ATTrackingManagerAuthorizationStatusDenied)
            {
                // ユーザがプライバシー設定で「トラックしない」を選択(オプトアウト)
                // IDFAが取得できなかった場合のコード
            }
            else
            {
                // それ以外のなにか
            }
        }];
    }
    else
    {
        // iOS13以前の処理
        //ASIdentifierManager *identifierManager = [ASIdentifierManager sharedManager];
        if ([identifierManager isAdvertisingTrackingEnabled])
        {
            //NSString *idfa = identifierManager.advertisingIdentifier.UUIDString;
            //NSLog(@"idfa:%@",idfa);
            //取得したIDFAで何かするコード
        }
        else
        {
            //NSLog(@"failure");
            //IDFAが取得できなかった場合のコード
        }
    }
}

サンプルをコピー
UUIDについて
他の広告ではUUID文字列を引数に設定しているようですが、
GoogleのAdMobを使用している場合は、AdMob側でUUIDの実装判定をしているようで
その必要がないようです。

AdMobのSKAdNetwork 対応について
前提条件: Google Mobile Ads SDK 7.64.0 以降
上記前提条件を満たすと、何もしなくても自動的に登録されるようです。

[URL]
https://developers.google.com/admob/ios/ios14#skadnetwork
[審査についての補足情報]
2022年4月上旬に申請した時点では審査チームはiOS15以上でテストをしているようで
iOS15向けの実装をしておいた方がいいと思われます。
IDFAが正しく表示されているキャプチャでは審査を受け付けてもらえませんでした。
動画で撮影したものを準備した方がいいと思います。
シミュレーターでキャプチャをした画像を提出しましたが、
iPhone実機で撮影したものでなければ審査として受け付けないという返信をされました。

動画についてはiOSに標準で使用可能な画面録画アプリで問題ないと思います。

[提出をしたときにリジェクトされたときの文書抜粋]
Guideline 2.1 - Information Needed



We're looking forward to completing our review of your app. Before we can continue, we need a video that demonstrates the current version, 1.2.7, in use on a physical iOS device.

Specifically, we need a demo video that shows the App Tracking Transparency permission request in your app. The video should show what the user sees after selecting "Ask App Not to Track" and "Allow," as well as any prompts or messages that appear before the permission request.

Keep these requirements in mind as you make your demo video:

- Only use footage of your app running on a physical iOS device, not on a simulator.
- Make sure the video clearly documents all relevant app features, services, and user permission requests.
- You can use a screen recorder to capture footage of your app in use.

Next Steps

Create the demo video, add a link to the video in the App Review Information section of your app’s page in App Store Connect, and reply to this message in App Store Connect.

To add the video link:

- Sign in to App Store Connect.
- Click on My Apps.
- Select your app.
- Click on the app version on the left side of the screen.
- Scroll down to App Review Information.
- Provide the demo video link and any necessary access details in the Notes section.
- Click the Save button at the top of the Version Information page.

Please note that if your app can only be reviewed with a demo video, you’ll need to provide an updated demo video for every app submission.

Resources

To learn more about providing information to App Store Review in App Store Connect, see App Store Connect Help.


> Keep these requirements in mind as you make your demo video:
>
> - Only use footage of your app running on a physical iOS device, not on a simulator.
> - Make sure the video clearly documents all relevant app features, services, and user permission requests.
> - You can use a screen recorder to capture footage of your app in use.
上記に記載しているようにiPhone実機で動画を撮影したものを提出してね
といっています。

このことからも動画による提出が必要になるものと思われます。

iPhoneの画面録画のやり方を解説|内部音声や外部音声のみの設定方法
[URL]
https://www.nojima.co.jp/support/koneta/82292/?amp=1
iPhoneで画面録画(スクショ動画を撮影)する方法──できないときの対策も解説
[URL]
https://appllio.com/iphone-take-screenshots-video-capture
[動画の撮影ポイント]
※念のため、審査に提出した撮影した動画ファイルは言語を英語にして撮影したものを提出しました。

1. トラッキング画面
設定画面→プライバシー→トラッキングの順で開き、トラッキング画面の状態を表示します。
このとき、許可(ON:緑色)の状態で撮影しました。
IDFAダイアログ実行済みの(審査する)アプリがあると、IDFAダイアログは一度実行すると実行されなくなります。
IDFAの動作確認にならないため、必要に応じてアプリのデータバックアップなどをして、
一度、アプリを削除してから実行することになると思います。

2. IDFAダイアログの表示
iPhone実機をXcodeに接続し、アプリを実行します。
正しく実装されていると、実装した場所でIDFAの確認ダイアログが表示されるはずです。
「許可」ボタンを
選択して、広告が正しく表示される状態を表示します。

3. トラッキング画面を再表示
トラッキング画面に戻ります。
結果を反映させるため、一度、プライバシー画面に戻ります。
再度、トラッキング画面を開きます。
追加したアプリのIDFAの状態が正しく反映されている状態を表示します。

上記、結果を撮影してmp4動画ファイルにして審査に提出するといいはずです。

iOSのステータスバーの高さ取得について(iOS15以降)

iOSのステータスバーの高さの取得方法に変更になったようです。
※Objective-Cでの実装方法となります。

[コード実装例]
※Objective-C
CGFloat height = 0.0f;
NSSet *scenes = [[UIApplication sharedApplication] connectedScenes];
for (UIScene *scene in scenes)
{
    if ([scene isKindOfClass:[UIWindowScene class]])
    {
        UIWindowScene *windowScene = (UIWindowScene*)scene;
        height = windowScene.statusBarManager.statusBarFrame.size.height;
        break;
    }
}

サンプルをコピー
[経緯]
今までは下記の実装によりステータスバーの高さを取得していました。
CGFloat height = [UIApplication sharedApplication].windows.firstObject.windowScene.statusBarManager.statusBarFrame.size.height;

しかし、iOS15からはDeprecatedになっているため変更の必要が生じました。
[警告メッセージ]
'windows' is deprecated: first deprecated in iOS 15.0 - Use UIWindowScene.windows on a relevant window scene instead

statusBarFrameを参照するとAPI_DEPRECATEDメッセージが下記のように表示されていました。
Use the statusBarManager property of the window scene instead.

そのため、下記のようにしてSceneオブジェクトを生成しようとしたのですが下記の警告メッセージが表示されました。
UIWindowScene *scene = UIApplication.sharedApplication.connectedScenes;
[警告メッセージ]
Incompatible pointer types initializing 'UIWindowScene *' with an expression of type 'API_AVAILABLE(ios(13.0)) NSSet *'

ここでNSSetを使用してくださいというメッセージが表示されているので、
オブジェクトを生成するために下記のように宣言をしました。
NSSet *scenes = [[UIApplication sharedApplication] connectedScenes];

上記のままではsceneオブジェクトの中にUIWindowSceneがどれなのかがわかりません。
そのため、for文を使用して判定処理をした後、UIWindowSceneでキャストをしたオブジェクトに対して
statusBarFrameプロパティからステータスバーの高さを取得しました。

迷惑メールに気をつけて
1/2