Hello i am trying to retrieve my email from facebook as i am playing the facebook ios sdk using swift. IOS platform is 10, swift 3 and Xcode 8. I followed tutorials online but having trouble retrieving email.
below is my code:
if FBSDKAccessToken.current() == nil {
print("I got token")
let fbButton = FBSDKLoginButton()
fbButton.readPermissions = ["public_profile", "email", "user_friends"]
view.addSubview(fbButton)
fbButton.center = view.center
fbButton.delegate = self
self.fetchprofile()
}
else {
print("Dont have token")
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!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if error != nil {
print(error.localizedDescription)
return
}
print("I'm in")
fetchprofile()
}
func fetchprofile() {
print("Getting profile")
let parameters = ["fields": "email"]
let graphRequest:FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: parameters, httpMethod: "GET")
graphRequest.start(completionHandler: {(connection, result, error) -> Void in
if error != nil {
print("Error retrieving details: \(error?.localizedDescription)")
return
}
guard let result = result as? [String:[AnyObject]], let email = result["email"] else {
return
}
print("Email: \(email)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")
self.view.backgroundColor = UIColor.red
})
}
and in my appdelegate.swift file :
//have both google and facebook signin. Google works but facebook doesn't
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return GIDSignIn.sharedInstance().handle(url,
sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String,
annotation: options[UIApplicationOpenURLOptionsKey.annotation]) ||
FBSDKApplicationDelegate.sharedInstance().application(app, open: url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String, annotation: options[UIApplicationOpenURLOptionsKey.annotation])
}
I am able to log in and log out but not able to retrieve email.
UPDATE Actually when i actually pass print(email) i can see it on the console as an optional statement. I'm having trouble displaying it without optional statment
I have solved the problem in this way:
func fetchProfile(){
FBSDKGraphRequest(graphPath: "/me", parameters: ["fields" : "email, name, id, gender"])
.start(completionHandler: { (connection, result, error) in
guard let result = result as? NSDictionary, let email = result["email"] as? String,
let user_name = result["name"] as? String,
let user_gender = result["gender"] as? String,
let user_id_fb = result["id"] as? String else {
return
}
})
}
This solution worked well for me without the "/" in the graphPath parameter!
FBSDKGraphRequest(graphPath: "me" .....
Related
I'm trying to learn something about swift and facebook.
I integrated the SDK manually without using the pods and so far everything is ok!
I created a LogIn button by following some online guides and this works too!
Through this code located in the ViewController I can also print Id, First_Name, Last_Name and receive the ProfilePicture info :
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
class ViewController: UIViewController, FBSDKLoginButtonDelegate {
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if (error == nil) {
print("Connected")
let r = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"email,first_name,last_name,picture.type(large)"], tokenString: FBSDKAccessToken.current()?.tokenString, version: nil, httpMethod: "GET")
r?.start(completionHandler: { (test, result, error) in
if(error == nil)
{
print(result as Any)
}
})
} else
{
print(error.localizedDescription)
}
}
func loginButtonWillLogin(_ loginButton: FBSDKLoginButton!) -> Bool {
return true
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
print("Disconnected")
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let loginButton = FBSDKLoginButton()
loginButton.readPermissions = ["public_profile", "email"]
loginButton.center = self.view.center
loginButton.delegate = self
self.view.addSubview(loginButton)
}
}
The OutPut is this :
Optional({
email = "cxxxxxxxxx2#live.it";
"first_name" = Cxxxxxe;
id = 10xxxxxxxxxxxxx75;
"last_name" = Lxxxxxo;
picture = {
data = {
height = 200;
"is_silhouette" = 0;
url = "https://platform-lookaside.fbsbx.com/platform/profilepic/?asid=10xxxxxxxxxxxxx75&height=200&width=200&ext=1565467901&hash=AeQ-NalWNEMh91CK";
width = 200;
};
};
})
Now I don't know how to extract a single information such as the first_name in a variable to be able to print it in a label or take the url of the image to print it in the app.
if I try to change inside the login function like this :
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if (error == nil) {
print("Connected")
let r = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"email,first_name,last_name,picture.type(large)"], tokenString: FBSDKAccessToken.current()?.tokenString, version: nil, httpMethod: "GET")
r?.start(completionHandler: { (test, result, error) in
if(error == nil)
{
print(result!["first_name"] as Any)
}
})
} else
{
print(error.localizedDescription)
}
}
the compiler tells me : "Value of type 'Any' has no subscripts".
How can i do this?
Thanks ;)
in the result you should put
result.user
and that object is the one that contains the properties like displayName, or firstName for this matter
I created the labels and for now I solved it this way:
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if (error == nil) {
print("Connected")
let r = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"email,first_name,last_name,picture.type(large)"], tokenString: FBSDKAccessToken.current()?.tokenString, version: nil, httpMethod: "GET")
r?.start(completionHandler: { (test, result, error) in
if let id : NSString = (result! as AnyObject).value(forKey: "id") as? NSString {
print("id: \(id)")
self.lbl_fbid.text = "ID: \(id)"
}
if let first_name : NSString = (result! as AnyObject).value(forKey: "first_name") as? NSString {
print("first_name: \(first_name)")
self.lbl_fbdirstname.text = "First_Name: \(first_name)"
}
if let last_name : NSString = (result! as AnyObject).value(forKey: "last_name") as? NSString {
print("last_name: \(last_name)")
self.lbl_fblastname.text = "First_Name: \(last_name)"
}
if let email : NSString = (result! as AnyObject).value(forKey: "email") as? NSString {
print("email: \(email)")
self.lbl_fbemail.text = "Email: \(email)"
}
})
} else
{
print(error.localizedDescription)
}
}
Now I just have to figure out how to take the profile pic...
All done... if someone need the code i wrote this:
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if (error == nil) {
print("Connected")
let r = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"email,first_name,last_name,picture.type(large)"], tokenString: FBSDKAccessToken.current()?.tokenString, version: nil, httpMethod: "GET")
r?.start(completionHandler: { (test, result, error) in
if let id : NSString = (result! as AnyObject).value(forKey: "id") as? NSString {
print("id: \(id)")
self.lbl_fbid.text = "ID: \(id)"
}
if let imageURL = (((((result! as AnyObject).value(forKey: "picture")) as AnyObject).value(forKey: "data")) as AnyObject).value(forKey: "url") as? NSString{
print("img url: \(imageURL)")
let url = URL(string: imageURL as String)
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
self.img_fbprofilepic.image = UIImage(data: data!)
}
}
}
if let first_name : NSString = (result! as AnyObject).value(forKey: "first_name") as? NSString {
print("first_name: \(first_name)")
self.lbl_fbdirstname.text = "First_Name: \(first_name)"
}
if let last_name : NSString = (result! as AnyObject).value(forKey: "last_name") as? NSString {
print("last_name: \(last_name)")
self.lbl_fblastname.text = "First_Name: \(last_name)"
}
if let email : NSString = (result! as AnyObject).value(forKey: "email") as? NSString {
print("email: \(email)")
self.lbl_fbemail.text = "Email: \(email)"
}
if(error == nil)
{
print(result as Any)
}
})
} else {
print(error.localizedDescription)
}
}
Hey guys actually i am trying two things here:- trying to create a new account and trying to open a screen like which appears after login but it is showing "email already exist error".
#IBAction func CreateAcccountButton(_ sender: AnyObject) {
guard let eventInterest = textBox.text,let email = EmailTestfield.text, let password = PasswordTestfield.text, let name = UsernameTestfield.text else {
print("Form is not valid")
return
}
Auth.auth().createUser(withEmail: email, password: password, completion: { (user, error) in
if let error = error {
print(error)
return
}
guard let uid = user?.uid else {
return
}
//successfully authenticated user
let imageName = UUID().uuidString
let storageRef = Storage.storage().reference().child("profile_images").child("\(imageName).png")
if let uploadData = UIImagePNGRepresentation(self.Profilepicture.image!) {
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
if let error = error {
print(error)
return
}
print (metadata)
// let downloadURL = metadata?.downloadURL()
// print("URL ", downloadURL)
if let Profilepictureurl = metadata?.downloadURL()?.absoluteString {
let values = ["name": name, "email": email,"EventInterest":eventInterest,"Password":password,"Profilepictureurl": Profilepictureurl ]
let user = User(dictionary: values as [String : AnyObject])
let customViewController = MessagesController()
customViewController.setupNavBarWithUser(user)
customViewController.fetchUserAndSetupNavBarTitle()
// customViewController.navigationItem.title = values["name"] as? String
self.dismiss(animated: true, completion: nil)
self.registeruserintoDb(uid,values: values as [String : AnyObject])
}
})
}
}
)
}
fileprivate func registeruserintoDb(_ uid: String, values: [String: AnyObject]) {
let ref = Database.database().reference()
let usersReference = ref.child("users").child(uid)
usersReference.updateChildValues(values, withCompletionBlock: { (err, ref) in
if err != nil {
print(err!)
return
}
})
}
It's exactly what the error says, you already have a user with that email. Instead, use the auth.signIn method and check for currently signed in users.
I'm trying to store facebook user data into firebase database but I keep getting the error "Cannot convert Any? to expected type String"
((FBSDKAccessToken.current()) != nil){
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, picture.type(large), email"]).start(completionHandler: { (connection, result, error) -> Void in
if (error == nil && result != nil) {
guard let fbData = result as? [String:Any] else { return }
let fbid = fbData["id"]
let name = fbData["name"]
self.ref.child("users").child(fbid).setValue([
"id": fbid,
"name": name
])
}
})
I also want to store the picture url into the database. How can I do this?
Using Facebook IOS Swift SDK and Firebase
Try my I implement this function. This is from the production app and it works well for us. I also recommend uploading profile image in Firebase storage or other storage, because after a while the profile image url is not valid.
class func getAllFacebookData(success: ((_ result: [String : Any]) -> Void)?, fail: ((_ error: Error) -> Void)?) {
guard !isGetDataFromFacebook else { return }
DispatchQueue.global(qos: .background).async {
guard let tokenString = FBSDKAccessToken.current()?.tokenString else { return }
guard let req = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "name,age_range,birthday,gender,email,first_name,last_name,picture.width(1000).height(1000),work,education,hometown,location, friends"], tokenString: tokenString, version: nil, httpMethod: "GET") else { return }
req.start { (connection, result, error) in
if error == nil {
guard let _result = result as? [String : Any] else { return }
let _picture = _result["picture"] as? [String : Any]
let _pictureData = _picture?["data"] as? [String : Any]
let _isSilhouette = _pictureData?["is_silhouette"] as? Bool
let userPref = UserDefaults.standard
userPref.set(_isSilhouette, forKey: "UserHasSilhouetteImage")
userPref.synchronize()
debugPrint("facebook result", _result)
isGetDataFromFacebook = true
syncUserInfoInDatabase(_result)
success?(_result)
} else {
debugPrint("request", error!)
fail?(error!)
}
}
}
}
fileprivate class func syncUserInfoInDatabase(_ userInfo: [String : Any]) {
let realmManager = RealmManager()
guard let currentUser = realmManager.getCurrentUser() else { return }
guard let userInfoModel = createUserInfoModel(userInfo) else { return }
do {
let realm = try Realm()
try realm.write {
currentUser.info = userInfoModel
}
} catch {
debugPrint("realm syncUserInfoInDatabase error", error.localizedDescription)
}
savePhoto(userInfo)
let firebaseDatabaseGeneralManager = FirebaseDatabaseGeneralManager()
firebaseDatabaseGeneralManager.updateCurrentUser(success: nil, fail: nil)
// crete a personal settings
let firUserSettingsDatabaseManager = FIRUserSettingsDatabaseManager()
firUserSettingsDatabaseManager.createStartPeopleFilterSettings(success: nil, fail: nil)
let userSearchLocationModel = UserSearchLocationModel()
userSearchLocationModel.userID = currentUser.id
userSearchLocationModel.birthdayTimeStamp = currentUser.birthdayTimeStamp
userSearchLocationModel.gender = currentUser.gender
switch currentUser.gender {
case UserPeopleFilterSettings.FilterGenderMode.female.description:
userSearchLocationModel.genderIndex = UserPeopleFilterSettings.FilterGenderMode.female.index
case UserPeopleFilterSettings.FilterGenderMode.male.description:
userSearchLocationModel.genderIndex = UserPeopleFilterSettings.FilterGenderMode.male.index
default: break
}
let firPeopleSearchDatabaseManager = FIRPeopleSearchDatabaseManager()
firPeopleSearchDatabaseManager.saveUserSearchLocationModel(userSearchLocationModel, success: nil, fail: nil)
}
private class func savePhoto(_ userInfo: [String : Any]) {
if let pictureDict = userInfo["picture"] as? [String : Any], let pictureDataDict = pictureDict["data"] as? [String : Any] {
if let urlPath = pictureDataDict["url"] as? String {
let firImageDatabaseManager = FIRImageDatabaseManager()
firImageDatabaseManager.saveProfileImage(urlPath, fileName: nil, isFacebookPhoto: true, realmSaved: nil)
}
}
}
I am rewriting my graph requests with the latest Swift3. I am following the guide found here - https://developers.facebook.com/docs/swift/graph.
fileprivate struct UserProfileRequest: GraphRequestProtocol {
struct Response: GraphResponseProtocol {
init(rawResponse: Any?) {
// Decode JSON into other properties
}
}
let graphPath: String = "me"
let parameters: [String: Any]? = ["fields": "email"]
let accessToken: AccessToken? = AccessToken.current
let httpMethod: GraphRequestHTTPMethod = .GET
let apiVersion: GraphAPIVersion = .defaultVersion
}
fileprivate func returnUserData() {
let connection = GraphRequestConnection()
connection.add(UserProfileRequest()) {
(response: HTTPURLResponse?, result: GraphRequestResult<UserProfileRequest.Response>) in
// Process
}
connection.start()
However, I am getting this error in the connection.add method:
Type ViewController.UserProfileRequest.Response does not conform to protocol GraphRequestProtocol.
I can't seem to figure this out what to change here. It seems like the developer guide is not up to date on Swift3, but I am not sure that is the issue.
Is anyone able to see what is wrong here?
Thanks.
Browsing on the github issues, i found a solution.
https://github.com/facebook/facebook-sdk-swift/issues/63
Facebook documentation for Swift 3.0 and SDK 0.2.0 is not yet updated.
This works for me:
let params = ["fields" : "email, name"]
let graphRequest = GraphRequest(graphPath: "me", parameters: params)
graphRequest.start {
(urlResponse, requestResult) in
switch requestResult {
case .failed(let error):
print("error in graph request:", error)
break
case .success(let graphResponse):
if let responseDictionary = graphResponse.dictionaryValue {
print(responseDictionary)
print(responseDictionary["name"])
print(responseDictionary["email"])
}
}
}
enjoy.
This code works for me, first I make a login with the correct permissions, then I build the GraphRequest for get the user information.
let login: FBSDKLoginManager = FBSDKLoginManager()
// Make login and request permissions
login.logIn(withReadPermissions: ["email", "public_profile"], from: self, handler: {(result, error) -> Void in
if error != nil {
// Handle Error
NSLog("Process error")
} else if (result?.isCancelled)! {
// If process is cancel
NSLog("Cancelled")
}
else {
// Parameters for Graph Request without image
let parameters = ["fields": "email, name"]
// Parameters for Graph Request with image
let parameters = ["fields": "email, name, picture.type(large)"]
FBSDKGraphRequest(graphPath: "me", parameters: parameters).start {(connection, result, error) -> Void in
if error != nil {
NSLog(error.debugDescription)
return
}
// Result
print("Result: \(result)")
// Handle vars
if let result = result as? [String:String],
let email: String = result["email"],
let fbId: String = result["id"],
let name: String = result["name"] as? String,
// Add this lines for get image
let picture: NSDictionary = result["picture"] as? NSDictionary,
let data: NSDictionary = picture["data"] as? NSDictionary,
let url: String = data["url"] as? String {
print("Email: \(email)")
print("fbID: \(fbId)")
print("Name: \(name)")
print("URL Picture: \(url)")
}
}
}
})
Here is my code like. I use Xcode 8, Swift 3 and it works fine for me.
let parameters = ["fields": "email, id, name"]
let graphRequest = FBSDKGraphRequest(graphPath: "me", parameters: parameters)
_ = graphRequest?.start { [weak self] connection, result, error in
// If something went wrong, we're logged out
if (error != nil) {
// Clear email, but ignore error for now
return
}
// Transform to dictionary first
if let result = result as? [String: Any] {
// Got the email; send it to Lucid's server
guard let email = result["email"] as? String else {
// No email? Fail the login
return
}
guard let username = result["name"] as? String else {
// No username? Fail the login
return
}
guard let userId = result["id"] as? String else {
// No userId? Fail the login
return
}
}
} // End of graph request
Your UserProfileRequest should look like this:
fileprivate struct UserProfileRequest: GraphResponseProtocol {
fileprivate let rawResponse: Any?
public init(rawResponse: Any?) {
self.rawResponse = rawResponse
}
public var dictionaryValue: [String : Any]? {
return rawResponse as? [String : Any]
}
public var arrayValue: [Any]? {
return rawResponse as? [Any]
}
public var stringValue: String? {
return rawResponse as? String
}
}
I have a facebook login which using firebase to authenticate the process.
However, after I input my login detail and press confirm. It will back to the login page and pop up the facebook login page again. Then I press confirm again. It will display "User Cancel Login".
I am not sure why does it happen 2 times also when i click the confirm button it will display "User Cancel Login"
func loginButton(FbLoginBtn: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
let FbloginManager = FBSDKLoginManager()
FbloginManager.logInWithReadPermissions(["email","public_profile", "user_location", "user_hometown","user_friends"],fromViewController: self, handler: { (result, error) in
if let error = error {
print(error.localizedDescription)
return
}else if(result.isCancelled) {
print("User Cancel Login")
}else{
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(FBSDKAccessToken.currentAccessToken().tokenString)
print("User\(self.user?.displayName) login successful")
AppState.instance.signedIn = true
if AppState.instance.signedIn == false{
self.firebaseLogin(credential)
//self.createFirebaseUser()
self.performSegueWithIdentifier(SEGUE_LOGIN, sender: nil)
}
}
})
}
For me this code work :
#IBAction func btnFBLoginPressed(sender: AnyObject) {
self.comeFromFB = true
let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()
var id:String = ""
var urlPhoto:String = ""
fbLoginManager.logInWithReadPermissions(["email"], fromViewController: self){ (result, error) -> Void in
if let error = error
{
print(error)
return
}
else
{
let fbloginresult : FBSDKLoginManagerLoginResult = result
if (!result.isCancelled)
{
if(fbloginresult.grantedPermissions.contains("email"))
{
if((FBSDKAccessToken.currentAccessToken()) != nil){
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, picture.type(large), email"]).startWithCompletionHandler({ (connection, result, error) -> Void in
let bUserFacebookDict = result as! NSDictionary
id = bUserFacebookDict["id"]! as! String
urlPhoto = "https://graph.facebook.com/"+id+"/picture?width=500&height=500"
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(FBSDKAccessToken.currentAccessToken().tokenString)
FIRAuth.auth()?.signInWithCredential(credential) { (user, error) in
self.currentUser.setCurrentUserState(user!.uid, _firstName: bUserFacebookDict["first_name"]! as! String, _name: bUserFacebookDict["last_name"]! as! String, _urlPhoto: urlPhoto, _email:bUserFacebookDict["email"]! as! String, _connected:true)
}
})
}
}
}
}
}
}
Then I add a listener in the ViewDidAppear method with perform segue after "connected" state.