Search code examples
swiftfacebookparse-platformswift3

Integrating Facebook Login with Parse Swift 3


In my Xcode Project I already have a sign in feature that uses a user's username and password they created. Now I want to integrate a Facebook login in the project, but I am not completely sure how to do this. When someone makes an account through they way I have it now, they make and save a username and a password which can then be used in with PFUser.logIn(withUsername: ..., password: ...) for whenever they want to sign in again.

But with Facebook, I do not know what unique identifier I am suppose to save their account with. I know there is a Facebook id that I can extract, but how do I login the user in after I get this? Like I said before I currently use PFUser.logIn(withUsername: ..., password: ...) to log the users' in then I just use PFUser.current()?.username to get all data related to that user. I heard that I am suppose to use PFFacebookUtils.logInInBackground for this, but I already tried implementing it but when I press the "Continue with Facebook button", the app crashes (I screenshot error and placed it at bottom). I have copied my code of what I have so far. How do I integrate a signup with Facebook feature that will allow me to save a users Facebook id and what method do I use to sign the user in (i.e. PFFacebookUtils.logInInBackground)? Here's my code so far:

@IBOutlet var facebookSignUpButton: FBSDKLoginButton!
    var fullnameFB = String()
    var idFB = String()
    var emailFB = String()
    var isFBSignUp = Bool()

    override func viewDidLoad() {
        super.viewDidLoad()

        signUpWithFacebook()
    }
    func signUpWithFacebook() {
        facebookSignUpButton.readPermissions = ["email", "public_profile"]
        facebookSignUpButton.delegate = self
        self.view.addSubview(facebookSignUpButton)

    }
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
        if error != nil { //if theres an error
            print(error)
        } else if result.isCancelled { // if user cancels the sign up request
            print("user cancelled login")
        } else {
            PFFacebookUtils.logInInBackground(with: result!.token!) { (user, error) in
                if error == nil {

                if let user = user {

                    if user.isNew {
                        print("User signed up and logged in through Facebook!")
                    } else {
                        print("User logged in through Facebook!")
                    }

                    if result.grantedPermissions.contains("email") {
                        if let graphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "email, name"]) {
                            graphRequest.start(completionHandler: { (connection, result, error) in
                                if error != nil {
                                    print(error?.localizedDescription ?? String())
                                } else {
                                    if let userDetails = result as? [String: String]{
                                        print(userDetails)
                                        self.fullnameFB = userDetails["name"]!
                                        self.idFB = userDetails["id"]!
                                        self.emailFB = userDetails["email"]!
                                        self.isFBSignUp = true
                                    }
                                }
                            })
                        }
                    } else {
                        print("didnt get email")
                        self.createAlert(title: "Facebook Sign Up", message: "To signup with Facebook, we need your email address")
                    }

                } else {
                    print("Error while trying to login using Facebook: \(error?.localizedDescription ?? "---")")
                }
                } else {
                    print(error?.localizedDescription ?? String())
                }
            }
        }
    }

Console output:

2017-08-12 14:14:33.223472-0700 Project[2423:1001235] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'You must initialize PFFacebookUtils with a call to +initializeFacebookWithApplicationLaunchOptions'

*** First throw call stack: (0x188042fe0 0x186aa4538 0x188042f28 0x100b8f934 0x100b90020 0x100b9032c 0x10019eee8 0x1001a0a64 0x100867598 0x10086e998 0x10086e4f0 0x100871a94 0x18b3610d4 0x101521a10 0x101526b78 0x187ff10c8 0x187feece4 0x187f1eda4 0x189989074 0x18e1dd364 0x1001ec288 0x186f2d59c) libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)


Solution

  • As stated in the docs, you need to initialize PFFacebookUtils before using it, like so:

    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
    
        // CODE...
    
        PFFacebookUtils.initializeFacebook(applicationLaunchOptions: launchOptions)
    }
    

    Important: Must be done after Parse setup (Parse.initialize...).