LoginSignup
2

More than 1 year has passed since last update.

SwiftUI 環境で表示中のUIViewControllerを取得する

概要

SwiftUIのプロジェクトで、現在フロントにあるUIViewControllerを手軽に取得する方法についてのTips

SwiftUIとUIKitの連携

SwiftUIのViewとUIKit間での連携は

  • UIHostingController
  • UIViewRepresentable

を使った方法がある。

ただ、SwiftUIのプロジェクトで外部ライブラリなど使用する場合に

いま提示している「UIViewController」を渡すことが必要になるケースがある。

例えば、Googleの「UserMessagingPlatform」を使って

ATT事前許諾プロンプトを提示する際に

SwiftUIのコンテキスト上からライブラリ側にUIViewControllerを渡す必要がある。

方法は他にも色々ありそうだが、その時の対応メモ。

現在のUIViewControllerを探す

表示中のUIViewControllerを探す流れは

まず

  1. UIApplicationから接続中のUISceneたちを取得
  2. 前面にあるアクティブなSceneをフィルタ
  3. SceneからUIWindowSceneを探す
  4. UIWindowSceneが持つUIWindowからKeyWindowを探す
  5. Windowから rootViewController or そこから生えているpresentedViewControllerを見つける

なお、ここで実際に取得できるのは

UIHostingController<SomeOneView>

となり

これを任意のライブラリなりに渡せば良い。

検証

// 1
let scenes = UIApplication.shared.connectedScenes
debugPrint(scenes)

// 2
let active_scenes = scenes.filter({$0.activationState == .foregroundActive})
debugPrint(active_scenes)

// 3
let window_scenes = active_scenes.map({$0 as? UIWindowScene})
debugPrint(window_scenes)

// 4
let windows = window_scenes.compactMap({$0}).first?.windows
debugPrint(windows)
let first_keywindow = windows?.filter({$0.isKeyWindow}).first
debugPrint(first_keywindow)

// 5
let vc = first_keywindow?.rootViewController
if let _vc = vc?.presentedViewController {
    debugPrint(String(describing: type(of: vc!)))
}else{
    debugPrint(String(describing: type(of: _vc)))
}

// UIHostingController<ContextView>

上をまとめたもの

例えば、UIViewControllerにExtensionで追加して


extension UIViewController {
    static func getFrontViewController() -> UIViewController? {
        let keyWindow = UIApplication.shared.connectedScenes
            .filter({$0.activationState == .foregroundActive})
            .map({$0 as? UIWindowScene})
            .compactMap({$0})
            .first?.windows
            .filter({$0.isKeyWindow}).first

        let vc = keyWindow?.rootViewController
        guard let _vc = vc?.presentedViewController else {
            return vc
        }
        return _vc
    }
}
guard let vc = UIViewController.getFrontViewController() else {
    return
}

// vc

みたいに使用したり。

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
What you can do with signing up
2