SwiftUI 2.0: How to programmatically setup an iOS device as a test device for adMob

## The problem

To avoid violating Google AdMob’s [invalid traffic policy](https://support.google.com/admob/answer/3342054) when testing an iOS application, you can use [demo ads](https://developers.google.com/admob/ios/test-ads#demo_ad_units) or [test devices](https://developers.google.com/admob/ios/test-ads#add_your_test_device_in_the_admob_ui) to verify your implementation code.

Another way to achieve the check your code is to programmatically setup the iOS device as a test device for adMob at the start of your iOS app ...
## Enabling Google AdMob's test mode
### [Demo ad units](https://developers.google.com/admob/ios/test-ads#demo_ad_units)
Use the Demo ad unit ID corresponding to the Ad format you want to display in your app.

For example, for a banner ad, the id listed in the [Demo ad units list](https://developers.google.com/admob/ios/test-ads#demo_ad_units) is `ca-app-pub-3940256099942544/2934735716`
### [Add your test device in the AdMob UI](https://support.google.com/admob/answer/9691433)
To automatically enable a device test mode, you can also use the [AdMob UI](https://apps.admob.com/v2/home).

- In the menu on the left, select the [`Settings`](https://apps.admob.com/v2/settings/personal-settings) item.
- Then, select the [`Test Devices`](https://apps.admob.com/v2/settings/test-devices/list) tab, at the top of the page.
- Click on the `Add test device` button.
- Finally, add the device to the list by filling the form and clicking `Save`.

※ The device's IDFA is necessary to add this device to the test device list.
### [Add your test device programmatically](https://developers.google.com/admob/ios/test-ads#add_your_test_device_programmatically)
Sometimes, you don't know the device's IDFA, in this case enabling the device test mode programmatically is a useful option.

To set a device or a list of devices as test devices:

- First, get the Google Mobile Ads SDK settings shared instance with `GADMobileAds.sharedInstance()`.
- Then, get the request configuration common to all requests with `.requestConfiguration`.
- Finally, assign a list of identifiers _for the devices you want to use in test mode_ to the list of identifiers _corresponding to test devices which will always request test ads_ returned by `.testDeviceIdentifiers`

Like that:

```Swift:Swift
import GoogleMobileAds
...
GADMobileAds.sharedInstance().requestConfiguration.testDeviceIdentifiers =
    [ "2077ef9a63d2b398840261c8221a0c9b" ] // Sample device ID
```
※ The test device identifier for the current device is logged to the console when the first ad request is made.

But how to get the test device identifiers?
## Get the test device IDFA
An IDFA is simply an Identifier for Advertising for a device issued by iOS to be used by advertisers to uniquely identify a device.

To get a device IDFA:

- First, get the shared instance of the object that contains the advertising identifier with `ASIdentifierManager.shared()`.
- Then, get the advertising identifier with `.advertisingIdentifier`.
- Finally, get the advertising identifier's UUID string returned by `.uuidString`

Like that:

```Swift:Swift
import AdSupport
...
var idfa: String = ASIdentifierManager.shared().advertisingIdentifier.uuidString
```
As you can see the UUID string format of a sample IDFA like `EA7583CD-A667-48BC-B806-42ECB2B48606` is different from the format of the sample device ID `2077ef9a63d2b398840261c8221a0c9b` we used previously. We will have to convert the IDFA.
## Converting an IDFA into a test device identifier
It turns out that the test device ID used by Google AdMob is simply a __md5__ hash of the IDFA UUID string we just acquired:

```Swift:Swift
import CryptoKit
...
var deviceId: String = Insecure.MD5.hash(
                           data: idfa.data(using: .utf8)!
                       )
                       .map { String(format: "%02hhx", $0) }
                       .joined()
```
Then you can use the resulting device ID string in the `testDeviceIdentifiers` to enable the current device's test mode.
## Complete Code
```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
  }
}
```

## Last words
Don't forget to remove the code enabling the test mode before releasing your app!