I am trying to log in and save a user to Parse using PFFacebookUtils. Note, I am using the FBSDKLoginButton, and I do NOT want to use the PFLoginViewController, I need a much more custom login. Here is my code:
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result1: FBSDKLoginManagerLoginResult!, error: NSError!) {
if error == nil {
// this block of code is reached fine.
PFFacebookUtils.logInInBackgroundWithReadPermissions(["public_profile"], block: { (user, error2) -> Void in
// both error2 and user both print out to nil here
print(error2)
print(user)
if let newUser = user {
// inside this block of code is never reached
}
})
}
}
what could be the problem?
Related
I am developing an iOS application which uses Facebook as one of the mode for user login. I have added the code as this:
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!)
{
if error != nil { print(error.localizedDescription) }
if result.isCancelled{
print("Cancelled") }
else {
self.performSegueWithIdentifier("facebookLogin", sender: self)
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(fbLoginButton)
fbLoginButton.center = view.center
//checking current login status
checkCurrentLoginStatus()
fbLoginButton.delegate = self
}
func checkCurrentLoginStatus(){
if FBSDKAccessToken.currentAccessToken() != nil{
//load data from here
}
else {
print("Not yet logged in!")
}
}
and the basic code in app delegate file along with permissions in info plist. I am not sure but currently but for some reason when I am trying authorise app in safari web browser, web view goes blank with the done button. If someone can tell me why is this happening, it will be really helpful.
Thank you!
self.storyboard?.instantiateViewControllerWithIdentifier("FirstViewControllerStoryboardIdhere") as! FirstViewControllerClassnamehere
This solved it. :)
I am trying to register / login users to my IOS app using the facebook sdk.
when i press the login button safari opens a Facebook login screen. After correct credential are entered i am returned to the app and the log in button changes to logout button and i can retrieve user information (name and email address). the problem is when i try to pass this on to my backend services (telerik / everlive) it comes back with the following error:
Failed to log in the user: The provided access token is invalid or has expired
all the following code is from my LoginViewController
override func viewDidLoad() {
super.viewDidLoad()
if (FBSDKAccessToken.currentAccessToken() != nil)
{
print("User is already logged in")
// 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"]
loginView.delegate = self
}
}
//
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
print("Returned from Login")
if ((error) != nil)
{
print(error.description)
// Process error
}
else if result.isCancelled {
print("cancelled")
// Handle cancellations
}
else {
// If you ask for multiple permissions at once, you
// should check if specific permissions missing
if result.grantedPermissions.contains("email")
{
print(result.token)
}
print(result.token.tokenString)
print(FBSDKAccessToken.currentAccessToken().tokenString)
fbToken = result.token
registerUserFromFacebook()
}
}
//
func registerUserFromFacebook(){
print("1")
print(fbToken.tokenString)
EVUser.loginWithFacebook(fbToken.tokenString , block: { (user:EVUser!, error:NSError!) -> Void in
if (error == nil) {
user.username = String("\(self.facebookFirstName)\(self.facebookLastName)")
} else {
//This is the error
print("Failed to log in the user: " + error.domain)
}
})
}
I am struggling with this and all the documentation for both telerik and Facebook SDK are in objective c which I don't know opposed to swift.
Don't make it as a duplicate question, I raise this question because the answers are not helpfull,
The integration works fine for me, but the pages loads really slow.
It takes really a long time to load the login screen. Login action takes more than 8-50 seconds or more.
Sometimes for loading authentification screen takes more than 10 secs.
The Following code is for FBLoginButtonAction
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!){
if(error != nil){
print(error.localizedDescription)
return
}
if result.isCancelled{
showAlert(title: "Login Cancelled", message: "You have cancelled login through Facebook")
}
if FBSDKAccessToken.currentAccessToken() != nil{
print("Logged in")
}
}
You can make FBlogin using NSNotification method.
Just follow below steps.
set FBDelegate and set observer for NSNotification in ViewDidload like,
self.btnFBLogin.delegate = self
self.btnFBLogin.readPermissions = ["public_profile","email","user_friends"]
FBSDKProfile.enableUpdatesOnAccessTokenChange(true)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "getUserProfile:", name: FBSDKProfileDidChangeNotification, object: nil)
2.Now make one custom function for NSNotification like,
func getUserProfile(notification : NSNotification)
{
let accessToken = FBSDKAccessToken.currentAccessToken()
if(accessToken != nil)
{
let req = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"email,name"], tokenString: accessToken.tokenString, version: nil, HTTPMethod: "GET")
req.startWithCompletionHandler({ (connection, result, error : NSError!) -> Void in
if(error == nil)
{
print("result \(result)")
let userInfo = result as AnyObject
if let email = userInfo.valueForKey("email") as? NSString
{
print(email)
}
else
{
let loginManager = FBSDKLoginManager()
loginManager.logOut()
}
}
else
{
print("error \(error)")
}
})
}
}
Note : Don't write any logic in FB delegate method. Just put it there.
I think this will help u bcz it works fine for me. :)
I've been stuck on how to implement a custom Twitter login with Parse for my Swift app for a while now. Most resources I've seen for Twitter login with iOS are for Objective-C, and I've tried changing the suggested solutions into Swift, but no luck so far. This is my current code:
#IBAction func twitterLogIn(sender: AnyObject) {
PFTwitterUtils.logInWithBlock( { (user: PFUser?, error: NSError?) -> Void in
// apparently both user and currentUser are nil...
if PFTwitterUtils.isLinkedWithUser(PFUser.currentUser()) {
var info: NSURL! = NSURL(string: "https://api.twitter.com/1.1/account/settings.json")
var request: NSMutableURLRequest = NSMutableURLRequest(URL: info)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: { (response: NSURLResponse!, data: NSData!, connectionError: NSError!) -> Void in
if let d = data {
var dict: NSDictionary = NSJSONSerialization.JSONObjectWithData(d, options: NSJSONReadingOptions.MutableLeaves, error: nil) as! NSDictionary
// do stuff with user's profile info
} else {
println("Apparently no Twitter response.")
}
})
} else {
println("Apparently failed login.")
}
})
}
This prints out Apparently failed login. I've also tried this:
PFTwitterUtils.logInWithBlock( { (user: PFUser?, error: NSError?) -> Void in
if let user = user {
if user.isNew {
println("User signed up and logged in with Twitter.")
// put information in user object
user.save()
} else {
println("User logged in with Twitter.")
}
} else {
println("User was nil.")
}
})
It printed out User was nil. And I also tried this:
if let twitter = PFTwitterUtils.twitter() {
if twitter.userId != nil && twitter.screenName != nil && twitter.authToken != nil && twitter.authTokenSecret != nil {
PFTwitterUtils.logInWithTwitterId(twitter.userId!, screenName: twitter.screenName!, authToken: twitter.authToken!, authTokenSecret: twitter.authTokenSecret!, block: { (user: PFUser?, error: NSError?) -> Void in
if let user = user {
if user.isNew {
println("User signed up and logged in with Twitter.")
// put info in user object
user.save()
} else {
println("User logged in with Twitter.")
}
} else {
println("User was nil. Something went wrong. Did the user cancel the login?")
}
})
} else {
println("Couldn't access a Twitter account on this device.")
}
} else {
println("Couldn't find a Twitter account on this device.")
}
Which printed Couldn't access a Twitter account on this device. The only other option I know of right now is to use the built-in login view controller, but I'd rather use a custom one. How can I implement a custom Twitter login function?
Edit: I tried another method that didn't work yet again:
PFTwitterUtils.logInWithBlock( { (user: PFUser?, error: NSError?) -> Void in
// apparently both user and currentUser are nil...
println(2)
if !(PFTwitterUtils.isLinkedWithUser(user)) {
println(3)
PFTwitterUtils.linkUser(user!, block: { (succeeded: Bool, error: NSError?) -> Void in
println(4)
if succeeded {
println("User linked with Twitter.")
}
})
}
println(5)
if let u = user {
println(6)
if u.isNew {
println("User signed up and logged in with Twitter.")
// put info in user object
var info: NSURL! = NSURL(string: "https://api.twitter.com/1.1/account/settings.json")
println(7)
var request: NSMutableURLRequest = NSMutableURLRequest(URL: info)
println(8)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: { (response: NSURLResponse!, data: NSData!, connectionError: NSError!) -> Void in
println(9)
if let d = data {
println(10)
var dict: NSDictionary = NSJSONSerialization.JSONObjectWithData(d, options: NSJSONReadingOptions.MutableLeaves, error: nil) as! NSDictionary
// do stuff with this data
} else {
println("Apparently no Twitter response.")
}
})
} else {
println("User logged in with Twitter.")
}
} else {
println("User was nil.")
}
})
This prints up to 3 and then complains of a nil optional value, most likely user.
Edit: I've been testing Fabric as a possible solution and although it provides a good Twitter login method, I can't figure out how to use it with Parse, specifically, how to create and handle a corresponding user object as I can't access the user's password. I'd much prefer to use PFTwitterUtils for the best integration with Parse, but I'm running out of options for that. Can anyone help?
var first_name = ""
func problemFunc() {
FBRequestConnection.startForMeWithCompletionHandler { (connection: FBRequestConnection!, result: AnyObject!, error: NSError!) -> Void in
if let fbGraphUserDict = result as? Dictionary<String, AnyObject>{
first_name = fbGraphUserDict["first_name"] as NSString
println(first_name)
}
}
}
PFFacebookUtils.logInWithPermissions(permissions, {
(user: PFUser!, error: NSError!) -> Void in
if user == nil {
NSLog("Uh oh. The user cancelled the Facebook login.")
} else if user.isNew {
NSLog("User signed up and logged in through Facebook!")
} else {
NSLog("User logged in through Facebook!")
problemFunc() // error is here
}
})
This code is inside an #Ibaction button. I cannot build because the call to problemFunc() triggers the error message in the title of this post. If I move the first_name var definition inside the problemFunc it will work ok. But I need it out, because another function will need to access its value.
I'm really not sure at what causes this problem, if you have a clue, please help.
Use a closure instead of a function:
var first_name = ""
let problemFunc = { () -> () in
FBRequestConnection.startForMeWithCompletionHandler { (connection: FBRequestConnection!, result: AnyObject!, error: NSError!) -> Void in
if let fbGraphUserDict = result as? Dictionary<String, AnyObject>{
first_name = fbGraphUserDict["first_name"] as NSString
println(first_name)
}
}
}
PFFacebookUtils.logInWithPermissions(permissions, {
(user: PFUser!, error: NSError!) -> Void in
if user == nil {
NSLog("Uh oh. The user cancelled the Facebook login.")
} else if user.isNew {
NSLog("User signed up and logged in through Facebook!")
} else {
NSLog("User logged in through Facebook!")
problemFunc() // error is here
}
})
Here are the basic principles in play: (from Apple's docs: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID103)
"Global and nested functions, as introduced in Functions, are actually special cases of closures. Closures take one of three forms:
Global functions are closures that have a name and do not capture any values.
Nested functions are closures that have a name and can capture values from their enclosing function.
Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context."
ie this is ok
func someFunc() {
func nestFunc() {}
}
but this is not
func someFunc() {
func nestFunc() {
func nestedFunc2() { }
}
}
If you look at this in Xcode the third function (func nestedFunc2) will give you the error "Cannot reference a local function with capture from another local function"
The top function (func someFunc) is a global scope function and those work like regular functions/methods.
The second function (func nestFunc) is a nested function which is a named closure one level deep that can capture the scope of its parent global function.
Nested functions, can capture the scope of a global function but not the scope of another nested function.
That's why we need a closure i.e.
func someFunc() {
func nestFunc() {
let strictClosure = { () -> () in
//this is where you write the code
}
}
}
#fluidsonic answer should solve the problem. However note that you're doing some spaghetti code, because you are modifying a variable captured by a closure, and executed in the context of another function. That's hard to track if you need to debug, and more generally hard to follow when and how that variable is modified.
A more linear and better readable flow is to define problemFunc as a function taking a function as parameter, and calling that function rather than directly setting the value in the first_name variable:
let problemFunc = { (callback: (String -> Void) -> ()) in
FBRequestConnection.startForMeWithCompletionHandler { (connection: FBRequestConnection!, result: AnyObject!, error: NSError!) -> Void in
if let fbGraphUserDict = result as? Dictionary<String, AnyObject>{
let first_name = fbGraphUserDict["first_name"] as NSString
callback(first_name) // << here you call the callback passing the `first_name` local variable
println(first_name)
}
}
}
and do the actual assignment to first_name in a closure you define when calling problemFunc:
PFFacebookUtils.logInWithPermissions(permissions, {
(user: PFUser!, error: NSError!) -> Void in
if user == nil {
NSLog("Uh oh. The user cancelled the Facebook login.")
} else if user.isNew {
NSLog("User signed up and logged in through Facebook!")
} else {
NSLog("User logged in through Facebook!")
problemFunc { (name: String) -> Void in
first_name = name
}
}
})