Timmy Mi
Timmy Mi

Reputation: 33

How to customize Firebase Authentication UI in Swift

I am building an authentication system using the Firebase prebuilt UI, and I want to customize the UI to fit the program. Say I want to set the background color to black and change the corner radius of the buttons, is there any way I can do this? I've tried sub-classing the authPickerViewController but somehow it didn't work. I did some searching, but couldn't find any tutorial or recent problems related to this either.

Here's what I have in my MainViewController

class LoginViewController: UIViewController, FUIAuthDelegate{

  override func viewDidLoad() {
    super.viewDidLoad()

    let authUI = FUIAuth.defaultAuthUI()
    authUI?.delegate = self
    let providers: [FUIAuthProvider] = [
      FUIEmailAuth(),
      FUIGoogleAuth(),
      FUIPhoneAuth(authUI:FUIAuth.defaultAuthUI()!)]
    authUI?.providers = providers

    let authViewController = authUI?.authViewController()
    authViewController!.modalPresentationStyle = .fullScreen
    authViewController!.setNavigationBarHidden(true, animated: false)

    self.present(authViewController!, animated: false, completion: nil)
  }

  func application(_ app: UIApplication, open url: URL,
    options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
    let sourceApplication = options[UIApplicationOpenURLOptionsKey.sourceApplication]
    if FUIAuth.defaultAuthUI()?.handleOpen(url, sourceApplication: sourceApplication as? String) ?? false {
      return true
    }
    return false
  }
}

And here is the subclass I created:

class FUICustomAuthPickerViewController: FUIAuthPickerViewController,FUIAuthDelegate {

  override func viewDidLoad() {
    super.viewDidLoad()

    self.view.backgroundColor = .black
  }

  func authPickerViewController(forAuthUI authUI: FUIAuth) -> FUIAuthPickerViewController {
    return FUICustomAuthPickerViewController(nibName: "FUICustomAuthPickerViewController",
      bundle: Bundle.main,
      authUI: authUI)
  }
}

On the Firebase documentation for customization, they say that:

You can customize the sign-in screens by subclassing FirebaseUI's view controllers and specifying them in FUIAuth's delegate methods.

I am a beginner, how can I do that?

Edited:

So by following the instructions on this link I managed to add stuff to the pre-built UI by creating an extension to the FUIAuthDelegate.

extension LoginViewController:FUIAuthDelegate {
  func application(_ app: UIApplication, open url: URL,
    options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
    let sourceApplication = options[UIApplicationOpenURLOptionsKey.sourceApplication]
    if FUIAuth.defaultAuthUI()?.handleOpen(url, sourceApplication: sourceApplication as? String) ?? false {
      return true
    }
    return false
  }

  func authPickerViewController(forAuthUI authUI: FUIAuth) -> FUIAuthPickerViewController {
    let vc = FUIAuthPickerViewController(authUI: authUI)

    let view = UIView(frame: .zero)
    view.backgroundColor = .black
    view.translatesAutoresizingMaskIntoConstraints = false
    vc.view.addSubview(view)

    NSLayoutConstraint.activate([
      view.heightAnchor.constraint(equalTo: vc.view.heightAnchor, multiplier: 1),
      view.widthAnchor.constraint(equalTo: vc.view.widthAnchor, multiplier: 1)])

    return vc
  }
}

Turns out subclass is not necessarily needed. However, I can't seem to make this view I created to be the background, it either covers everything or nothing at all.I tried changing the background color of the view directly, didn't work. Anyone knows how to do this?

Upvotes: 1

Views: 1505

Answers (1)

Timmy Mi
Timmy Mi

Reputation: 33

Solved the problem using the method and one of the comments provided in this link. Turns out, apart from subclassing, you have to add the following two methods to your subclass for it to work.

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?, authUI: FUIAuth?) {
        super.init(nibName: nil, bundle: Bundle.main, authUI: authUI!)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

However, the approach I used (not sure if other approaches raise the same problem) also caused another problem - the email sign-in button stopped responding - which is addressed in this link by presenting the view controller with a navigationViewController because the email sign-in button works together with the navigation bar, you can get rid of it once you have presented the view with a navigationViewController.

Now the complete subclass looks like this:

import UIKit
import FirebaseUI

class FUICustomAuthPickerViewController: FUIAuthPickerViewController {

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?, authUI: FUIAuth?) {
        super.init(nibName: nil, bundle: Bundle.main, authUI: authUI!)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let width = UIScreen.main.bounds.size.width
        let height = UIScreen.main.bounds.size.height

        let imageViewBackground = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
        imageViewBackground.backgroundColor = .eatstrOrange

        view.insertSubview(imageViewBackground, at: 0)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHidden(true, animated: animated)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.setNavigationBarHidden(false, animated: animated)
    }
}

And here's the main view controller:

import UIKit
import FirebaseUI

class LoginViewController: UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()

        let authUI = FUIAuth.defaultAuthUI()
        let delegate = authUI?.delegate
        authUI?.delegate = delegate
        let providers: [FUIAuthProvider] = [
          FUIGoogleAuth(),
          FUIEmailAuth(),
          FUIPhoneAuth(authUI:FUIAuth.defaultAuthUI()!)]
        authUI?.providers = providers

        let authViewController = FUICustomAuthPickerViewController(authUI: authUI!)
        authViewController.modalPresentationStyle = .fullScreen
        navigationController?.pushViewController(authViewController, animated: false)
    }
}

Final outcome

Upvotes: 2

Related Questions