Facebook SDK and Swift 2.0 - Problems with handling accessToken - ios

my name is Vincent and I need your help !
(My code is not exhaustive)
No problem to login or logout with the Facebook SDK ... BUT
When I start my app, no access token and when i click on the Login button, it prints me an accessToken, then I logout.
How to get the accessToken when the app starts ?
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
class HomeViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
getUserStatuts()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK -> Facebook Connect
func loginToFacebook() {
if let fbToken = FBSDKAccessToken.currentAccessToken() {
print("Acces token : \(fbToken)")
loginManager.logOut()
print("Logout")
} else {
print("Login")
loginManager.logInWithPublishPermissions(publishPermissions, fromViewController: nil, handler: {
(result:FBSDKLoginManagerLoginResult!, error:NSError!) -> Void in
if error == nil {
self.getUserData()
} else {
print(error.localizedDescription)
}
})
}
}
func getUserData() {
let readPermissions = ["public_profile", "email", "user_friends", "user_birthday"]
let parameters = ["fields": "id, first_name, last_name, name, birthday, picture.type(large)"]
let request = FBSDKGraphRequest(graphPath: "me", parameters: parameters)
request.startWithCompletionHandler({
(connection, result, error) -> Void in
if error == nil {
// display info
}
})
}

In the login function you want to implement the
let fbLogin = FBSDKLoginManager()
fblogin.logout()
the fblogin.logout() must be implemented before fbLogin.logInWithReadPermissions(["email"], fromViewController: self) { (facebookResult, facebookError) in
if facebookError != nil { ` to clear any access tokens from previous login.

Related

Facebook login and App Invites for iOS in Swift

I am stuck after coding the Facebook login.....!
After the login procedure I just end up with a logout button.
I would like to make use of the App Invites for iOS but I cant figure out how to integrate it...
The documentations on "Facebook.developer" is hard to understand.
This is my code so far in the view controller:
import UIKit
import FacebookLogin
import FBSDKLoginKit
class ViewController: UIViewController, FBSDKLoginButtonDelegate {
var dict : [String : AnyObject]!
override func viewDidLoad() {
super.viewDidLoad()
//creating button
let loginButton = LoginButton(readPermissions: [ .publicProfile, .userFriends, .email ])
loginButton.center = view.center
//adding it to view
view.addSubview(loginButton)
//if the user is already logged in
if let accessToken = FBSDKAccessToken.current(){
getFBUserData()
}
}
//when login button clicked
#objc func loginButtonClicked() {
let loginManager = LoginManager()
loginManager.logIn([ .publicProfile, .userFriends, .email ], viewController: self) { loginResult in
switch loginResult {
case .failed(let error):
print(error)
case .cancelled:
print("User cancelled login.")
case .success(let grantedPermissions, let declinedPermissions, let accessToken):
self.getFBUserData()
}
}
}
//function is fetching the user data
func getFBUserData(){
if((FBSDKAccessToken.current()) != nil){
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, picture.type(large), email"]).start(completionHandler: { (connection, result, error) -> Void in
if (error == nil){
self.dict = result as! [String : AnyObject]
print(result!)
print(self.dict)
}
})
}
}
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
/*
Check for successful login and act accordingly.
Perform your segue to another UIViewController here.
*/
let viewController = self.storyboard?.instantiateInitialViewController("StoryBoardID") as? UITableViewController
self.presentViewController(viewController, animated: true, completion: nil)
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
// Actions for when the user logged out goes here
}
}
Any help?

Facebook FBSDKLoginManager/logInWithReadPermissions Swift Example not using Parse

Where is the latest Facebook Swift Documentation. I can't get the FB Login Dialog to show up. The call to loginWithReadPermissions never returns?
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
class ViewController: UIViewController {override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let loginManager = FBSDKLoginManager()
loginManager.logInWithReadPermissions(["basic_info", "email", "user_likes"], fromViewController: self.parentViewController, handler: { (result, error) -> Void in
if error != nil {
print(FBSDKAccessToken.currentAccessToken())
} else if result.isCancelled {
print("Cancelled")
} else {
print("LoggedIn")
}
})
}
You code should work if you exclude "user_likes" from permissions.
From facebook docs:
If your app asks for more than public_profile, email and user_friends, Facebook must review it before you release it. Learn more about the review process and what's required to pass review.
https://developers.facebook.com/docs/facebook-login/permissions/v2.5#reference-user_likes
Another problem may be that you have not set correctly the FacebookSDK in your project. See this tutorial: https://developers.facebook.com/docs/ios/getting-started/
So the answer is to use FBSDKLoginButton with the following
In the class declaration of the viewController
import FBSDKCoreKit
import FBSDKLoginKit
class ViewController: UIViewController, FBSDKLoginButtonDelegate
Then show the FBLogin Button with
// Setup the FB Login/Logout Button FB will take care of the
// verbiage based on the current access token
let loginView : FBSDKLoginButton = FBSDKLoginButton()
self.view.addSubview(loginView)
loginView.center = self.view.center
loginView.readPermissions = ["public_profile", "email", "user_friends"]
loginView.delegate = self
// If we have an access token, then let's display some info
if (FBSDKAccessToken.currentAccessToken() != nil)
{
// Display current FB premissions
print (FBSDKAccessToken.currentAccessToken().permissions)
// Since we already logged in we can display the user datea and taggable friend data.
self.showUserData()
self.showFriendData()
}
Show the users info with
func showUserData()
{
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields" : "id, name, gender, first_name, last_name, locale, email"])
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
// Process error
print("Error: \(error)")
}
else
{
let userName : NSString = result.valueForKey("name") as! NSString
print("User Name is: \(userName)")
if let userEmail : NSString = result.valueForKey("email") as? NSString {
print("User Email is: \(userEmail)")
}
}
})
}
And to display the taggable friends
func showFriendData()
{
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me/taggable_friends?limit=999", parameters: ["fields" : "name"])
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
// Process error
print("Error: \(error)")
}
else
{
if let friends : NSArray = result.valueForKey("data") as? NSArray{
var i = 1
for obj in friends {
if let name = obj["name"] as? String {
print("\(i) " + name)
i++
}
}
}
}
})
}

Swift how to close Facebook graph block

I want, and I don't know how to =(, close my Facebook graph block
My problem is that I want to save the username of my user facebook in a variable to use it later (another view controller), but I can't because my block is closed after I try to save the data.
This is my delegate function :
// Facebook Delegate Methods
func loginButton(connection: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
if (error != nil)
{
println("Error")
}
else {
println("User logged in")
self.returnUserData()
}
}
And this is my function which use facebook graph api
// Here my block that I want to close, maybe with completion closure inside
func returnUserData()
{
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, picture.type(large), email"])
// Launch asynchronous function
var userName : String = "error"
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
// Process error
println("Error: \(error)")
}
else
{
println(result)
userName = result["first_name"] as! String
}
})
}
Can somebody help me ?
Take a look at this example, you can set the variable outside of the scope of your closure then ask it to perform a specific func when it's value is set like so:
import UIKit
class ViewController: UIViewController {
var myString : String = "123" {
didSet {
self.stringUpdated()
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
myString = "456" // this would take place in your graph request closure
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func stringUpdated() {
println("got it, string is \(myString)")
}
}

Facebook Login without FBSDKLoginButton in Swift

I am trying to add facebook login for my app. I am using the FBSDKLoginButton which comes with its own button and once you login it turns to logout. I don't want all that. I just need to add my own button a view. And in that button's #IBAction I want the facebook login to take place. The code which I am now using is
class ViewController: UIViewController,FBSDKLoginButtonDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if (FBSDKAccessToken.currentAccessToken() != nil)
{
// User is already logged in, do work such as go to next view controller.
}
else
{
let loginView : FBSDKLoginButton = FBSDKLoginButton()
self.view.addSubview(loginView)
loginView.center = self.view.center
loginView.readPermissions = ["public_profile", "email", "user_friends"]
loginView.delegate = self
}
}
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
println("User Logged In")
if ((error) != nil)
{
// Process error
}
else if result.isCancelled {
// Handle cancellations
}
else {
returnUserData()
// If you ask for multiple permissions at once, you
// should check if specific permissions missing
if result.grantedPermissions.contains("email")
{
// Do work
}
}
}
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
{
println("fetched user: \(result)")
let userName : NSString = result.valueForKey("name") as! NSString
println("User Name is: \(userName)")
let userEmail : NSString = result.valueForKey("email") as! NSString
println("User Email is: \(userEmail)")
}
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
How do I customise this and achieve what I need. Thanks in advance.
You might want to check the latest FacebookSDK, here's what i have:
#IBAction func connectWithFacebook(){
if FBSDKAccessToken.currentAccessToken() != nil {
FBSDKLoginManager().logOut()
return
}
let login:FBSDKLoginManager = FBSDKLoginManager()
login.logInWithReadPermissions(["email"], handler: { (result:FBSDKLoginManagerLoginResult!, error:NSError!) -> Void in
if(error != nil){
FBSDKLoginManager().logOut()
}else if(result.isCancelled){
FBSDKLoginManager().logOut()
}else{
//Handle login success
}
})
}
Otherwise with the older SDK you can do the following:
Add the FBSDKLoginButton to your view and set it invisible
Add your custom button
On your custom button IBAction perform a click on the FBSDKLoginButton with the method sendActionsForControlEvents
FBSDKLoginManager can be used if FB Login is handled via custom button.
For more info, your can check this.
Set current access is nil.
This calls [FBSDKAccessToken setCurrentAccessToken:nil] and
[FBSDKProfile setCurrentProfile:nil].
FBSDKAccessToken.setCurrentAccessToken(nil)
For Facebook logout.

Parse Facebook Login/Signup Not Working (Swift)

I've been frustratingly trying to implement Parse's Facebook login function into my app using Swift for over a month and can't seem to figure it out. I successfully linked my app to both Facebook and Parse separately, but I can't make a Parse user using Facebook's login. I believe the AppDelegate is setup correctly, so I will only show my LoginViewController and hopefully someone who knows what they're doing can please help me out:
import UIKit
import Parse
import FBSDKCoreKit
import FBSDKLoginKit
protocol LoginViewControllerDelegate {
func onRegister(loginViewController : LoginViewController)
func onFacebookLogin(loginViewController : LoginViewController)
func onLogin(loginViewController : LoginViewController)
}
class LoginViewController: UIViewController, FBSDKLoginButtonDelegate {
//MARK: - Outlets
#IBOutlet weak var lblStatus: UILabel!
//var delegate : LoginViewControllerDelegate?
// Set permissions required from the facebook user account
let permissions = [ "user_about_me", "user_relationships", "user_location", "user_birthday", "public_profile", "user_friends", "user_email", "user_gender"]
//MARK: - Initial Load
override func viewDidLoad() {
super.viewDidLoad()
self.lblStatus.alpha = 0
//Facebook
if (FBSDKAccessToken.currentAccessToken() != nil)
{
// User is already logged in, do work such as go to next view controller.
}
else
{
let loginView : FBSDKLoginButton = FBSDKLoginButton()
// self.view.addSubview(loginView)
// loginView.center = self.view.center
// loginView.readPermissions = ["public_profile", "email", "user_friends"]
loginView.delegate = self
}
// ---------------------------- Check if user is logged in ---------------------
if PFUser.currentUser() != nil {
println("parse: User already logged in")
performSegueWithIdentifier("loggedIn", sender: self)
}
}
//MARK: - Facebook Login Button
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
if ((error) != nil) {
println(error) // Process error
} else if result.isCancelled { // Handle cancellations
} else {
// If you ask for multiple permissions at once, you
// should check if specific permissions missing
if result.grantedPermissions.contains("email")
{
// Do work
}
}
returnUserData()
}
#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.alpha = 1
}else{
println("FB login 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("loggedIn", sender: self)
} else {
println("User logged in via Facebook \(user)")
self.performSegueWithIdentifier("loggedIn", sender: 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)
var facebookID: AnyObject? = userData["id"]
var name: AnyObject? = userData["first_name"]
var gender: AnyObject? = userData["gender"]
var birthday: AnyObject? = userData["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: "profilePicture")
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") }
}
})
}
}
Some important notes to make:
I am using the newest version of Parse (1.7.4) and FBSDK (4.1), so most other methods I've found online do not work anymore because certain functions or members have been removed since then.
The "func loginButton" is what I used for the FBSDKLoginButton, while the "#IBAction func facebookLoginDidPres" is for a regular UIButton I tried using for logging in. Based on what I've learned recently, I believe the UIButton method is the one I should go with, but that one leads to a Thread 1: Signal SIGABRT error stating:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[PFFacebookUtils logInInBackgroundWithReadPermissions:block:]: unrecognized selector sent to class 0x10ed3ed80'
*** First throw call stack:
...
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) ""
So I placed an exception breakpoint and it ended at the end of the "logInInBackgroundWithReadPermissions" function in my IBAction with the console stating:
"[PFFacebookUtils logInInBackgroundWithReadPermissions:block:]: unrecognized selector sent to class 0x10dbe2db0 (lldb)"
The last detail I feel is worth mentioning is that my console states "parse: User already logged in" in when I run the app, however there is no User created when I check Parse. This is getting printed from the section under "check if the user is logged in" section of my LogInViewController's viewDidLoad function.
I will be forever grateful to anyone who can help me figure out this problem that's been puzzling me for far too long. Thank you in advance!
I deleted the old PFFacebookUtils Framework, but kept the PFFacebookUtilsV4 Framework, and that solved the problem for me! Hopefully that helps anyone else with this problem :)
I have the same problem, my solution is to define Login behaviour = Web
PFFacebookUtils.facebookLoginManager().loginBehavior = FBSDKLoginBehavior.Web
When I call this before call loginInBackground..., after clicking to the "OK" button, my application received call-back with a user (not nil) and PFUser.currentUser is updated with that user.

Resources