So I am following the Facebook documentation on how to add a custom login button in iOS but I am not sure if this is a documentation error or something is up with what I had written into my project. I have followed it for verbatim.
I get errors at these lines:
"Extra argument in call ["public_profile", "user_friends", "email"]"
func loginButtonClicked() {
var login: FBSDKLoginManager = FBSDKLoginManager()
FBSDKLoginManager.logInWithReadPermissions(["public_profile", "user_friends", "email"], fromViewController: self) { (result, error) -> Void in
if let result = result where error == nil && !result.isCancelled {
// Successful login
} else {
// Canceled or error
}
}
};
}
Here below is what the rest of the ViewController looks like:
class LogInViewController: UIViewController {
#IBOutlet weak var loginButton: FBSDKLoginButton!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}
override func viewDidLoad() {
["public_profile", "email", "user_friends"]
super.viewDidLoad()
// Add a custom login button to your app
let myLoginButton: UIButton = UIButton(type: .Custom)
myLoginButton.backgroundColor = UIColor.darkGrayColor()
myLoginButton.frame = CGRectMake(0, 0, 180, 40)
myLoginButton.center = self.view.center
myLoginButton.setTitle("My Login Button", forState: .Normal)
// Handle cliks on the button
myLoginButton.addTarget(self,action: "loginButtonClicked", forControlEvents: .TouchUpInside)
// Add the button to the view
self.view!.addSubview(myLoginButton)
}
// Once the button is clicked, show the login dialogue.
func loginButtonClicked() {
var login: FBSDKLoginManager = FBSDKLoginManager()
FBSDKLoginManager.logInWithReadPermissions(["public_profile", "user_friends", "email"] /*Extra argument in call is here */, fromViewController: self) { (result, error) -> Void in
if let result = result where error == nil && !result.isCancelled {
// Successful login
} else {
// Canceled or error
}
}
};
}
TL;DR what is the exact problem and what is Xcode trying to tell me?
The Error is very simple that you are not parsing Object of FBSDKLoginManager that you are creating with following line:
var login: FBSDKLoginManager = FBSDKLoginManager()
So do the code like following:
func loginButtonClicked() {
let login: FBSDKLoginManager = FBSDKLoginManager()
login.logInWithReadPermissions(["public_profile", "email", "user_friends"], fromViewController: self) { (result, error) -> Void in
if let result = result where error == nil && !result.isCancelled {
// Successful login
} else {
// Canceled or error
}
}
}
Seems like the problem is the way you call the loginWithPermissions method. You could try writing it again, let xcode autocomplete for you and then press enterfor all the parameters, so that the right code is filled in for you.
However, this is an example of how calling the method should look like
loginManager.logInWithReadPermissions(["public_profile", "user_friends", "email"], fromViewController: self) { (result, error) -> Void in
if let result = result where error == nil && !result.isCancelled
// Successful login
} else {
// Canceled or error
}
}
Hope this helps you figure out your error. Let me know if it worked out :)
Related
Within my main.storyboard I have a UIImage view which is just a generic Facebook Login Button. However, I am confused because using these generic steps
override func viewDidLoad(){
{
super.viewDidLoad()
var imageView = <# imageView #>
let tapGestureRecognizer = UITapGestureRecognizer(target:self, action:Selector("imageTapped:"))
imageView.userInteractionEnabled = true
imageView.addGestureRecognizer(tapGestureRecognizer)
}
func imageTapped(img: AnyObject)
{
// The Action
}
I am a little lost as to what The Action would be in this scenario as I need to link everything through the Facebook SDK.
In your imageTapped
func imageTapped() {
let manager = FBSDKLoginManager()
manager.logInWithReadPermissions(["public_profile"], fromViewController: self, handler: { result, error in
if error != nil {
print("process error")
} else if result.isCancelled {
print("cancelled log in")
} else {
print("logged in")
}
})
}
Been smashing my face against the wall all day trying to upgrade my app to the Firebase 3.x code.
I was having a ton of trouble with updating my original userAuth code and decided to just start from scratch. I haven't really been able to test it though because when I run the app it is calling the segue immediately upon loading the initial VC. Obviously I don't want it to do this and I don't know what is causing it.
I've tried deleting the app from the simulator and when I load it back up I get the same result.
Here is my code for the VC:
import UIKit
import FirebaseAuth
class SignInViewController: UIViewController {
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
override func viewDidAppear(animated: Bool) {
if let user = FIRAuth.auth()?.currentUser {
self.signedIn(user)
}
}
#IBAction func didTapSignIn(sender: AnyObject) {
// Sign In with credentials.
let email = emailField.text
let password = passwordField.text
FIRAuth.auth()?.signInWithEmail(email!, password: password!) { (user, error) in
if let error = error {
print(error.localizedDescription)
return
}
self.signedIn(user!)
}
}
#IBAction func didTapSignUp(sender: AnyObject) {
let email = emailField.text
let password = passwordField.text
FIRAuth.auth()?.createUserWithEmail(email!, password: password!) { (user, error) in
if let error = error {
print(error.localizedDescription)
return
}
self.setDisplayName(user!)
}
}
func setDisplayName(user: FIRUser) {
let changeRequest = user.profileChangeRequest()
changeRequest.displayName = user.email!.componentsSeparatedByString("#")[0]
changeRequest.commitChangesWithCompletion(){ (error) in
if let error = error {
print(error.localizedDescription)
return
}
self.signedIn(FIRAuth.auth()?.currentUser)
}
}
#IBAction func didRequestPasswordReset(sender: AnyObject) {
let prompt = UIAlertController.init(title: nil, message: "Email:", preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction.init(title: "OK", style: UIAlertActionStyle.Default) { (action) in
let userInput = prompt.textFields![0].text
if (userInput!.isEmpty) {
return
}
FIRAuth.auth()?.sendPasswordResetWithEmail(userInput!) { (error) in
if let error = error {
print(error.localizedDescription)
return
}
}
}
prompt.addTextFieldWithConfigurationHandler(nil)
prompt.addAction(okAction)
presentViewController(prompt, animated: true, completion: nil);
}
func signedIn(user: FIRUser?) {
MeasurementHelper.sendLoginEvent()
AppState.sharedInstance.displayName = user?.displayName ?? user?.email
AppState.sharedInstance.photoUrl = user?.photoURL
AppState.sharedInstance.signedIn = true
NSNotificationCenter.defaultCenter().postNotificationName(Constants.NotificationKeys.SignedIn, object: nil, userInfo: nil)
performSegueWithIdentifier(Constants.Segues.SignInToFp, sender: nil)
}
}
Can someone please help? Thank you in advance.
I have an iPad app and its used in a hotel for guests. So multiple users use the app through Facebook login and after the usage I need to logout the user from the app. So the next user will have the login screen again. I'm doing this in logout process and when I call the login function Its not giving the login screen. Instead it give me the already authorized screen. (With ok and cancel button). Please help to resolve this issue.
To login:
FBSDKLoginManager().logInWithReadPermissions(["email", "public_profile"], fromViewController: self, handler: { (result, error) -> Void in
if error != nil {
print("error : \(error.localizedDescription)")
} else if result.isCancelled {
print("user cancelled")
} else {
print("success")
}
})
To Logout :
FBSDKLoginManager().logOut()
FBSDKAccessToken.setCurrentAccessToken(nil)
FBSDKProfile.setCurrentProfile(nil)
let storage = NSHTTPCookieStorage.sharedHTTPCookieStorage()
for cookie in storage.cookies! {
storage.deleteCookie(cookie)
}
NSUserDefaults.standardUserDefaults().synchronize()
It will always give you an already authorized screen because Facebook is not responsible to logout from the Safari browser.
You are logged out from the login manager it is fine.
For this situation you can use the loginBehavior property of FBSDKLoginManager
You have to set the behavior to the Web it will open popup to login.
let fbManager : FBSDKLoginManager = FBSDKLoginManager()
fbManager.loginBehavior = FBSDKLoginBehavior.Web
fbManager.logInWithReadPermissions(["email"], fromViewController: self) { (result, error) -> Void in
if error != nil {
print(error)
}
else {
print(result)
}
}
You can do the logout from the manager as per your need.
Hope it will help you.
clear your facebook token from ios like this... this make user to login every time in app
ACAccountStore *store = [[ACAccountStore alloc] init];
NSArray *fbAccounts = [store accountsWithAccountType:[store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook]];
for (ACAccount *fb in fbAccounts) {
[store renewCredentialsForAccount:fb completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) {
}];
}
This works for me
For objective-C
1st Define
#property(nonatomic,strong)FBSDKLoginManager *login;
Then Use this method.
-(void)logoutFromFacebook{
if(self.login){
[self.login logOut];
}else{
self.login = [[FBSDKLoginManager alloc] init];
[self.login logOut];
}
}
For Swift
var login: FBSDKLoginManager?
func FBSDKLoginManager () {
if self.login != nil {
self.login.logout()
}else {
self.login = self.login()
self.login.logout()
}
}
Hope this will help.
Here is a working solution using their custom button class FBSDKLoginButton on a view. You should only enter the protected page on view will appear if the currentAccessToken is not nil. This will prevent showing the first view for a few miliseconds. As you can see, I embeded my viewControllers in a NaviguationController.
UIView with custom class in the login view :
ViewWillAppear :
override func viewWillAppear(animated: Bool) {
super.viewDidAppear(animated)
if (FBSDKAccessToken.currentAccessToken() != nil) {
loginFacebook(FBSDKAccessToken.currentAccessToken().tokenString,
userId: FBSDKAccessToken.currentAccessToken().userID)
self.enterProtectedPage();
}
}
ViewDidLoad :
override func viewDidLoad() {
super.viewDidLoad()
loginBtn.delegate = self
loginBtn.readPermissions = ["public_profile", "email", "user_birthday", "user_relationship_details"];
}
login button click action :
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
if (error != nil) {
print(error.localizedDescription)
return
}
if let _ = result.token {
loginFacebook(FBSDKAccessToken.currentAccessToken().tokenString,
userId: FBSDKAccessToken.currentAccessToken().userID)
self.enterProtectedPage();
}
}
enter protected page :
func enterProtectedPage() {
let protectedPage = self.storyboard?.instantiateViewControllerWithIdentifier("ProtectedPageViewController") as!
ProtectedPageViewController
let protectedPageNav = UINavigationController(rootViewController: protectedPage)
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = protectedPageNav
}
logout action on the protected page :
#IBAction func btnLogoutClicked(sender: AnyObject) {
let loginManager = FBSDKLoginManager()
loginManager.logOut()
let loginPage = self.storyboard?.instantiateViewControllerWithIdentifier("ViewController") as!ViewController
let loginPageNav = UINavigationController(rootViewController: loginPage)
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = loginPageNav
}
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.
I am using Xcode, Swift, and Parse. When I try and logout a PFUser, i never get a return of nil.
In this part of the app, the viewController is simply showing a few buttons one logs in. One sends the user to signup. One sends the user to change details, and one is a simple logout.
The code for the two that matter on logout is;
#IBAction func logout(sender: AnyObject) {
PFUser.logOut()
var currentUser = PFUser.currentUser()
self.displayAlert("You are now logged out", error: "")
println(currentUser!)
}
#IBAction func changeDetails(sender: AnyObject) {
var currentUser = PFUser.currentUser()
println(currentUser!)
if currentUser != nil {
let nextView30 = self.storyboard?.instantiateViewControllerWithIdentifier("changeDetails") as! changeUserDetailsViewController
self.navigationController?.pushViewController(nextView30, animated: true)
} else {
self.displayAlert("Please log in", error: "")
}
}
Once the code runs and I logout, wherever the currentUser gets read I get the following type of response, not nil. The next ViewController is actioned, and this shouldn't happen without a usr logged in.
PFUser: 0x37018fbc0, objectId: new, localId: local_3b5eb7453f9af5ed {
}
Am I doing something wrong or is this standard?
If it is correct, how do I return no user logged in?
Thanks
if PFUser.currentUser()!.username != nil
{
self.performSegueWithIdentifier("loginSegue", sender: self)
}
The above code worked for the login issue. But i still have the logout issue. After I call PFUser.logout(), PFUser.currentUser() is not becoming nil. Any help?
Thanks
I've been struggling with logging out for a little while and I believe I have finally cracked it!
No matter what I did, when I used "PFUser.logOut()" would never set "PFUser.currentUser()" to nil, but it would set "PFUser.currentUser()!.username" to nil...
Because of this I used
var currentUser = PFUser.currentUser()!.username
as a global variable to track is a user is logged in.
On my login/first page I added
override func viewDidAppear(animated: Bool) {
if currentUser != nil {
self.performSegueWithIdentifier("login", sender: self)
}
}
and finally on my logout button i used
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "logout" {
PFUser.logOut() //Log user out
currentUser = PFUser.currentUser()!.username //Reset currentUser variable to nil
}
}
I hope that helps!
Try commenting out the following line of code in your AppDelegate.swift file -
PFUser.enableAutomaticUser()
enableAutomaticUser() will log in an anonymous user once you call PFUser.logOut(), and the username for an anonymous user is nil.
override func viewDidLoad(animated: Bool) {
var currentUser = PFUser.currentUser()?.username
if(currentUser != nil){
var loginAlert: UIAlertController = UIAlertController(title: "Signup/ Login", message:"Please Signup or Login" , preferredStyle: UIAlertControllerStyle.Alert)
loginAlert.addTextFieldWithConfigurationHandler({
textfield in
textfield.placeholder = "Your Username"
})
loginAlert.addTextFieldWithConfigurationHandler({
textfield in
textfield.placeholder = "Your Password"
textfield.secureTextEntry = true
})
loginAlert.addAction(UIAlertAction(title: "Login", style: UIAlertActionStyle.Default, handler: {alertAction in
let textFields: NSArray = loginAlert.textFields! as NSArray
let usernameTextFields: UITextField = textFields.objectAtIndex(0) as! UITextField
let passwordTextFields: UITextField = textFields.objectAtIndex(1) as! UITextField
PFUser.logInWithUsernameInBackground(usernameTextFields.text as String!, password: passwordTextFields.text as String!){
(loggedInuser: PFUser?, signupError: NSError?) -> Void in
if((loggedInuser) != nil){
println("User logged in successfully")
}else{
println("User login failed")
}
}
}))
loginAlert.addAction(UIAlertAction(title: "SignUp", style: UIAlertActionStyle.Default, handler: {alertAction in
let textFields: NSArray = loginAlert.textFields! as NSArray
let usernameTextFields: UITextField = textFields.objectAtIndex(0) as! UITextField
let passwordTextFields: UITextField = textFields.objectAtIndex(1) as! UITextField
var sweeter : PFUser = PFUser()
sweeter.username = usernameTextFields.text
sweeter.password = passwordTextFields.text
sweeter.signUpInBackgroundWithBlock {(sucess,error) -> Void in
if !(error != nil){
println("sign up success")
}else
{
println("constant error string\(error)")
}
}
}))
self.presentViewController(loginAlert, animated: true, completion: nil)
}
}