I am only experiencing this issue after uploaded test builds to iTunes Connect, but not on any of my development builds.
Are there any "gotchas" that could be causing things to behave differently when the code itself is identical between the development and iTunes Connect builds?
What happens is the user presumably silently logs into Facebook fine, but then upon certain calls to our API, which only pass our API Token and do nothing with Facebook, the app then hits this line (couldn't use debugger, so had to use the alert to show the problem for iTunesConnect builds):
//let alert = UIAlertView(title: "Setup Guest Acct", message: "#3", delegate: nil, cancelButtonTitle: "Okay")
//alert.show()
which means what the session state became closed. So I then sign them into one of our own guest accounts. Is this behavior normal, should I try reopening the Facebook session, or something else? Any help would be greatly appreciated!
Here is the relevant Facebook code:
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.
FBAppCall.handleDidBecomeActive()
println("applicationDidBecomeActive")
}
...
func setupAppUserManagerBySigningInWithLoginFlow() {
// Whenever a person opens the app, check for a cached session
if FBSession.activeSession().state == FBSessionState.CreatedTokenLoaded {
// If there IS one, just open the session silently, w/o showing the user the login UI
println("Cached facebook token found")
FBSession.openActiveSessionWithReadPermissions(facebookSessionPermissions, allowLoginUI: false,
completionHandler: { session, state, error in
// Handler for session state changes
// This method will be called EACH time the session state changes,
// also for intermediate states and NOT just when the session open
self.sessionStateChanged(session, state: state, error: error)
}
)
} else {
// If no facebook token, check keychain info for user
println("Cached facebook token unavailable, check keychain for user")
var userID: Int? = SSKeychain.passwordForService(service, account: userIDKeychainKey) != nil ? SSKeychain.passwordForService(service, account: userIDKeychainKey).toInt() : nil
var userAPIToken: String? = SSKeychain.passwordForService(service, account: userAccessTokenKeychainKey)
var userGuestBool: String? = SSKeychain.passwordForService(service, account: userGuestBoolKeychainKey)
if userID == nil || userAPIToken == nil || userGuestBool == nil {
// If no user, then request a guest user to be created, set it up, save in keychain, save to UserManager
println("user NOT found in keychain")
//let alert = UIAlertView(title: "Setup Guest Acct", message: "#1", delegate: nil, cancelButtonTitle: "Okay")
//alert.show()
UserManager.sharedUser.setupGuestAccount()
} else {
// Got user from keychain
println("user WAS found in keychain")
if userGuestBool == userGuestBoolKeychainValueIsGuest {
// Sign them into the guest account
println("keychain user is guest")
UserManager.sharedUser.signIntoGuestAccount(userID!, userAccessToken: userAPIToken!)
} else if userGuestBool == userGuestBoolKeychainValueIsNotGuest {
// Show them the Facebook login UI and give them chance to sign in
println("keychain user is NOT guest")
FBSession.openActiveSessionWithReadPermissions(facebookSessionPermissions, allowLoginUI: true,
completionHandler: { session, state, error in
// Handler for session state changes
// This method will be called EACH time the session state changes,
// also for intermediate states and NOT just when the session open
self.sessionStateChanged(session, state: state, error: error)
}
)
} else {
println("ERROR: invalid guest bool keychain value")
}
}
}
}
...
// MARK: Facebook SDK related code
func sessionStateChanged(session: FBSession, state: FBSessionState, error: NSError!) {
// Handles ALL the session state changes in the app
// Handle the session state
// Usually the only interesting states are opened session, closed session, and failed login
if error == nil && state == FBSessionState.Open { //FBSessionStateOpen {
println("Facebook session state change: Open")
let accessTokenData = session.accessTokenData
let userFBAccessToken = accessTokenData.accessToken
println("Facebook session access token:\(userFBAccessToken)")
var userID: Int? = SSKeychain.passwordForService(service, account: userIDKeychainKey) != nil ? SSKeychain.passwordForService(service, account: userIDKeychainKey).toInt() : nil
var userAPIToken: String? = SSKeychain.passwordForService(service, account: userAccessTokenKeychainKey)
if userID != nil && userAPIToken != nil {
println("Found userID and userAPIToken from keychain, sign in with Facebook account")
println("userID from keychain:\(userID)")
println("userAPIToken from keychain:\(userAPIToken)")
println("userfbAuthToken:\(userFBAccessToken)")
if userFBAccessToken != nil {
UserManager.sharedUser.signIntoFullAccount(userID!, userAccessToken: userAPIToken!, fbAuthToken: userFBAccessToken)
} else {
// Reset all data and let user know to sign back into facebook
// The Facebook SDK session state will change to closed / login failed, and will be handled accordingly
/*
UserManager.sharedUser.deleteAllSavedUserInformation(
completion: {
let alert = UIAlertView(title: "Facebook Information Expired", message: "The Facebook login information has expired. Please restart the app and sign in again. The temporary new guest account that has been provided does not have any information from the Facebook verified account", delegate: nil, cancelButtonTitle: "Ok")
alert.show()
}
)*/
// Try to have them sign back into Facebook
FBSession.openActiveSessionWithReadPermissions(facebookSessionPermissions, allowLoginUI: true,
completionHandler: { session, state, error in
// Handler for session state changes
// This method will be called EACH time the session state changes,
// also for intermediate states and NOT just when the session open
self.sessionStateChanged(session, state: state, error: error)
}
)
}
} else {
println("UserID and userAPIToken NOT found from keychain, setup guest user")
//let alert = UIAlertView(title: "Setup Guest Acct", message: "#2", delegate: nil, cancelButtonTitle: "Okay")
//alert.show()
UserManager.sharedUser.setupGuestAccount()
}
} else if (state == FBSessionState.Closed) || (state == FBSessionState.ClosedLoginFailed) {
// was using FBSessionStateClosed and FBSessionStateClosedLoginFailed until using forked facebook iOS SDK
// If the session is closed, delete all old info and setup a guest account if the user had a full account
println("Facebook session state change: Closed/Login Failed")
if UserManager.sharedUser.guest != nil && UserManager.sharedUser.guest == false {
println("User was NOT a guest; delete all their saved info & clear facebook token, setup new guest account")
UserManager.sharedUser.deleteAllSavedUserInformation(
completion: {
//let alert = UIAlertView(title: "Setup Guest Acct", message: "#3", delegate: nil, cancelButtonTitle: "Okay")
//alert.show()
UserManager.sharedUser.setupGuestAccount()
}
)
} else {
// If user was a guest (could only occur during sign in...?) then just delete the facebook info
println("User WAS a guest; clear facebook token")
FBSession.activeSession().closeAndClearTokenInformation()
// Make sure splash screen would get closed at this point in the Login Flow
NSNotificationCenter.defaultCenter().postNotificationName(FinishedLoginFlowNotification, object: nil)
}
} else if (error != nil) {
println("Facebook session state change: Error")
// Make sure splash screen would get closed at this point in the Login Flow
NSNotificationCenter.defaultCenter().postNotificationName(FinishedLoginFlowNotification, object: nil)
var alertText: String?
var alertTitle: String?
// If the error requires people using an app to make an action outside of the app in order to recover
if FBErrorUtility.shouldNotifyUserForError(error) == true {
alertTitle = "Session Error"
alertText = FBErrorUtility.userMessageForError(error)
let alert = UIAlertView(title: alertTitle, message: alertText, delegate: nil, cancelButtonTitle: "Ok")
alert.show()
} else {
// If the user cancelled login, do nothing
if FBErrorUtility.errorCategoryForError(error) == FBErrorCategory.UserCancelled {
println("User cancelled login")
} else if FBErrorUtility.errorCategoryForError(error) == FBErrorCategory.AuthenticationReopenSession {
// If session closure outside of the app happened
alertTitle = "Session Error"
alertText = "Your Facebook current session is no longer valid. Please log in again."
let alert = UIAlertView(title: alertTitle, message: alertText, delegate: nil, cancelButtonTitle: "Ok")
alert.show()
} else {
// All other errors handled with generic message
// Get more info from the error
// TODO: figure out a way around this issue
/*
let errorMessageObject: AnyObject? = error.userInfo["com.facebook.sdk:ParsedJSONResponseKey"]?["body"]?["error"]?["message"]
if let errorMessage = errorMessageObject as? String {
alertTitle = "Something went wrong"
alertText = "Please retry. If the problem persists contact us and mention this error code: \(errorMessage)"
let alert = UIAlertView(title: alertTitle, message: alertText, delegate: nil, cancelButtonTitle: "Ok")
alert.show()
}
*/
}
}
// Clear the token for all errors
FBSession.activeSession().closeAndClearTokenInformation()
// Show the user the logged out UI
}
NSNotificationCenter.defaultCenter().postNotificationName(FacebookSessionChangeNotification, object: nil)
}
// Manages results of all the actions taken outside the app (successful login/auth or cancellation)
func application(application: UIApplication!, openURL url: NSURL!, sourceApplication: String!, annotation: AnyObject!) -> Bool {
return FBAppCall.handleOpenURL(url, sourceApplication: sourceApplication)
}
}
Related
I have a really weird bug right now. Inside my app the user is able to login with Email/Facebook/Google. This is how the bug occurs:
When I log in via Email and log out again and then use one of the Social-Logins, it logs me into the email account that I used before??? How and why is that happening? It makes absolut no sense for me.
This is for example my facebookLogin- method (google-method works pretty much the same way):
//MARK: Facebook Login
#objc func facebookButtonTapped(){
// disable button tap
self.facebookButton.isEnabled = false
let accessToken = AccessToken.current
LoginManager().logIn(permissions: ["email", "public_profile"], from: self) { (result, error) in
if error != nil {
// some FB error
Utilities.showErrorPopUp(labelContent: "Fehler beim Facebook-Login", description: error!.localizedDescription)
return
}else if result?.isCancelled == true {
// enable button tap
self.facebookButton.isEnabled = true
}else {
// successfull FB-Login
GraphRequest(graphPath: "/me", parameters: ["fields": "id, email, name"]).start { (connection, result, error) in
if error != nil {
// some FB error
Utilities.showErrorPopUp(labelContent: "Fehler beim Facebook-Login", description: error!.localizedDescription)
}else {
print(result!)
// check if user has account
guard let Info = result as? [String: Any] else { return }
let email = Info["email"] as? String
print(email!)
Auth.auth().fetchSignInMethods(forEmail: email!) { (methods, error) in
if error != nil {
// show error popUp
Utilities.showErrorPopUp(labelContent: "Fehler", description: error!.localizedDescription)
} else {
// no error -> check email adress
// enable button tap
self.facebookButton.isEnabled = true
// Email ist noch nicht registriert -> sign up
if methods == nil {
let usernameVC = self.storyboard?.instantiateViewController(withIdentifier: "UsernameVC") as! UserNameVC
usernameVC.accessToken = accessToken
usernameVC.signInOption = "facebook"
self.navigationController?.pushViewController(usernameVC, animated: true)
}
// Email is registered -> login
else {
// set user status to logged-in
UserDefaults.standard.setIsLoggedIn(value: true)
UserDefaults.standard.synchronize()
// enable button tap
self.facebookButton.isEnabled = true
// transition to Home-ViewController
self.transitionToHome()
}
}
}
}
}
}
}
}
I also tested and printed the Auth.auth().currentUser!.uid inside my HomeViewController and it is actually logging into the previous used Email-Account! Super weird...
If anyone can bring some light into this and help me out I am more than grateful!
If there is anything unclear and you need more info just let me know.
Solved the issue.. The problem was that I never actually logged the in. I just checked wether or not the user has an account. I missed to call Auth.auth().signIn
I implemented a button in my app that allows the user to change their email using Firebase.
#IBAction func resetEmail(_ sender: Any) {
let alertController = UIAlertController(title: "Change Email", message: "", preferredStyle: .alert)
alertController.addTextField { (textField : UITextField!) -> Void in
textField.placeholder = "Enter New Email Address"
let saveAction = UIAlertAction(title: "Save", style: .default, handler: { (action : UIAlertAction!) -> Void in
//Reset Email
let currentUser = Auth.auth().currentUser
if Auth.auth().currentUser != nil{
currentUser?.updateEmail(to: textField.text!) { error in
if let error = error {
print(error)
} else {
print("CHANGED")
let user = Auth.auth().currentUser
let name = user?.displayName!
let ref = Database.database().reference().child("main").child("users_sen").child(name!).child("email")
ref.setValue(textField.text!)
}
}
}
})
alertController.addAction(saveAction)
}
self.present(alertController, animated: true, completion: {
alertController.view.superview?.isUserInteractionEnabled = true
alertController.view.superview?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.alertClose(gesture:))))
})
}
However, when I run it and I try to change the email it gives me this error:
UserInfo={NSLocalizedDescription=This operation is sensitive and requires
recent authentication. Log in again before retrying this request.
and tells me to re-sign in order to change the email. How do I avoid this? How do I change the email without re-signing in?
This is how I change the password:
// Password updated.
let currentUser = Auth.auth().currentUser
currentUser?.updatePassword(to: textField.text!) { error in
if let error = error {
} else {
// Password updated.
print("success")
}
}
let userEmail = Auth.auth().currentUser?.email
self.currentPassword = textField.text!
let credential = EmailAuthProvider.credential(withEmail: userEmail!, password: textField.text!)
currentUser?.reauthenticate(with: credential) { error in
if let error = error {
// An error happened.
} else {
// User re-authenticated.
}
}
Base on Firebase's documentation, you need to re-authenticate the user when performing this type of action.
Re-authenticate a user Some security-sensitive actions—such as
deleting an account, setting a primary email address, and changing a
password—require that the user has recently signed in. If you perform
one of these actions, and the user signed in too long ago, the action
fails with an error. When this happens, re-authenticate the user by
getting new sign-in credentials from the user and passing the
credentials to reauthenticateWithCredential.
let user = Auth.auth().currentUser
let credential = EmailAuthProvider.credential(withEmail: "email", password: "password")
user?.reauthenticate(with: credential)
{ error in
if let error = error {
// An error happened.
} else {
// User re-authenticated.
user?.updateEmail(to: "newemail")
{ error in
}
}
}
To change user email without re-authentication you can also leverage Cloud Functions. An example course of action could be:
Create a function that accepts user access token and new email address as parameters
In the function, verify access token and get the user ID from it
In the function, call
admin.auth().updateUser(userId, { email: newEmail })
Call the new function from the client
Note: This solution is less secure because the user intent is not verified by additional authentication. Therefore anyone getting hold of the user's device could change their email address.
If you use email and password to authenticate a user you should to do something like this.
You have to re-authenticate user using credential
Re-authenticate user
Update email
Before don't forget to get current user in your class and import Firebase like this :
...
import Firebase
class Blabla {
...
var currentUser: User? {
return Auth.auth().currentUser
}
Then :
func updateUserEmail(newEmail: String, password: String) {
// 1. Get the credential
guard let currentEmail = currentUser?.email else {return}
var credential = EmailAuthProvider.credential(withEmail: currentEmail, password: password)
You can't get directly password, so you must ask to the user his password by a textfield or other.
// 2. Re-authenticate the user
//(To change mail or password, the user must to be authentificate a short time ago !!!)
self.currentUser?.reauthenticate(with: credential, completion: { (result, error) in
if error != nil {
print("ERROR: ", error?.localizedDescription)
return
}
//3. Update email
self.currentUser?.updateEmail(to: newEmail, completion: { (error) in
if error != nil {
print("ERROR: ", error?.localizedDescription)
}else {
//Do something, for example present an alert of confirmation..
}
})
})
All of the code in the same function from the step 1.
I'm trying to provide some very simple (as I thought) functionality into my application which uses Parse.com service. What I need is just allow users to create an account via Facebook and login them again via Facebook.
The problem is that PFFacebookUtils login methods not only login users through Facebook but also create a new PFUser. Why is it a problem for me? Well, of course. I can distinguish between signing up and in by isNew field but it doesn't really help.
Consider the following - user tries to login via Facebook (he doesn't any have PFUser yet), he loggs in, a new user is created. I see that the user is new (i.e. the user wasn't registered before) and I have to reject this login. Ok, I reject him, I say "You haven't been registered yet, go and sign up". User signs up (via the same login method) and this time the same PFUser is returned which was created when the user tried to log in. I see that the user is not new, it has already been registered and therefore I have to reject the user again, because the account already exists and it is impossible to create the same account again.
Do you understand the problem? Am I being idiotic not realizing how to deal with PFFacebookUtils account creation and logging in or it is PFFacebookUtils who provides an idiotic API? How do you people do that? How do you solve the problem that I've described. Really, it must be so simple but I can't find a good example anywhere
I have login and signup code in swift that checks to see if a user is new in login and signup. Here is my code:
LOGIN
let spinningActivity = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
spinningActivity.label.text = "Just a Moment"
spinningActivity.detailsLabel.text = "Logging in"
if reachabilityStatus == kNOTREACHABLE {
spinningActivity.hideAnimated(true)
self.displayError("No Internet Connection", message: "Please connect to the internet before continuing")
} else {
let permissions = ["public_profile"]
PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions) { (user:PFUser?, error:NSError?) -> Void in
if error != nil {
spinningActivity.hideAnimated(true)
self.displayError("Error", message: error!.localizedDescription)
} else if let user = user {
if user.isNew {
spinningActivity.hideAnimated(true)
PFUser.currentUser()?.deleteInBackground()
self.displayNoticeWithTwoActions("Account Not Found", message: "This Facebook account is not in our system. You have to sign up first.", firstButtonTitle: "Sign Up",closeButtonTitle: "Ok", segue: "dontHaveAccountSegue")
} else {
spinningActivity.hideAnimated(true)
self.performSegueWithIdentifier("successfulLoginSegue", sender: self)
}
} else {
PFUser.currentUser()?.deleteInBackground()
spinningActivity.hideAnimated(true)
self.displayError("Error", message: "Unless you tapped on 'Cancel' or 'Done', something went wrong. Please try again.")
}
}
}
SIGNUP
I have a signup button and then a function that is implemented into the login button called "loadFacebookUserDetails"
let spinningActivity = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
spinningActivity.label.text = "Just a Moment"
spinningActivity.detailsLabel.text = "Loading Details"
if reachabilityStatus == kNOTREACHABLE {
spinningActivity.hideAnimated(true)
self.displayError("No Internet Connection", message: "Please connect to the internet before continuing")
} else {
let permissions = ["public_profile", "email"]
PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions) { (user:PFUser?, error:NSError?) -> Void in
if let user = user {
if !user.isNew {
spinningActivity.hideAnimated(true)
PFUser.logOut()
self.displayNoticeWithTwoActions("Account Found", message: "This Facebook account already in our system. You have to log in first.", firstButtonTitle: "Log In", closeButtonTitle: "Cancel", segue: "haveAccountSegue")
} else if error != nil {
spinningActivity.hideAnimated(true)
self.displayError("Error", message: error!.localizedDescription)
} else if error == nil {
spinningActivity.hideAnimated(true)
self.loadFacebookUserDetails()
}
}
else {
spinningActivity.hideAnimated(true)
self.displayError("Something Went Wrong", message: "Unless you tapped on 'Cancel' or 'Done', something went wrong. Please try again")
}
}
}
func loadFacebookUserDetails() {
let spinningActivity = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
spinningActivity.mode = MBProgressHUDMode.AnnularDeterminate
spinningActivity.label.text = "Just a Moment"
spinningActivity.detailsLabel.text = "Loading Details"
let requestPerameters = ["fields": "id, email, first_name, last_name, name"]
let userDetails = FBSDKGraphRequest(graphPath: "me", parameters: requestPerameters)
userDetails.startWithCompletionHandler { (connection, result, error:NSError!) -> Void in
if error != nil {
spinningActivity.hideAnimated(true)
self.displayError("Error", message: error!.localizedDescription)
PFUser.logOut()
} else {
let userID:String = result["id"] as! String
let userEmail:String = result["email"] as! String
let userFirstName:String = result["first_name"] as! String
let userLastName:String = result["last_name"] as! String
// Get Facebook Profile Picture
let userProfile = "https://graph.facebook.com/" + userID + "/picture?type=large"
let usernameLink = "https://graph.facebook.com/" + userID
let username = usernameLink.stringByReplacingOccurrencesOfString("https://graph.facebook.com/", withString: "")
let profilePictureUrl = NSURL(string: userProfile)
let profilePictureData = NSData(contentsOfURL: profilePictureUrl!)
if profilePictureData != nil {
let profilePictureObject = PFFile(data: profilePictureData!)
PFUser.currentUser()?.setObject(profilePictureObject!, forKey: "profile_picture")
}
PFUser.currentUser()?.setObject(userFirstName, forKey: "first_name")
PFUser.currentUser()?.setObject(userLastName, forKey: "last_name")
PFUser.currentUser()?.setObject(username, forKey: "facebook_link")
if userEmail == userEmail {
PFUser.currentUser()?.email = userEmail
}
PFUser.currentUser()?.saveInBackgroundWithBlock({ (success:Bool, error:NSError?) -> Void in
if error != nil {
spinningActivity.hideAnimated(true)
self.displayError("Error", message: error!.localizedDescription)
PFUser.logOut()
} else if success == true {
if !userID.isEmpty {
spinningActivity.hideAnimated(true)
NSUserDefaults.standardUserDefaults().setObject("authData", forKey: "facebookAuth")
NSUserDefaults.standardUserDefaults().synchronize()
self.performSegueWithIdentifier("facebookUserDetailsSegue", sender: self)
}
} else {
spinningActivity.hideAnimated(true)
self.displayError("Something Went Wrong", message: "Please try again")
PFUser.logOut()
}
})
}
}
}
If you have trouble with the conversion to objective c, I bet you can find YouTube videos on how to do this.
I am using email + password authentication with Firebase for my app. Login works, and I use observeAuthEventWithBlock to check if a user is logged in - in order not to bring up the Login page. If I press the home button and open the app again, there is no problem. The problem I am having is if I force-quit the app. When I re-open, I have to log-in again.
Some notes about the setup before I show my login code.
There is a LoginViewController - not embedded - built w/ Storyboard
This is connected to a Navigation Controller
Which is what the first screen is embedded in, and the rest of the app uses this Nav Controller.
Login code:
#IBAction func loginButtonPressed() {
let userEmail = emailTextField.text
self.ref.authUser(self.emailTextField.text, password: self.passwordTextField.text, withCompletionBlock: { (error, auth) -> Void in
guard error == nil else {
if let errorCode = FAuthenticationError(rawValue: error.code) {
switch (errorCode) {
case .EmailTaken:
self.displayMessage("Email Error", theMessage: "This email is taken")
case .InvalidEmail:
self.displayMessage("Email Error", theMessage: "This email is invalid")
case .UserDoesNotExist:
self.displayMessage("User Error", theMessage: "A user account for email: \(userEmail!) does not exist")
case .InvalidPassword:
self.displayMessage("Password Error", theMessage: "The password is incorrect")
case .NetworkError:
self.displayMessage("Network Error", theMessage: "Seems like there's a problem with your internet connection")
default:
return
}
}
return //set Unknown Error Alert here
}
print("LOGGED IN: segue from loginButtonPressed")
self.userLoggedIn = true
print("user is logged in? \(self.userLoggedIn)")
self.performSegueWithIdentifier("loginLocaleSegue", sender: self)
})
}
Check if user is logged in - if so segue to navcon, pop it and display embedded View Controller:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if self.userLoggedIn.boolValue == true {
ref.observeAuthEventWithBlock { (authData) -> Void in
if authData != nil {
let navCon: UINavigationController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("MainNavigationController") as! UINavigationController
self.presentViewController(navCon, animated: false, completion: nil)
navCon.popViewControllerAnimated(false)
print("user is authenticated: \(authData.providerData["email"] as! String)")
print("segues from viewDidAppear")
} else {
return
}
}
}
}
I've seen questions related to Firebase auth which state that Authdata is stored in Keychain by default, which causes problems with Authdata persisting even after deletion of app, but I'm experiencing the total opposite issue. Any ideas?
From what I can tell, you're not writing "self.userLoggedIn = true" to any database, so it makes sense that it continues being "True" while you have the app on idle, but once you close the application, it then becomes nil (no value), this is because it's just chilling in the background while the app is open, but not completely closed. Try writing this to your Firebase database, as outlined in this tutorial, and see if that helps.
https://www.raywenderlich.com/109706/firebase-tutorial-getting-started
I'm trying to get user information using a custom facebook login with the Facebook SDK for iOS. I successfully log in the user but I don't know how to get access to the user information.
This is my login function:
func facebookLogin() {
if (FBSession.activeSession().state == FBSessionState.Open || FBSession.activeSession().state == FBSessionState.OpenTokenExtended)
{
// Close the session and remove the access token from the cache
// The session state handler (in the app delegate) will be called automatically
FBSession.activeSession().closeAndClearTokenInformation()
}
else
{
// Open a session showing the user the login UI
// You must ALWAYS ask for public_profile permissions when opening a session
FBSession.openActiveSessionWithReadPermissions(["public_profile", "email"], allowLoginUI: true, completionHandler: {
(session:FBSession!, state:FBSessionState, error:NSError!) in
self.sessionStateChanged(session, state: state, error: error)
})
}
}
Then when the session is open the function sessionStateChanged is called:
func sessionStateChanged(session:FBSession, state:FBSessionState, error:NSError?){
if ((error) != nil){
NSLog("Error")
FBSession.activeSession().closeAndClearTokenInformation()
}
else{
if (state == FBSessionState.Open){
//I would like to get the user token or FBGraphUser here but i don't know how
}
}
if (state == FBSessionState.Closed || state == FBSessionState.ClosedLoginFailed){
NSLog("Session Clossed")
}
if (FBErrorUtility.shouldNotifyUserForError(error) == true){
NSLog("Something went wrong")
}
else{
if (FBErrorUtility.errorCategoryForError(error) == FBErrorCategory.UserCancelled){
NSLog("User cancelled login")
}
else if (FBErrorUtility.errorCategoryForError(error) == FBErrorCategory.AuthenticationReopenSession){
NSLog("Current session is no valid")
}
}
}
Ran into the exact same problem today! I'm not sure if this is the ideal way of doing things, but this is the workaround that my colleague showed me:
FBSession.openActiveSessionWithReadPermissions(["public_profile"], allowLoginUI: false) { session, state, error in
let request = FBRequest(session: FBSession.activeSession(), graphPath: "/me")
request.startWithCompletionHandler({ (connection, result, error) -> Void in
println(result)
let birthday = result.valueForKey("birthday") as String
println("\(birthday)")
})
self.fbSessionStateChanged(session, state: state, error: error)
}
Please forgive the ugly code, I'm still very much experimenting with Swift. Hope it helps!
You can use this:
Add FBLoginViewDelegate to the class
Declare this
#IBOutlet var fbLoginView : FBLoginView!
Connect this var (fbLoginView) with a new view in your storyboard. This new view can be hidden so it wont has any effect but helping you to track the information
In your viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
//facebook login
self.fbLoginView.delegate = self
self.fbLoginView.readPermissions = ["public_profile", "email"]
}
And add this function
func loginViewFetchedUserInfo(LoginView : FBLoginView!, user: FBGraphUser){
println("User name: \(user.name)")
//THE USER WAS LOGGED
}
When the user is authenticated by facebook, returns to loginViewFetchedUserInfo method automatically by using the FBLoginViewDelegate and you can get the information with the "user" variable