Can not fetch email from Facebook in Swift - swift

EDIT: The problem with this question is a bit silly. As in the answer the problem is that I have not given the parameters which I want.
I can not get through with it anymore :) What can be the problem?
func returnUserData()
{
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: nil)
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
// Process error
print("Error: \(error)")
}
else
{
print("fetched user: \(result)")
let userName : NSString = result.valueForKey("name") as! NSString
print("User Name is: \(userName)")
let userEmail : NSString = result.valueForKey("email") as! NSString
print("User Email is: \(userEmail)")
}
})
}
I call the function like that:
func loginButton(loginButton: FBSDKLoginButton!,
didCompleteWithResult result: FBSDKLoginManagerLoginResult!,
error: NSError!) {
print("User Logged In")
if ((error) != nil)
{
// 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()
}
}
}
I get the error:
My problem is about the fatal error. However, I am kindly waiting for the comments on 2nd and 3rd lines of the output. Because, I get this output every time but the app runs correctly.

You must specify the parameters for the request.
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "first_name, last_name, email"])

Related

Retrieving user email, using FBSDKLoginKit, from an account registered with phone number only: what does "email" result returns?

I'm following iOS Academy tutorial on a Chat App. In said app, when a user logs in for the first time using Facebook, i need to retrieve the associated email and store it in my database. Lurking at YT comments ( here ) i've found out that a FB account can have no associated email if it was registered with the phone number. Quoting the literal comment:
I created my facebook account without an email (only through a phone number) it still registers the authentication however the identifier is missing. It also does not send out information to the database. Incase anyone who has only a phone has tried.
Since i need to pass the retrieved email to my Firebase Realtime database, i want to handle this issue, but i would need to know what happens when i try to retrieve an email using FBSKDLoginKit API if there is no associated email.
Since my FB has an associated email, and apparently there's no way to remove it and leave the field blank, i tried to register a new FB account with my phone number. The problem is that in order to be able to run the app on test mode and log into FB, i would need to validate it on Facebook For Developers, but to log into Developers i need an associated email. So i'm at a dead end and can't test myself.
My question is: does anyone knows what the email result returns in a FB request if there is no associated email?
Here's my code, my guess is that the function hits the return in the guard block at the commented line down below, because the email is equal to nil, but from what i've read on Youtube it seems that only the Database block is skipped while the Firebase authentication succeeds. So maybe it returns an empty string, or something else.
func loginButton(_ loginButton: FBLoginButton, didCompleteWith result: LoginManagerLoginResult?, error: Error?) {
guard let token = result?.token?.tokenString else {
return
}
let facebookRequest = FBSDKLoginKit.GraphRequest(graphPath: "me",
parameters: ["fields" : "email, first_name"], tokenString: token,
version: nil,
httpMethod: .get)
facebookRequest.start { [weak self] _, result, error in
guard let result = (result as? [String: Any]), error == nil else {
self?.alertUserLoginError(message: "An error occurred while processing your request. Please try to sign in using Google.")
return
}
guard let firstName = (result["first_name"] as? String),
let email = (result["email"] as? String) else {
return
}
// Imo here the func returns cause email is equal to nil, but apparently that's not true.
// The database block is skipped, but the auth block down below is not.
DatabaseManager.shared.insertUser(with: chatUser, completion: { success in
// Doing other unrelated stuff
}
// The following block is run apparently, not sure why
let credential = FacebookAuthProvider.credential(withAccessToken: token)
FirebaseAuth.Auth.auth().signIn(with: credential) { authResult, error in
guard authResult != nil, error == nil else {
FBSDKLoginKit.LoginManager().logOut()
return
}
}
}
}
This is the database function in DatabaseManager class, called up above:
public func insertUser(with user: ChatAppUser, completion: #escaping (Bool) -> Void) {
database.child(user.safeEmail).setValue([
"first_name" : user.firstName
],
withCompletionBlock: { error, _ in
guard error == nil else {
completion(false)
return
}
completion(true)
})
}
func FacebookGETDataClicked(_ sender: Any)
{
let fbLoginManager : LoginManager = LoginManager()
fbLoginManager.logIn(permissions: ["email"], from: self) { (result, error) in
if (error == nil){
let fbloginresult : LoginManagerLoginResult = result!
let fbloginresultsss: Set<String> = fbloginresult.grantedPermissions
let arr = [String](fbloginresultsss)
if arr.count > 0 {
if(arr.contains("email"))
{
self.getFBUserData()
fbLoginManager.logOut()
}
}
}
}
}
func getFBUserData(){
var userProfileImage = String()
var useremail = String()
var userFullName = String()
var userID = String()
if((AccessToken.current) != nil){
GraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name,last_name, picture.type(large), email"]).start(completionHandler: { (connection, result, error) -> Void in
if (error == nil){
let dict = result as! [String : AnyObject]
print(dict)
if let mail = (dict["email"] as? String)
{
useremail = mail
}
if let name = (dict["name"] as? String)
{
userFullName = name
}
if let id = (dict["id"] as? String)
{
userID = id
}
if let pic = dict["picture"] as? NSDictionary
{
let profilePictureObj = pic
let datas = profilePictureObj["data"] as! NSDictionary
userProfileImage = datas["url"] as! String
}
print(userID,useremail,userFullName,userProfileImage)
}
})
}
}

FBSDKGraphRequestHandler Swift 3 error

I have tried to debug my entire app, and currently I am down to 3 errors, all the same error. I have spent hours trying to debug these last 3 errors on my own, but I haven't been successful. Of course, the 3 errors are the same, and I know once I debug one, I can debug all of them
The error is related to the Facebook SDK, specifically the FB SDK Graph Request Handler.
This is the code
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error?) {
if let error = error {
print(error.localizedDescription)
return
}
else{
let credential = FacebookAuthProvider.credential(withAccessToken: FBSDKAccessToken.current().tokenString)
// If already anon user exists link with new user
if Auth.auth().currentUser != nil{
Auth.auth().currentUser!.link(with: credential) { (user, error) in
// ...
}
}
let req = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "email,first_name, last_name, birthday, gender"], tokenString: FBSDKAccessToken.current().tokenString, version: nil, httpMethod: "GET")
req ? .start(completionHandler: {
(connection, result, error: NSError!) - > Void in
if (error == nil) {
print("result \(result)")
Auth.auth() ? .signIn(with: credential) {
(user, error) in
if error != nil {
print("Login failed. \(error)")
} else {
print("Logged in! \(user)")
FirebaseUtility.sharedInstance.setUser(user!)
let name = String.init(format: "%# %#", result.value(forKey: "first_name") as!String, result.value(forKey: "last_name") as!String)
FirebaseUtility.sharedInstance.editUserValue(name, key: "name")
if (result.object(forKey: "gender") != nil) {
let gender = result.object(forKey: "gender") as!String
FirebaseUtility.sharedInstance.editUserValue(gender.capitalized, key: "gender")
}
if (result.object(forKey: "email") != nil) {
let gender = result.object(forKey: "email") as!String
FirebaseUtility.sharedInstance.editUserValue(gender.capitalized, key: "email")
}
if self.isSignupflow == true {
FirebaseUtility.sharedInstance.sendToken()
// this user hasn't completed his profile so show him profile page
let vc: SignupViewController = SignupViewController(nibName: "SignupViewController", bundle: nil)
self.present(vc, animated: true, completion: nil)
} else {
FirebaseUtility.sharedInstance.isFirstTimeUser {
(isFirstTimeUser) in
if isFirstTimeUser {
FirebaseUtility.sharedInstance.sendToken()
// this user hasn't completed his profile so show him profile page
let vc: SignupViewController = SignupViewController(nibName: "SignupViewController", bundle: nil)
self.present(vc, animated: true, completion: nil)
} else {
// take him into app
// self.loginSuccessful()
let vc: RecordViewControllerNew = RecordViewControllerNew(nibName: "RecordViewControllerNew", bundle: nil)
vc.isBackButtonHidden = true
self.present(vc, animated: true, completion: nil)
}
}
}
}
}
}
The error that occurs is:
Cannot convert value of type '(, _, NSError!) ->Void' to expected argument type 'FBSDKGraphRequestHandler!'
and it occurs on this line of the code
req ? .start(completionHandler: {
(connection, result, error: NSError!) - > Void
Any help would be appreciated, I know once this error is solved, more errors are going to be created, but that's just how coding works :)
Thank you!
FBSDKGraphRequestHandler having optional Error? as last argument not the NSError!, so change the completion block to req?.start(completionHandler: { (connection, result, error) in from req?.start(completionHandler: { (connection, result, error: NSError!) - > Void will reduce that error.
Also after changing this you get new warning like.
Expression of type 'FBSDKGraphRequestConnection?' is unused
So simply add _ = as prefix of req?.start.
_ = req?.start(completionHandler: { (connection, result, error) in
//Add your code here
})

Get facebook user groups names

I'm looking for a way to get the names (names only) for all the groups a user is a member of. I'm not looking for publishing permissions or anything tricky. All I found online is how to get the groups a user is an admin of.
Edit
After searching some more, this is what i've got:
func returnUserData() {
let userRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: nil)
userRequest.start(completionHandler: { (connection, result, error) -> Void in
if ((error) != nil) {
// Process error
print("Error: \(error.debugDescription)")
} else {
guard let data = result as? [String:Any] else {
return
}
guard let userID = data["id"] else {
return
}
let groupsRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "\(userID)/groups", parameters: ["fields":"name"])
groupsRequest.start(completionHandler: { (connection, result, error) -> Void in
if ((error) != nil) {
// Process error
print("Error: \(error.debugDescription)")
} else {
print("\(result.debugDescription)")
}
})
}
})
}
Thing is that it doesn't work. The error is not nil but the result is 0 which is not true.
Please help :)
Thanks

Retrieve email FacebookSDK and Swift

I'm successfully implemented facebook login in my app, but I'm not able to query/retrieve the email address from the user.
I have the following code:
import UIKit
class testViewController: 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.
// Or Show Logout Button
let loginView : FBSDKLoginButton = FBSDKLoginButton()
self.view.addSubview(loginView)
loginView.center = self.view.center
loginView.readPermissions = ["public_profile", "email", "user_friends"]
loginView.delegate = self
self.returnUserData()
}
else
{
let loginView : FBSDKLoginButton = FBSDKLoginButton()
self.view.addSubview(loginView)
loginView.center = self.view.center
loginView.readPermissions = ["public_profile", "email", "user_friends"]
loginView.delegate = self
}
}
// Facebook Delegate Methods
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 {
// If you ask for multiple permissions at once, you
// should check if specific permissions missing
if result.grantedPermissions.contains("email")
{
// Do work
}
self.returnUserData()
}
}
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.
}
}
And the println output:
fetched user: {
id = 808101565906152;
name = "Marcelo Pontes Machado";
}
When I try to display the email I got a nill value.
I think the code is right, maybe some SDK that I miss to import?
Put the fields you want back from the Graph request in your parameters
FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"id,email,name,picture.width(480).height(480)"]).startWithCompletionHandler({
Because the Graph API may sometimes only return a minimum amount of information unless otherwise requested.
In Swift
if((FBSDKAccessToken.current()) != nil)
{
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, picture.type(large), email"]).start(completionHandler:
{ (connection, result, error) -> Void in
if (error == nil)
{
//everything works print the user data
// print(result!)
if let data = result as? NSDictionary
{
let firstName = data.object(forKey: "first_name") as? String
let lastName = data.object(forKey: "last_name") as? String
if let email = data.object(forKey: "email") as? String
{
print(email)
}
else
{
// If user have signup with mobile number you are not able to get their email address
print("We are unable to access Facebook account details, please use other sign in methods.")
}
}
}
})
}
In Objective C wire this code
// START_LOADING;
[[[FBSDKGraphRequest alloc] initWithGraphPath:#"me"
parameters:#{#"fields": #"picture, email,first_name,last_name"}]
startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error)
{
if (!error)
{
if ([result valueForKey:#"email"] != nil)
{
NSLog([result valueForKey:#"email"]);
}
else
{
// If user have signup with mobile number you are not able to get their email address
NSLog(#"We are unable to access Facebook account details, please use other sign in methods.");
// STOP_LOADING;
}
}
}];

Add Facebook "name" to PFUser ["fullname"] in swift

I have a registration/login method (from PFFacebookUtilsV4) that successfully adds a new PFUser object to my Parse database when a new Facebook user logs in. Within that method I make an FBSDKGraphRequest to get the basic user data (name, email). However I am having trouble adding the name and email to the newly created PFUser object. Here's my code so far:
#IBAction func facebookLogin(sender: AnyObject) {
PFFacebookUtils.logInInBackgroundWithReadPermissions(["public_profile","email","user_friends"], block: { (user: PFUser?, error: NSError?) -> Void in
if let user = user {
if user.isNew {
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"name,email,picture.width(480).height(480)"])
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
println("Error: \(error)")
ProgressHUD.showError("Error occurred.")
} else {
self.userFullName = result.valueForKey("name") as? String
println("User Name is: \(self.userFullName)")
self.userEmail = result.valueForKey("email") as? String
println("User Email is: \(self.userEmail)")
// Here I try to add the retrieved Facebook data to the PFUser object
user["fullname"] = self.userFullName
user.email = self.userEmail
self.performSegueWithIdentifier("login", sender: self)
println("User signed up and logged in through Facebook!")
ProgressHUD.showSuccess("Welcome \(self.userFullName)!")
}
})
} else {
println("User logged in through Facebook!")
ProgressHUD.showSuccess("Welcome \(self.userFullName)!")
self.performSegueWithIdentifier("login", sender: self)
}
} else {
println("User cancelled the Facebook login.")
}
})
}
Thanks! Any help is greatly appreciated.
Save the user after you add the new data inside the Facebook request closure.
user.saveEventually()
Or any other save that you prefer.