SwiftUI集成Azure AD B2C登录遇MSAL错误,求解决方案
问题解决:SwiftUI集成Azure AD B2C登录错误及iOS15+根视图替换方案
一、解决MSAL错误(parentViewController has no window!)
错误核心原因是控制器视图未关联到window时就触发了MSAL登录请求,具体问题点:
- 重写了UIKit用于创建视图的核心方法
loadView,打乱了视图生命周期 - 在
viewDidLoad中手动调用loadView,此时控制器尚未完成视图挂载,无有效window关联
修复步骤:
- 删除自定义的
loadView方法,将登录逻辑移至viewDidAppear(此时视图已挂载到window,具备有效上下文) - 移除
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
相关产品推荐
相关产品推荐

