You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中调用OID认证方法时如何将View转为UIViewController?

解决SwiftUI视图转换为UIViewController用于OIDAuthState认证的问题

SwiftUI的View是结构体类型,和UIKit的UIViewController分属不同框架体系,直接传入MainView实例必然会出现类型不匹配错误。你需要获取当前SwiftUI视图所在的UIKit容器控制器,以下是两种可行方案:

方案一:通过UIApplication获取顶层ViewController

给UIApplication编写扩展,用来获取当前应用的顶层可见ViewController:

extension UIApplication {
    func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let navigationController = controller as? UINavigationController {
            return topViewController(controller: navigationController.visibleViewController)
        }
        if let tabController = controller as? UITabBarController {
            if let selected = tabController.selectedViewController {
                return topViewController(controller: selected)
            }
        }
        if let presented = controller?.presentedViewController {
            return topViewController(controller: presented)
        }
        return controller
    }
}

在MainView中调用该方法获取顶层VC,替换原代码中错误的vc实例:

struct MainView: View {
    var body: some View {
        // 示例:在按钮点击事件中触发认证
        Button("发起认证") {
            guard let topVC = UIApplication.shared.topViewController() else {
                print("无法获取顶层ViewController")
                return
            }
            
            // 确保request已正确初始化
            appDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request, presenting: topVC) { authState, error in
                if let authState = authState {
                    print("获取到授权令牌. Access token: \(authState.lastTokenResponse?.accessToken ?? "nil")")
                } else {
                    print("授权错误: \(error?.localizedDescription ?? "未知错误")")
                }
            }
        }
    }
}

方案二:自定义UIHostingController并传递引用

如果需要更精准控制当前视图的容器控制器,可以在App入口处自定义UIHostingController,并将其引用传递给SwiftUI视图:

  1. 在App入口(@main结构体)中保存UIHostingController引用:
@main
struct YourApp: App {
    @State private var hostingVC: UIViewController?
    
    var body: some Scene {
        WindowGroup {
            MainView(hostingVC: $hostingVC)
                .onAppear {
                    hostingVC = UIApplication.shared.topViewController()
                }
        }
    }
}
  1. 在MainView中接收引用并使用:
struct MainView: View {
    @Binding var hostingVC: UIViewController?
    
    var body: some View {
        Button("发起认证") {
            guard let vc = hostingVC else { return }
            
            appDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request, presenting: vc) { authState, error in
                if let authState = authState {
                    print("获取到授权令牌. Access token: \(authState.lastTokenResponse?.accessToken ?? "nil")")
                } else {
                    print("授权错误: \(error?.localizedDescription ?? "未知错误")")
                }
            }
        }
    }
}

关键修正点

你原代码中的let vc = MainView()是错误写法,MainView是SwiftUI视图结构体,并非UIViewController实例,必须替换为上述方案中获取的UIKit控制器实例。

内容的提问来源于stack exchange,提问作者Alexander Paul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 07:10:33