SwiftUIでAdMob対応（バナー編）


# 要約

UIViewControllerRepresentableを使ってSwiftUIでいい感じにバナーを含んだ画面を表示します。

# はじめに
SwiftUIでAdMobのバナーが表示したかったので、実装してみました。
AdMobの導入が済んでいる事が前提となります。
https://developers.google.com/admob/ios/quick-start?hl=ja


# 結果
こんな感じでプレビューでバナーが表示できました。

![スクリーンショット 2021-03-25 16.35.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62305/ebd65cc7-7d4a-de88-a6dc-381165fd3265.png)

# Repository

https://github.com/coe/SwiftUIAdMob

# 概要

SwiftUIでAdMob対応をします。
手始めにバナーを表示します。

## Life Cycle SwiftUI App対応
リポジトリではプロジェクトはSwiftUI Appでのプロジェクトになります。
AdMobはAppDelegateで`GADMobileAds.sharedInstance().start(completionHandler: nil)`の初期化を行う必要があるので、ひと手間必要です。

AppDelegateを作成し、プロジェクトのAppに`UIApplicationDelegateAdaptor`を追加して、AppDelegate内で初期化するようにします。

```swift
@main
struct SwiftUIAdMobApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
```

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

## UIViewControllerRepresentableで広告表示用UIViewControllerを作成
AdMobのバナーには、広告の処理を行うためのフルスクリーンなrootViewControllerが必要です。
SwiftUI単体ではUIViewControllerを用意することができないため、これをUIViewControllerRepresentable経由で用意します。

ContainedAdViewControllerでUIViewControllerRepresentableに適合する処理を書きます。
`makeUIViewController`で提供するUIViewControllerはStoryboardで用意しました。

```swift
struct ContainedAdViewController<Content: View>: UIViewControllerRepresentable {
    let rootView: Content

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func makeUIViewController(context: Context) -> UIViewController {
        let adViewController: AdViewController = UIStoryboard(name: "AdViewController", bundle: nil).instantiateInitialViewController()!
        adViewController.rootView = AnyView(rootView)
        return adViewController
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        
    }
    
    typealias UIViewControllerType = UIViewController
    
    class Coordinator: NSObject {
        var parent: ContainedAdViewController
        
        init(_ containedAdViewController: ContainedAdViewController) {
            parent = containedAdViewController
        }
    }
}

```

Storyboardの初期表示はAdViewControllerというUIViewController継承クラスで、その内部ではSwiftUIを表示するUIHostingControllerコンテナとその下で表示を行うバナーを格納しています。
広告バナーに対するrootViewControllerはAdViewControllerになります。

![スクリーンショット 2021-03-25 16.53.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62305/bb0412d2-381f-8781-59c5-729768e78817.png)

## SwiftUI側の表示
SwiftUI側はContainedAdViewControllerのrootViewに表示したいViewを実装すればOKです。

```swift
struct ContentView: View {
    var body: some View {
        ContainedAdViewController(rootView:
                                    Text("Hello, world!").padding()
        )
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

```

# 動作

表示できました。
![Simulator Screen Shot - iPod touch (7th generation) - 2021-03-25 at 16.56.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62305/d6dd34dc-ce81-bedf-5912-14b94d49b8d8.png)

上記のRepositoryのコードはSceneもサポートしているので、複数画面でもばっちりアダプティブ広告が表示できます。
![Simulator Screen Shot - iPad Pro (12.9-inch) (4th generation) - 2021-03-25 at 16.40.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62305/a5406fe9-ba87-7108-af73-a26915925226.png)