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

SwiftUI集成Azure AD B2C登录遇MSAL错误,求解决方案

问题解决:SwiftUI集成Azure AD B2C登录错误及iOS15+根视图替换方案

一、解决MSAL错误(parentViewController has no window!)

错误核心原因是控制器视图未关联到window时就触发了MSAL登录请求,具体问题点:

  • 重写了UIKit用于创建视图的核心方法loadView,打乱了视图生命周期
  • 在viewDidLoad中手动调用loadView,此时控制器尚未完成视图挂载,无有效window关联

修复步骤:

  1. 删除自定义的loadView方法,将登录逻辑移至viewDidAppear(此时视图已挂载到window,具备有效上下文)
  2. 移除viewDidLoad内的loadView()调用

二、iOS15+替换根视图方案(替代废弃的windows)

iOS15起UIApplication.shared.windows被废弃,需通过UIWindowScene获取活跃场景,再修改其根控制器:

if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
   let window = scene.windows.first(where: { $0.isKeyWindow }) {
    window.rootViewController = UIHostingController(rootView: MainContentView())
}

注:将登录后的目标视图命名为MainContentView,避免与原ContentView形成循环引用(原ContentView包含登录视图,登录成功需跳转至新主视图)

修改后的完整代码

1. LoginViewController

class LoginViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 移除手动调用的loadView()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        startLoginFlow()
    }

    private func startLoginFlow() {
        do {
            let authority = try MSALB2CAuthority(url: URL(string: "https://Kauthority/b2c_1_susi")!)
            let pcaConfig = MSALPublicClientApplicationConfig(
                clientId: "MyClientID",
                redirectUri: nil,
                authority: authority
            )
            pcaConfig.knownAuthorities = [authority]
            let application = try MSALPublicClientApplication(configuration: pcaConfig)
            
            let webViewParameters = MSALWebviewParameters(authPresentationViewController: self)
            let interactiveParameters = MSALInteractiveTokenParameters(
                scopes: ["user.read"],
                webviewParameters: webViewParameters
            )

            application.acquireToken(with: interactiveParameters) { result, error in
                guard let result = result else {
                    print(error!)
                    return
                }

                if result.account.identifier != nil {
                    // iOS15+ 替换根视图
                    if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
                       let window = scene.windows.first(where: { $0.isKeyWindow }) {
                        window.rootViewController = UIHostingController(rootView: MainContentView())
                    }
                }
            }
        } catch {
            print(error)
        }
    }
}

2. 登录后主视图

struct MainContentView: View {
    var body: some View {
        Text("登录成功,欢迎进入主界面")
            .font(.largeTitle)
    }
}

3. 原ContentView与UIViewControllerRepresentable

struct LoginUIViewRepresentable: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> LoginViewController {
        LoginViewController()
    }

    func updateUIViewController(_: LoginViewController, context _: Context) {}
}

struct ContentView: View {
    var body: some View {
        LoginUIViewRepresentable()
    }
}

内容的提问来源于stack exchange,提问作者David Harinson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 09:36:21