【SwiftUI】アプリ起動広告の表示方法

第0部: [スタートガイド](https://qiita.com/SNQ-2001/items/44f3446ce0966c78641b)

第1部: [リワード広告](https://qiita.com/SNQ-2001/items/253173abefc6f90f86ea)
第2部: [インタースティシャル広告](https://qiita.com/SNQ-2001/items/5590a55324c39582a9ef)
第3部: [ネイティブ広告](https://qiita.com/SNQ-2001/items/7151fdcb8e9f8c2c42c2)
第4部: [バナー広告](https://qiita.com/SNQ-2001/items/9bf389475cb5995469a0)
第5部: [アプリ起動広告](https://qiita.com/SNQ-2001/items/75ce24982bf418c52349) ← イマココ

# はじめに
AdMob広告シリーズ第5部です
今回は[アプリ起動広告](https://developers.google.com/admob/ios/app-open)です。

アプリ起動広告は公式のドキュメントにSwiftでの実装方法が記載されていない(Objective-Cのみ)のでおそらく優先度がかなり低い広告ユニットなんだと思われます。

広告の見た目はこのような感じです。
![simulator_screenshot_64872B5E-B9C2-4B84-BC4F-F07B6CD335E5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/2797ed48-55ff-a271-39e2-e1e5dfd3dba2.png)

# 実装準備
実装の前に[スタートガイド](https://developers.google.com/admob/ios/quick-start?hl=ja)に記載してある事を行います

①: Mobile Ads SDK のインポート
②: Info.plist の更新
③: Mobile Ads SDK の初期化

[こちら](https://qiita.com/SNQ-2001/items/44f3446ce0966c78641b)で詳しく解説してあります。
これが終われば準備は完了です。

# 実装
```AppOpen.swift
import GoogleMobileAds

class AppOpen: NSObject, GADFullScreenContentDelegate, ObservableObject {

    @Published var appOpenAdLoaded: Bool = false
    var appOpenAd: GADAppOpenAd?

    override init() {
        super.init()
        loadAppOpenAd()
    }

    func loadAppOpenAd() {
        let request = GADRequest()
        GADAppOpenAd.load(
            withAdUnitID: "ca-app-pub-3940256099942544/5662855259",
            request: request,
            orientation: UIInterfaceOrientation.portrait
        ) { appOpenAdIn, _ in
            self.appOpenAd = appOpenAdIn
            self.appOpenAd?.fullScreenContentDelegate = self
            self.appOpenAdLoaded = true
            print("🍊: 準備完了しました")
        }
    }

    func presentAppOpenAd() {
        guard let root = self.appOpenAd else { return }
        root.present(fromRootViewController: (UIApplication.shared.windows.first?.rootViewController)!)
    }

    func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
        self.loadAppOpenAd()
        print("😭: エラー -> \(error)")
    }

    func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
        self.loadAppOpenAd()
        print("🍅: 閉じました")
    }
}
```

```AdMob_AppOpen_DemoApp.swift
import SwiftUI
import GoogleMobileAds

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
    ) -> Bool {
        GADMobileAds.sharedInstance().start(completionHandler: nil)
        return true
    }
}

@main
struct AdMob_AppOpen_DemoApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    @StateObject var appOpen = AppOpen()
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: appOpen.appOpenAdLoaded) { newValue in
            appOpen.presentAppOpenAd()
        }
    }
}
```
![appopen.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/baec517e-13d7-9605-d25c-60fe7bc1507b.gif)


# 解説
今までの広告表示形式とちょっと違うので軽く解説します。

アプリが起動してすぐ広告を読み込みます
```swift
override init() {
    super.init()
    loadAppOpenAd()
}
```
読み込みが完了したら`appOpenAdLoaded`というフラグを`true`に変更します
```swift
func loadAppOpenAd() {
    let request = GADRequest()
    GADAppOpenAd.load(
        withAdUnitID: "ca-app-pub-3940256099942544/5662855259",
        request: request,
        orientation: UIInterfaceOrientation.portrait
    ) { appOpenAdIn, _ in
        self.appOpenAd = appOpenAdIn
        self.appOpenAd?.fullScreenContentDelegate = self
        self.appOpenAdLoaded = true
        print("🍊: 準備完了しました")
    }
}
```
`XXXApp.swift`の方で`onChange`を使用して変更が検知されたら`presentAppOpenAd()`が実行されます
```swift
WindowGroup {
    ContentView()
}
.onChange(of: appOpen.appOpenAdLoaded) { newValue in
    appOpen.presentAppOpenAd()
}
```

# おわり
今回の完成サンプルです。
参考にしてください

https://github.com/SNQ-2001/AdMob-AppOpen-Demo