SwiftUI 2.0: iOSデバイスをadMobのテストデバイスとしてプログラムで設定する方法

## 課題

iOSアプリケーションをテストする時にGoogle AdMobの[無効なトラフィックポリシー](https://support.google.com/admob/answer/3342054)に違反しないようにするには、[デモ広告](https://developers.google.com/admob/ios/test-ads＃demo_ad_units)または[テストデバイス](https://developers.google.com/admob/ios/test-ads#add_your_test_device_in_the_admob_ui)を使用して、実装コードの動作を確認します。

実装コードの動作を確認するもう1つの方法は、iOSアプリの起動時にiOSデバイスをadMobのテストデバイスとしてプログラムで設定することです...

## Google AdMobのテストモードを有効にする
### [デモ広告ユニット](https://developers.google.com/admob/ios/test-ads#demo_ad_units)
アプリに表示する広告フォーマットに対応するデモ広告ユニットIDを使用します。

たとえば、バナー広告の場合、[デモ広告ユニットリスト](https://developers.google.com/admob/ios/test-ads#demo_ad_units)にあるIDは `ca-app-pub-3940256099942544/2934735716`です。
### [Google AdMobの管理画面でテストデバイスを追加する](https://developers.google.com/admob/ios/test-ads#add_your_test_device_in_the_admob_ui)
デバイステストモードを自動的に有効にするには、[Google AdMobの管理画面](https://apps.admob.com/v2/home)を使用することもできます。.

- 左側のメニューで、[`設定`](https://apps.admob.com/v2/settings/personal-settings)を選択します。
- 次に、ページ上部の[`テストデバイス`](https://apps.admob.com/v2/settings/test-devices/list)タブを選択します。
- `テストデバイスを追加`ボタンをクリックします。
- 最後に、フォームに入力して`保存`をクリックして、デバイスをリストに追加します。

※ このデバイスをテストデバイスリストに追加するには、デバイスのIDFAが必要です。
### [プログラムでテストデバイスを追加する](https://developers.google.com/admob/ios/test-ads#add_your_test_device_programmatically)
デバイスのIDFAがわからない場合があります。この場合、プログラムでデバイステストモードを有効にすることは便利な方法です。

デバイスまたはデバイスのリストをテストデバイスとして設定するには、次の手順に従います。

- まず、 `GADMobileAds.sharedInstance()`を使用してGoogle Mobile AdsSDK設定の共有インスタンスを取得します。
- 次に、 `.requestConfiguration`を使用してすべてのリクエストに共通のリクエスト設定を取得します。
- 最後に、_テストモードで使用されるデバイスのIDリスト_`testDeviceIdentifiers`のなかにテストデバイスに対応するIDリストを組み込みます。

例えば：

```Swift:Swift
import GoogleMobileAds
...
GADMobileAds.sharedInstance().requestConfiguration.testDeviceIdentifiers =
    [ "2077ef9a63d2b398840261c8221a0c9b" ] // Sample device ID
```
※ 最初の広告リクエスト時に、現在のデバイスのテストデバイスIDがコンソールに表示されます。

では、テストデバイスIDを取得する方法は？
## テストデバイスIDFAを取得する
IDFAは、iOSによって発行されたデバイスの広告用IDであり、広告主がデバイスを識別するために使用します。

デバイスIDFAを取得するには：

- まず、 `ASIdentifierManager.shared()`を使用して、広告IDを含むオブジェクトの共有インスタンスを取得します。
- 次に、 `.advertisingIdentifier`で広告IDを取得します。
- 最後に、 `.uuidString`の広告IDのUUID文字列を取得します

例えば：

```Swift:Swift
import AdSupport
...
var idfa: String = ASIdentifierManager.shared().advertisingIdentifier.uuidString
```
ご覧のとおり、 `EA7583CD-A667-48BC-B806-42ECB2B48606`のようなサンプルIDFAのUUID文字列形式は、以前に使用したサンプルデバイスID`2077ef9a63d2b398840261c8221a0c9b`の形式とは異なります。 IDFAを変換する必要があります。
## IDFAをテストデバイスIDに変換する
Google AdMobで使用されるテストデバイスIDは、取得したIDFAのUUID文字列の__md5__ハッシュにすぎないことが分かりました。

```Swift:Swift
import CryptoKit
...
var deviceId: String = Insecure.MD5.hash(
                           data: idfa.data(using: .utf8)!
                       )
                       .map { String(format: "%02hhx", $0) }
                       .joined()
```
次に、取得したデバイスID文字列を`testDeviceIdentifiers`で使用して、現在のデバイスのテストモードを有効にすることができます。
## サンプルコード
```Swift:MyApp.swift
import SwiftUI
import AdSupport
import CryptoKit
import GoogleMobileAds

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    let persistenceController = PersistenceController.shared
    
    var body: some Scene {
        WindowGroup {
            MyAppView()
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
        }
    }
}

class AppDelegate: NSObject, UIApplicationDelegate {

  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GADMobileAds.sharedInstance().start(completionHandler: nil)
    GADMobileAds.sharedInstance().requestConfiguration.testDeviceIdentifiers = [  
      Insecure.MD5.hash(
        data: ASIdentifierManager.shared().advertisingIdentifier.uuidString.data(using: .utf8)!
      )
      .map { String(format: "%02hhx", $0) }
      .joined() 
    ];
    return true
  }
}
```

## 最後に
アプリをリリースする前に、テストモードを有効にするコードを削除することを忘れないでください！