5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[SwiftUI] UIViewController を引数に取る関数を使う方法

Last updated at Posted at 2023-10-06

概要

実行時に UIViewController を必要とする関数は少なくありません。

  • GoogleSignIn ライブラリの GIDSignIn.sharedInstance.signIn(with: , presenting: )
  • AdMob のインタースティシャル広告表示時の GADInterstitialAd.present(fromRootViewController: )

UIViewController が表立って使うことがない SwiftUI において、それらの関数を実行する際に UIApplication.shared.windows.first?.rootViewController を使う方法を紹介している記事が数多くあります。

しかし、これはあまり安全とは言えません。

今回は、UIApplication.shared.windows.first?.rootViewController を使わずにこれらの関数を使用する方法を紹介したいと思います。

参考記事

ざっくりとした流れ

ちょっとトリッキーですが、やり方はそこそこシンプルです

  1. 空の UIViewControllerUIViewControllerRepresentable でラップした View を作成
  2. SwiftUI の View に、前述の View を初期化した変数 (仮に anchorView とする) を追加
  3. body 内で、.background に前述の変数を設置
  4. UIViewController を必要とする関数に、anchorView.viewController を渡す

実際に書いてみる

  • ここでは、例として AdMob のインタースティシャル広告を表示するコードを書いてみたいと思います。
  1. 空の UIViewController をラップした RepresentedEmptyViewController を作成

    import SwiftUI
    
    // MARK: - 空の `UIViewController` をラップしたもの
    struct RepresentedEmptyViewController: UIViewControllerRepresentable {
        let viewController: UIViewController = .init()
    
        func makeUIViewController(context: Context) -> some UIViewController {
            return self.viewController
        }
    
        func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        }
    }
    
  2. UIViewController を必要とする関数を実行する View に、前述の RepresentedEmptyViewController を初期化した変数を追加

    import SwiftUI
    
    struct ContentView: View {
        // これ↓
        let prensentationAnchorView: RepresentedEmptyViewController = .init()
    
        var body: some View {
        // 中略
        }
    }
    
  3. body 内のルートのビューに、.background モディファイアを付与し、前述の prensentationAnchorView を設置

    • background に設置することで、UIへの影響なく設置できます
    import SwiftUI
    
    struct ContentView: View {
        let prensentationAnchorView: RepresentedEmptyViewController = .init()
    
        var body: some View {
            VStack {
                
            }
            // これ↓
            .background {
                prensentationAnchorView
            }
        }
    }
    
  4. UIViewController を必要とする関数を使う処理を書く (ここでは GADInterstitialAd.present(fromRootViewController: ))

    import SwiftUI
    import GoogleMobileAds
    
    struct ContentView: View {
        @State var interstitialAdObject: GADInterstitialAd? = nil
    
        let prensentationAnchorView: RepresentedEmptyViewController = .init()
    
        func loadAd() async {
            do {
                self.interstitialAdObject = try await GADInterstitialAd.load(withAdUnitID: "ユニットID", request: GADRequest())
            } catch {
                print(error)
            }
        }
    
        func showInterstitialAd() {
            self.interstitialAdObject.present(fromRootViewController: prensentationAnchorView.viewController)
        }
    
        var body: some View {
            VStack {
                Button(action: showInterstitialAd) {
                    Text("広告を表示")
                }
            }
            .task {
                await loadAd()
            }
            .background {
                prensentationAnchorView
            }
        }
    }
    

こうすることで、Button 押下時にインタースティシャル広告が表示されるようになります。

presentationAnchorView を起点として、モーダルが表示されるイメージですね。

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?