Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase google signin authentication AppDelegate- Use of unresolved identifier 'isMFAEnabled'

I'm new to iOS development. I am trying to add google sign in to my app but i am facing an some problems.Code shows some "Use of unresolved identifier 'isMFAEnabled"and "Value of type 'AppDelegate' has no member 'showTextInputPrompt'".Please help me.I'm following this doc- https://firebase.google.com/docs/auth/ios/google-signin#swift_9 enter image description here

import UIKit
import Firebase
import GoogleSignIn

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,GIDSignInDelegate {
   
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
        GIDSignIn.sharedInstance().delegate = self
        return true
    }

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        return GIDSignIn.sharedInstance().handle(url)
    }
    func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
           if let error = error {
            print(error.localizedDescription)
             return
           }

           guard let authentication = user.authentication else { return }
           let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
                                                             accessToken: authentication.accessToken)
          Auth.auth().signIn(with: credential) { (authResult, error) in
            if let error = error {
              let authError = error as NSError
              if (isMFAEnabled && authError.code == AuthErrorCode.secondFactorRequired.rawValue) {
                // The user is a multi-factor user. Second factor challenge is required.
                let resolver = authError.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver
                var displayNameString = ""
                for tmpFactorInfo in (resolver.hints) {
                  displayNameString += tmpFactorInfo.displayName ?? ""
                  displayNameString += " "
                }
                self.showTextInputPrompt(withMessage: "Select factor to sign in\n\(displayNameString)", completionBlock: { userPressedOK, displayName in
                  var selectedHint: PhoneMultiFactorInfo?
                  for tmpFactorInfo in resolver.hints {
                    if (displayName == tmpFactorInfo.displayName) {
                      selectedHint = tmpFactorInfo as? PhoneMultiFactorInfo
                    }
                  }
                  PhoneAuthProvider.provider().verifyPhoneNumber(with: selectedHint!, uiDelegate: nil, multiFactorSession: resolver.session) { verificationID, error in
                    if error != nil {
                      print("Multi factor start sign in failed. Error: \(error.debugDescription)")
                    } else {
                      self.showTextInputPrompt(withMessage: "Verification code for \(selectedHint?.displayName ?? "")", completionBlock: { userPressedOK, verificationCode in
                        let credential: PhoneAuthCredential? = PhoneAuthProvider.provider().credential(withVerificationID: verificationID!, verificationCode: verificationCode!)
                        let assertion: MultiFactorAssertion? = PhoneMultiFactorGenerator.assertion(with: credential!)
                        resolver.resolveSignIn(with: assertion!) { authResult, error in
                          if error != nil {
                            print("Multi factor finanlize sign in failed. Error: \(error.debugDescription)")
                          } else {
                            self.navigationController?.popViewController(animated: true)
                          }
                        }
                      })
                    }
                  }
                })
              } else {
                print(error.localizedDescription)
                return
              }
              // ...
              return
            }
            // User is signed in
            // ...
          }
       }
    
    func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
          let firebaseAuth = Auth.auth()
        do {
          try firebaseAuth.signOut()
        } catch let signOutError as NSError {
          print ("Error signing out: %@", signOutError)
        }
like image 712
Gleny Rebellow Avatar asked Jun 28 '20 15:06

Gleny Rebellow


2 Answers

So the boilerplate is wayyyy more code than you need. This is my review of your AppDelegate.

  1. didFinishLaunchingWithOptions looks good as-is. Pro tip: add this line for staying logged in GIDSignIn.sharedInstance()?.restorePreviousSignIn()

  2. open,options looks good as-is.

  3. didSignInFor user is where it gets tangled. Delete the entire function and replace it with the following extension (outside the class' brackets):

(also delete GIDSignInDelegate in the class protocols)

    extension AppDelegate: GIDSignInDelegate {
    func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
        
        //handle sign-in errors
        if let error = error {
            if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue {
                print("The user has not signed in before or they have since signed out.")
            } else {
            print("error signing into Google \(error.localizedDescription)")
            }
        return
        }
        
        // Get credential object using Google ID token and Google access token
        guard let authentication = user.authentication else { return }
        
        let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
                                                        accessToken: authentication.accessToken)
        
        // Authenticate with Firebase using the credential object
        Auth.auth().signIn(with: credential) { (authResult, error) in
            if let error = error {
                print("authentication error \(error.localizedDescription)")
            }
        }
    } 
}

I have tested this in today and it's currently working (Swift 5/ios 13.6).

like image 69
eyesplice17 Avatar answered Nov 09 '22 07:11

eyesplice17


TL;DR; you can just delete that variable if you don't want to enable multi-factor authentication.

The Firebase documentation provides the variable as a way for you to enable/disable multi-factor (MF) authentication (i.e. when facebook sends you a text message for you to verify). It's more like they are giving you an incomplete template that doesn't compile unless you declare and set this variable (among other things like implementing showTextInputPrompt).

The code provided in firebase documentation is an example, so don't expect it to work out of the box.

like image 5
Stephen Lee Avatar answered Nov 09 '22 08:11

Stephen Lee