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

UIAlertController约束异常求助:FirebaseAuth手机号验证后界面问题

Fixing UIAlertController Constraint Issues After Firebase Recaptcha Verification

Hey David, I’ve run into this exact issue with Firebase Phone Auth and UIAlertController before—here’s what’s going on and how to fix it:

What’s Causing the Constraint Mess?

UIAlertController isn’t a regular view controller—it’s managed by the system in a special, opaque way under the hood. When you present Firebase’s Recaptcha verification view controller, it modifies the app’s view hierarchy in ways that break the system’s internal layout constraints for the already-presented alert. When you dismiss the Recaptcha VC, the alert’s constraints don’t properly reset, leading to that messed-up layout you’re seeing.

1. Use a Custom Verification Popup (Best Long-Term Fix)

Instead of relying on UIAlertController, build a custom view controller for your code input. This gives you full control over layout and avoids system-related constraint bugs entirely. Here’s a quick, production-ready example:

Custom Verification Code View Controller

class VerificationCodeVC: UIViewController {
    // UI Elements
    private let codeTextField = UITextField()
    private let confirmButton = UIButton(type: .system)
    private let cancelButton = UIButton(type: .system)
    
    // Callback and data
    var verificationId: String?
    var onVerificationComplete: ((String) -> Void)?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupView()
        setupLayout()
        setupActions()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        preferredContentSize = CGSize(width: 320, height: 190)
        codeTextField.becomeFirstResponder() // Auto-focus on input
    }
    
    private func setupView() {
        view.backgroundColor = .systemBackground
        view.layer.cornerRadius = 16
        view.clipsToBounds = true
    }
    
    private func setupLayout() {
        // Disable autoresizing masks
        [codeTextField, confirmButton, cancelButton].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)
        }
        
        // Configure text field
        codeTextField.placeholder = "Verification code"
        codeTextField.borderStyle = .roundedRect
        codeTextField.keyboardType = .numberPad
        
        // Configure buttons
        confirmButton.setTitle("Ok", for: .normal)
        cancelButton.setTitle("Cancel", for: .normal)
        cancelButton.tintColor = .systemRed
        
        // Add constraints
        NSLayoutConstraint.activate([
            codeTextField.topAnchor.constraint(equalTo: view.topAnchor, constant: 24),
            codeTextField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            codeTextField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            
            confirmButton.topAnchor.constraint(equalTo: codeTextField.bottomAnchor, constant: 20),
            confirmButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            
            cancelButton.topAnchor.constraint(equalTo: codeTextField.bottomAnchor, constant: 20),
            cancelButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            
            view.bottomAnchor.constraint(equalTo: confirmButton.bottomAnchor, constant: 20)
        ])
    }
    
    private func setupActions() {
        confirmButton.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside)
        cancelButton.addTarget(self, action: #selector(cancelTapped), for: .touchUpInside)
    }
    
    @objc private func confirmTapped() {
        guard let code = codeTextField.text, !code.isEmpty else { return }
        onVerificationComplete?(code)
        dismiss(animated: true)
    }
    
    @objc private func cancelTapped() {
        dismiss(animated: true)
    }
}

Update Your Verification Method

Replace your showVerificationAlert() with this:

func showVerificationPopup() {
    let verificationVC = VerificationCodeVC()
    verificationVC.verificationId = self.verificationId
    verificationVC.modalPresentationStyle = .automatic // Uses sheet style on iOS 13+
    verificationVC.onVerificationComplete = { [weak self] code in
        guard let self = self, let verificationId = self.verificationId else { return }
        
        let credential = PhoneAuthProvider.provider().credential(
            withVerificationID: verificationId,
            verificationCode: code
        )
        
        Auth.auth().signIn(with: credential) { user, error in
            if let error = error {
                debugPrint(error)
                return
            }
            print("userSignedIn")
            self.animateFromRight(viewControllerToPush: MainScreenVC())
        }
    }
    present(verificationVC, animated: true)
}

2. Quick Fix: Re-Present the Alert After Recaptcha Dismissal

If you want to stick with UIAlertController for now, you can dismiss the existing alert before presenting the Recaptcha VC, then re-show the alert once you’re back:

  • Before launching the Recaptcha flow, dismiss your verification alert (save any necessary state).
  • After the Recaptcha flow completes, call showVerificationAlert() again to re-present the code input.

Note: This can feel a bit jarring to users, so the custom popup is a smoother, more reliable experience long-term.

Why This Works

Custom view controllers avoid the system’s opaque handling of UIAlertController layout. You control every constraint, so there’s no risk of third-party SDKs like Firebase Recaptcha breaking the layout when modifying the app’s view hierarchy.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:46:33