Parse: Facebook login not creating new PFUser

965 Views Asked by At

I've been trying to integrate Facebook login and Parse, so that a new PFUser is created upon logging in. I have created a Facebook login button, and when I press it the standard Facebook login/asking for permissions screen appears. When I accept the login I am redirected back to the initial screen, and the log shows that the user has cancelled the Facebook login. When I check my data on the Parse website, there are no PFUsers.

As far as I can tell I have followed the exact instructions laid out by Parse (https://parse.com/docs/ios/guide#users) and Facebook.(https://developers.facebook.com/docs/ios/getting-started). I am using XCode 6.3.2. I have added integrated Parse (ParseFacebookUtilsV4 v1.7 & ParseUI v1.1) and Facebook (FBSDKCoreKit v4.2 &FBSDKLoginKit v4.2) in Cocoapods, and have linked the following libraries:

libsqlite3.dylib
libz.dylib
Accounts.framework
AudioToolbox.framework
CFNetwork.framework
CoreGraphics.framework
CoreLocation.framework
CoreLocation.framework
MobileCoreService.framework
QuartzCore.framework
Security.framework
Social.framework
StoreKit.framework
SystemConfiguration.framework
libPods-xxx.a (being the name of my project)

My code is as follows:

//Appdelegate.swift
import UIKit


@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

//--------------------------------------
// MARK: - UIApplicationDelegate
//--------------------------------------

func application(application: UIApplication, didFinishLaunchingWithOptions   launchOptions: [NSObject: AnyObject]?) -> Bool {


    Parse.setApplicationId("xxxxxxxx",
        clientKey: "xxxxxxxxxx")
               PFFacebookUtils.initializeFacebookWithApplicationLaunchOptions(launchOptions)

    return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)


}

}


func application(   application: UIApplication,
                openURL url: NSURL,
                sourceApplication: String,
                annotation: AnyObject?) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application,
                                                            openURL: url,
                                                            sourceApplication: sourceApplication,
                                                            annotation: annotation)
}

//Facebook analytics
func applicationDidBecomeActive(application: UIApplication!) {
FBSDKAppEvents.activateApp()
} 

And the View controller in which the login in placed:

//OnboardingRootViewController.swift

import Foundation
import UIKit




class OnboardingRootViewController: UIViewController {


override func viewDidLoad() {
    super.viewDidLoad()
}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}



@IBAction func fbLoginClick(sender: AnyObject) {

var permissions = ["public_profile", "email", "user_likes"]


PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions) {
    (user: PFUser?, error: NSError?) -> Void in
    if let user = user {
        if user.isNew {
            println("User signed up and logged in through Facebook!")
        } else {
            println("User logged in through Facebook!")
        }
    } else {
        println("Uh oh. The user cancelled the Facebook login.")
    }
}
}


}

So, can anyone be of any help? Again, the Facebook login at least appears to work, when the IBAction fbLoginClick is invoked, but the "Uh oh. The user cancelled the Facebook login." message is shown in the log, and no new PFUser is created in Parse. I've seen multiple other similar questions, but none with any real answers so I'm sure an answer to this question would be appreciated by many, especially as this is using the exact code shown in the login tutorials created by Parse and Facebook!

Edit: If no one is able to help, I'd still appreciate help with the following: I've been told that I should check which error message is returned by loginInBackgroundWithReadPermissions, unfortunately without further explanation. Was this person simply referring to the "Uh oh. The user cancelled the Facebook login." message, or is it possible to retrieve any information through the NSError?

Edit #2: I added the following line of code to see what the NSError returns: println("write failure: (error?.localizedDescription)")

And get the following message in the log: Uh oh. The user cancelled the Facebook login. write failure: nil

So I guess that didn't really get me any further...

Edit #3: Like seriously, I'll paypal 10$ to anyone that can help me

1

There are 1 best solutions below

1
On BEST ANSWER

This code will work if you set up the frameworks correctly and follow the steps of Parse's Facebook setup guide (https://parse.com/docs/ios/guide#users-facebook-users). Make sure your syntax is the same as the functions I have and try getting rid of any unnecessary code that isn't included below.

AppDelegate.swift

import UIKit
import CoreData
import Parse

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    //X's replace my actual Parse information

    Parse.setApplicationId("XXXXXXXXXXXXXXXXXXXXXX", clientKey: "XXXXXXXXXXXXXXXXXXXXXX")
    PFAnalytics.trackAppOpenedWithLaunchOptions(launchOptions)

    PFFacebookUtils.initializeFacebookWithApplicationLaunchOptions(launchOptions)

    return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)

}

func applicationWillResignActive(application: UIApplication) {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

func applicationDidEnterBackground(application: UIApplication) {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

func applicationWillEnterForeground(application: UIApplication) {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

func applicationDidBecomeActive(application: UIApplication) {

    FBSDKAppEvents.activateApp()
}

/*
func application(application: UIApplication, url: NSURL, sourceApplication: NSString, annotation: AnyObject) -> Bool {

    return FBSDKApplicationDelegate.sharedInstance().application(
        application,
        openURL: url,
        sourceApplication: sourceApplication as String,
        annotation: annotation)

}*/

func application(application: UIApplication,
    openURL url: NSURL,
    sourceApplication: String?,
    annotation: AnyObject?) -> Bool {
        return FBSDKApplicationDelegate.sharedInstance().application(application,
            openURL: url,
            sourceApplication: sourceApplication,
            annotation: annotation)
}

func applicationWillTerminate(application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    // Saves changes in the application's managed object context before the application terminates.
    self.saveContext()
}

ViewController.swift

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

let permissions = [ "email","user_birthday", "public_profile", "user_friends"]

@IBAction func loginButtonPressed(sender: AnyObject) {
    PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions) {
        (user: PFUser?, error: NSError?) -> Void in
        if let user = user {
            if user.isNew {
                println("User signed up and logged in through Facebook!")
            } else {
                println("User logged in through Facebook!")
            }
        } else {
            println("Uh oh. The user cancelled the Facebook login.")
        }
    }
}

}

The @IBAction is for a simple UIButton I put in the center of the blank viewcontroller in my Main.storyboard

Objective-C Bridging Header:

#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <ParseFacebookUtilsV4/PFFacebookUtils.h>
#import <Parse/Parse.h>

Hope this solves your problem!