ios - 解析和 Facebook 登录和注册返回 "User Cancelled Login"(iOS 8.1 + Swift 1.2)

标签 ios facebook swift facebook-graph-api parse-platform

我一直在尝试使用 Parse(版本 1.7.4)通过 Facebook 的 SDK(版本 4.1)登录和注册用户,但每次我尝试注册时,以下代码都会打印“用户取消了 FB 登录”,这意味着用户返回为零,但没有错误。我不知道这是 Parse 问题还是 Facebook 问题,但如果有人知道如何解决这个问题,我将非常感激。

这是我的登录/注册 View Controller 的代码:

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

@IBOutlet weak var lblStatus: UILabel!

@IBAction func facebookLoginDidPress(sender: AnyObject) {

    self.lblStatus.alpha = 0

    PFFacebookUtils.logInInBackgroundWithReadPermissions(self.permissions, block: {
        (user: PFUser?, error: NSError?) -> Void in
        if user == nil {
            if error == nil {
                println("User cancelled FB login")
                self.lblStatus.text = "User cancelled login"
                self.lblStatus.alpha = 1
            }else if error != nil {
                println("FB login error: \(error)")
                self.lblStatus.text = "Error: \(error)"
                self.lblStatus.alpha = 1
            }
        } else {
            if user!.isNew {
                println("User signed up and logged in with Facebook! \(user)")
                self.requestFacebook()
                self.returnUserData()
                self.performSegueWithIdentifier("signedUp", sender: self)
            } else {
                println("User logged in via Facebook \(user)")
                self.performSegueWithIdentifier("loggedIn", sender: self)
            }
            if self.delegate != nil {
                self.delegate!.onFacebookLogin(self)
            }
        }
    })

}

func requestFacebook() {

    let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: nil)
    graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in

        if ((error) != nil)
        {
            // Process error
            println("Error: \(error)")
        }
        else if error == nil
        {

            var userData: NSDictionary = NSDictionary(objectsAndKeys: result)

            /*
            if let facebookID : NSString = result.valueForKey("id") as? NSString {
                println("User FbId is: \(facebookID)")
            } else {println("No facebookID fetched")}

            if let name : NSString = result.valueForKey("first_name") as? NSString {
                println("User's Name is: \(name)")
            } else {println("No name fetched")}

            if let gender : NSString = result.valueForKey("gender") as? NSString {
                println("User's gender is: \(gender)")
            } else {println("No gender fetched")}

            if let name : NSString = result.valueForKey("first_name") as? NSString {
                println("User's Name is: \(name)")
            } else {println("No name fetched")}

            if let birthday : NSString = result.valueForKey("birthday") as? NSString {
                println("User's birthday is: \(birthday)")
            } else {println("No birthday fetched")}
            */

            var facebookID: AnyObject? = userData["id"]
            PFUser.currentUser()!.setObject(facebookID!, forKey: "fbid")

            var name: AnyObject? = userData["first_name"]
            PFUser.currentUser()!.setObject(name!, forKey: "username")

            var gender: AnyObject? = userData["gender"]
            PFUser.currentUser()!.setObject(gender!, forKey: "gender")

            var birthday: AnyObject? = userData["birthday"]
            PFUser.currentUser()!.setObject(birthday!, forKey: "birthday")

            var pictureURL = "https://graph.facebook.com/\(facebookID)/picture?type=large&return_ssl_resources=1"

            var URLRequest = NSURL(string: pictureURL)
            var URLRequestNeeded = NSURLRequest(URL: URLRequest!)


            NSURLConnection.sendAsynchronousRequest(URLRequestNeeded, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!, error: NSError!) -> Void in
                if error == nil {
                    var picture = PFFile(data: data)
                    PFUser.currentUser()!.setObject(picture, forKey: "picture")
                    PFUser.currentUser()!.saveInBackground()
                }
                else {
                    println("Error: \(error.localizedDescription)")
                }
            })
        }
    })
}

func loginButtonDidLogOut(loginButton: FBSDKLoginButton!) {
    println("User Logged Out")
}

func returnUserData()
{
    let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: nil)
    graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
        if ((error) != nil)
        {
            // Process error
            println("Error: \(error)")
        }
        else
        {
            if let userName : NSString = result.valueForKey("name") as? NSString {
                println("User Name is: \(userName)")

            } else {println("No username fetched")}

            if let userEmail : NSString = result.valueForKey("email") as? NSString {
                println("User Email is: \(userEmail)")
            } else  {println("No email address fetched")}

            if let userGender : NSString = result.valueForKey("gender") as? NSString {
                println("User Gender is: \(userGender)")
            } else {println("No gender fetched") }
        }
    })
}

这是我的 AppDelegate.swift 中的代码(当然编辑了解析键):

import UIKit
import CoreData
import Parse
import FBSDKCoreKit
import FBSDKLoginKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

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

    //Parse Configuration
    Parse.setApplicationId("XXXXXXX", clientKey: "XXXXXXX")

    PFAnalytics.trackAppOpenedWithLaunchOptionsInBackground(launchOptions, block: nil)

    PFFacebookUtils.initializeFacebookWithApplicationLaunchOptions(launchOptions)

    //Facebook Configuration
    FBSDKLoginButton()

    PFUser.enableRevocableSessionInBackground()

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

}

func applicationDidBecomeActive(application: UIApplication) {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    FBSDKAppEvents.activateApp()
}

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()
}

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

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

}

这是我的框架的屏幕截图:

Frameworks as seen on side bar

Frameworks as seen on Link Binaries section

我仔细检查了我的 info.plist 并确保我的 bundle 标识符位于我的 Facebook 应用程序设置中,并且我的 Facebook 信息位于我的 Parse 应用程序设置中。我尝试制作一个全新的 Parse 和 Facebook 应用程序,但问题仍然存在。我记得几个月前分别测试了 Facebook 登录和 Parse 用户注册,创建了一个用户并将该帐户链接到该应用程序,但在实现 PFFacebokUtils 并删除旧用户后,登录似乎继续显示用户“已取消 FB”登录。”该应用程序是否可以保存或缓存旧用户或某些我不知道的 Facebook token ,从而阻止再次登录或注册?我尝试使用 PFUser.logOut() 并打印信息来确认我的应用程序中没有现有用户,但它仍然说用户取消了登录。使用 accessToken 可以解决问题吗?我的 Facebook 应用程序获得批准会改变什么吗?如果有人知道这些问题的答案,或者有以前的答案或评论中未提出的想法,请告诉我。非常感谢您的帮助。

最佳答案

好吧,经过几个月的挫折,我终于解决了这个问题!而且它非常简单。我决定创建一个新的 Xcode 项目,专门用于测试 PFFacebookUtils 登录,看看是否可以创建一个不存在此问题的登录系统。果然,在仔细遵循 Parse 的 Facebook 登录指南( https://parse.com/docs/ios/guide#users-facebook-users )后,我通过 PFFacebookUtils 成功登录,在测试应用程序上没有任何问题!事实证明,我的所有框架都设置正确,但我的应用程序中的某些关键功能混合了不必要的代码和略有不同的语法,导致取消登录问题。我将把 PFFacebookUtils 测试项目中的所有代码放在下面,以便任何面临相同问题的人都可以编辑他们的代码以匹配它。如果这不起作用,我建议您自己尝试一下,看看它们的不同之处。

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.")
        }
    }
}

}

@IBAction 用于一个简单的 UIButton,我将其放置在 Main.storyboard 中空白 View Controller 的中心

Objective-C 桥接头:

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

希望这对遇到此问题的其他人有所帮助!

关于ios - 解析和 Facebook 登录和注册返回 "User Cancelled Login"(iOS 8.1 + Swift 1.2),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30642969/

相关文章:

facebook - 使用 Facebook Graph API 上传动画 GIF 文件

ios - 透明背景变白

ios - 在第二个 View Controller 中使用 GameScene 的分数

ios - 如何将 Swift REPL 与 iOS SDK 一起使用

ios - 如何在不加载以前的数据的情况下从父 View 中删除和添加 UICollectionView ?

ios - UIViewControllerView 内的 UITableView 意外边距

ios - 如何将 iOS 价格格式从 -0.00 舍入到 0.00?

facebook - 如何为您的 Facebook 应用程序创建虚假用户进行测试?

ios - 缩放 UIImage 以与 CGContextDrawImage 一起使用

ios - 向数据库添加信息 Parse.com 错误 PFObject