I'm trying to fetch the user's fb profile pic but wasn't able to do so far. I'm trying to do something simple: the user log in with fb account and the app goes to another view where appears his name, email and profile picture. User's name and email are okay, but I can't get the picture!
The app is crashing with my actual code because apparently I'm unwrapping a nil optional value, but I don't know why it's nil.
My code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"id,email,name,picture.width(480).height(480)"])
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)")
let id = result.valueForKey("id") as! String
self.nameLabel.text = userName as String
self.emailLabel.text = userEmail as String
self.profilePic.image = self.getProfPic(id)
}
})
}
func getProfPic(fid: String) -> UIImage? {
if (fid != "") {
let imgURLString = "http://graph.facebook.com/" + fid + "/picture?type=large" //type=normal
let imgURL = NSURL(string: imgURLString)
let imageData = NSData(contentsOfURL: imgURL!)
let image = UIImage(data: imageData!) // CODE CRASHES IN HERE
return image
}
return nil
}
From your comments I understand that it crashes at the image assigning, you should be doing it with the conditional binding methodology of Swift (if let) in order to avoid unwrapping a nil optional value:
if let data = result["picture"]?["data"]
{
if let url = data["url"] as? String
{
profilePictureURL = url
}
}
Also, as you can see I am not using the valueForKey method.
Related
I try to get user id, email, picture.type(large),updated_time from Facebook SDK, I successfully get all of them but I didn't get picture gives me:
Error Cannot call value of non-function type 'Any?!'
My clear codes under below.
import UIKit
import Foundation
class LoginViewController : UIViewController, FBSDKLoginButtonDelegate {
private var fromLogin = [Login]()
#IBOutlet weak var loginButton : FBSDKLoginButton!
override func viewDidLoad() {
super.viewDidLoad()
// Check Session
if let token = FBSDKAccessToken.current(){
print(token.tokenString! as Any)
self.fetchProfile()
}
loginButton.delegate = self
loginButton.readPermissions = ["email", "public_profile"]
}
// Get Profile
func fetchProfile() {
print("fetch profile")
// Create facebook graph with fields
FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"id, name, email, picture.type(large), updated_time"]).start { (connection, result, error) in
// check error
if error != nil {
// error happen
print("Failed to start graph request: \(error?.localizedDescription)")
return
}
if let userDict = result as? NSDictionary {
let name = userDict["name"] as? String
let id = userDict["id"] as? String
let email = userDict["email"] as? String
// HERE GIVES ERROR I DIDNT GET PICTURE WITH STRING
let userPicture = userDict.objectForKey("picture")?.objectForKey("data")?.objectForKey("url") as String
print(userPicture)
print(name as Any)
print(id as Any)
print(email as Any)
}
}
}
// Delegate Method
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!){
// check error
if error != nil {
// error happen
print(error?.localizedDescription as Any)
return
}
print("Successfull login in with facebook...")
fetchProfile()
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!){
print("Log Out")
}
This line gives error;
let userPicture = userDict.objectForKey("picture")?.objectForKey("data")?.objectForKey("url") as String
Also picture object json data example here;
picture = {
data = {
"is_silhouette" = 0;
url = "https://scontent.xx.fbcdn.net/v/t1.0-1/p200x200/14067524_9513823423422249533237851_n.jpg?oh=88eb9b80abbb2342346c01de298&oe=58C5138B";
};
};
I'm using Xcode 8.1 and Swift 3.0
This requires simple parsing .. "picture" is Dictionary and so is "data". so something like below works for you
guard let userDict = result as? [String:Any] else { return }
let name = userDict["name"] as? String
let id = userDict["id"] as? String
let email = userDict["email"] as? String
if let picture = userDict["picture"] as? [String:Any] ,
let imgData = picture["data"] as? [String:Any] ,
let imgUrl = imgData["url"] as? String {
print(imgUrl)
}
Replace this
FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"id, name, email, picture.type(large), updated_time"]).start { (connection, result, error) in
with
FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"id, name, email, picture.width(500).height(500), updated_time"]).start { (connection, result, error) in
Then check this
if let imageUrl = ((dictData.value(forKey: "picture") as? NSDictionary)?.value(forKey: "data") as? NSDictionary)?.value(forKey: "url") as? NSString
{
Facebook.imagesArr.add(imageUrl)
print("Pictureasd:",Facebook.imagesArr)
}
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!)
{
FBSDKGraphRequest.init(graphPath: "me", parameters: ["fields":"first_name, last_name, picture.type(large)"]).start { (connection, result, error) -> Void in
let strFirstName: String = (result.object(forKey: "first_name") as? String)!
let strLastName: String = (result.object(forKey: "last_name") as? String)!
let strPictureURL: String = (result.object(forKey: "picture")?.object(forKey: "data")?.object(forKey: "url") as? String)!
self.lblName.text = "Welcome, \(strFirstName) \(strLastName)"
self.ivUserProfileImage.image = UIImage(data: try! Data(contentsOf: URL(string: strPictureURL)!))
}
}
Im using the latest version for Facebook SDK 4.15 and and Google Firebase to authenticate users. I'm following along the documentation here: https://firebase.google.com/docs/auth/ios/facebook-login
This is working for me.
However I would like to pull extra permissions like email from the Facebook user. I have modified the code like so:
#IBOutlet var facebookButton : FBSDKLoginButton!
override func viewDidLoad() {
/...
facebookButton.readPermissions = ["email","public_profile"]
...
}
With this I get the Facebook confirm dialog asking for email permission when authorizing my app through Facebook. So that works.
However on my callback the user's email address is always nil:
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError?) {
if let error = error {
print(error.localizedDescription)
return
}
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(FBSDKAccessToken.currentAccessToken().tokenString)
FIRAuth.auth()?.signInWithCredential(credential) { (user, error) in
// ...
if let error = error {
print(error.localizedDescription)
return
}
print("user.uid \(user!.uid)")
print("user.photoURL \(user!.photoURL)")
print("user.providerID \(user!.providerID)")
print("user.email \(user!.email)")
print("user.displayName \(user!.displayName)")
How can I pull the extra permission like email through Facebook login while using Google Firebase Authentication?
When using third party authentication, you get back an authentication token which you then use to sign a user into your app. With this token, Firebase Auth is able to extract the user's email address along with it. But for your case, if you're looking to getting the user's email address after FB logging in, you'd need to use Facebook's Graph API. You simply have to make a GraphRequest containing the info you're asking for as shown below.
Swift 2
struct FacebookPermission
{
static let ID: String = "id"
static let NAME: String = "name"
static let EMAIL: String = "email"
static let PROFILE_PIC: String = "picture"
static let LAST_NAME: String = "last_name"
static let FIRST_NAME: String = "first_name"
static let USER_FRIENDS: String = "user_friends"
static let PUBLIC_PROFILE: String = "public_profile"
}
func getFacebookData()
{
let graphRequest: FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields" : "\(FacebookPermission.NAME), \(FacebookPermission.FIRST_NAME), \(FacebookPermission.LAST_NAME), \(FacebookPermission.EMAIL), \(FacebookPermission.PROFILE_PIC).type(large)"])
graphRequest.startWithCompletionHandler { (connection: FBSDKGraphRequestConnection!, result:AnyObject!, error: NSError!) in
if error == nil
{
if let userName = result.valueForKey(FacebookPermission.NAME) as? String
{
self.currentUser.userName = userName
}
if let firstName = result.valueForKey(FacebookPermission.FIRST_NAME) as? String
{
self.currentUser.firstName = firstName
}
if let lastName = result.valueForKey(FacebookPermission.LAST_NAME) as? String
{
self.currentUser.lastName = lastName
}
if let email = result.valueForKey(FacebookPermission.EMAIL) as? String
{
self.currentUser.email = email
}
if let profilePic = result.valueForKey(FacebookPermission.PROFILE_PIC)
{
let facebookImageURL = profilePic.valueForKey("data")?.valueForKey("url") as? String
if let unwrappedURL = facebookImageURL
{
let imageData: NSData = NSData(contentsOfURL: NSURL(string: unwrappedURL)!)!
self.currentUser.profileImage = UIImage(data: imageData)!
}
}
}
else
{
print("Facebook Graph Request Error")
}
}
}
Swift 3
func getFacebookData()
{
let graphRequest: FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields" : "\(FacebookPermission.NAME), \(FacebookPermission.FIRST_NAME), \(FacebookPermission.LAST_NAME), \(FacebookPermission.EMAIL), \(FacebookPermission.PROFILE_PIC).type(large)"])
graphRequest.start { (connection: FBSDKGraphRequestConnection?, result: Any?, error: Error?) in
if error == nil
{
if let facebookData = result as? NSDictionary
{
if let userName = facebookData.value(forKey: FacebookPermission.NAME) as? String
{
self.currentUser.userName = userName
}
if let firstName = facebookData.value(forKey: FacebookPermission.FIRST_NAME) as? String
{
self.currentUser.firstName = firstName
}
if let lastName = facebookData.value(forKey: FacebookPermission.LAST_NAME) as? String
{
self.currentUser.lastName = lastName
}
if let email = facebookData.value(forKey: FacebookPermission.EMAIL) as? String
{
self.currentUser.email = email
}
if let profilePic = facebookData.value(forKey: FacebookPermission.PROFILE_PIC)
{
let facebookImageURL = ((profilePic as AnyObject).value(forKey: "data") as AnyObject).value(forKey: "url") as? String
if let unwrappedURL = facebookImageURL
{
let imageData: Data = try! Data(contentsOf: URL(string: unwrappedURL)!)
self.currentUser.profileImage = UIImage(data: imageData)!
}
}
}
}
else
{
print("Facebook Graph Request Error")
}
}
}
After grabbing their info you may go ahead and store it into your Firebase Database.
Here's more info about Facebook Permission.
Cheers mate!
I found this
Firebase only stores a list of email+password users. It doesn't store any data for users of your app that are signed with social providers (such as Facebook).
My problem boils down to this: fetch a photo URL given a photo ID. Ultimately, I need to do this for all of the photos a user of my iOS app is tagged in. I am able to get the IDs of the photos with the code:
// Create request for user's Facebook data
let request = FBSDKGraphRequest(graphPath:"me", parameters:["fields": "photos"])
request.startWithCompletionHandler {
(connection, result, error) in
if error != nil { }
else if let userData = result as? [String:AnyObject] {
let userPhotos = userData["photos"]
}
}
In the returned user data, I have access to the ID of each photo. Now, I defined a function which should (ideally) return the URL of a photo given it's ID. However, I really do not know how to correctly call the Facebook Graph API. This is what I have (note: hardcoded photo ID).
// Create request for user's Facebook data
let request = FBSDKGraphRequest(graphPath:"/{photo-id}?id=xxxxxxxxxxxxxxxxx", parameters:["fields": "link"])
request.startWithCompletionHandler {
(connection, result, error) in
if error != nil { }
else if let userData = result as? [String:AnyObject] {
let link = userData["link"]
print(link)
}
}
I'm quite confident the the graphPath parameter is wildly wrong. I made some "intelligent" guesses based on this: https://developers.facebook.com/docs/graph-api/reference/photo/
Any help you could give me would be much appreciated. Thanks!
Ok here is a simple answer, thanks for the answer above #user2585945
import UIKit
class FacePhotosViewController: UIViewController{
#IBOutlet weak var imgTest: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
if (FBSDKAccessToken.currentAccessToken() != nil)
{
print("We are good!")
}
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"photos,picture"])
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
// Process error
print("Error: \(error)")
}
else
{
print(result)
let resultdict = result.objectForKey("photos") as! NSDictionary
let data : NSArray = resultdict.objectForKey("data") as! NSArray
for i in 0..<data.count {
let valueDict : NSDictionary = data[i] as! NSDictionary
let id = valueDict.objectForKey("id") as! String
let created_time = valueDict.objectForKey("created_time") as! String
print("id: \(id) created_time: \(created_time) ")
}
}
})
let graphRequestPhoto : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "10156292340905363?type=large", parameters: ["fields":"picture, name, album, place"])
graphRequestPhoto.startWithCompletionHandler({ (connection, result, error) -> Void in
print(result)
if ((error) != nil)
{
// Process error
print("Error: \(error)")
}
else if let userData = result as? [String:AnyObject] {
let url = userData["picture"] as? String
print("link: \(url)")
let imgURL: NSURL! = NSURL(string: url!)
//lets' download profile photo
let session = NSURLSession.sharedSession()//session
let request: NSURLRequest = NSURLRequest(URL: imgURL!)//request
let dataTask = session.dataTaskWithRequest(request) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in //session calls the request
if let noerror = data {
dispatch_async(dispatch_get_main_queue()) {
let image = UIImage(data: noerror)
self.imgTest.image = image
}
}
else {
print("Error: \(error!.localizedDescription)", terminator: "")
}
}
dataTask.resume()
}
})
}
}
let requestPhotos = FBSDKGraphRequest(graphPath:id_num, parameters:["fields":"picture, name, album, place"])
Where id_num is the ID number of the Facebook photo. Very simple.
I have a profile picture which I am taking from a URL from facebook graph request that I am trying to make into a circular profile picture but it is appearing like this:
I don't want it to be pointing at the top, I just want a perfect circle.
This is my code:
#IBOutlet var imageURL: UIImageView!
func returnUserData()
{
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"id,email,name,picture.width(50).height(50)"])
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
// Process error
print("Error: \(error)")
}
else
{
print("fetched user: \(result)")
let userID : NSString = result.valueForKey("id") as! NSString
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)")
let facebookProfileUrl = "https://graph.facebook.com/\(userID)/picture?type=large"
print("\(facebookProfileUrl)")
let url = NSURL(string:facebookProfileUrl)
let data = NSData(contentsOfURL:url!)
if data == nil {
} else {
self.imageURL.layer.borderWidth=1.0
self.imageURL.layer.masksToBounds = false
self.imageURL.layer.borderColor = UIColor.whiteColor().CGColor
self.imageURL.layer.cornerRadius = 15
self.imageURL.layer.cornerRadius = self.imageURL.frame.size.height/2
self.imageURL.clipsToBounds = true
self.imageURL.image = UIImage(data:data!)
}
}
})
}
Apparently your input image isn't square. Crop the top and bottom (or extend the sides) to make it square, then the rest should work.
I have a log in system in my app swift 2.0 integrated with Facebook, I'm able to get some user informations and profile_picture.
I'm wondering how to get the cover Image from the User logged :
let requestParameters = ["fields": "id, email, first_name, last_name, name, gender, cover"]
let userDetails = FBSDKGraphRequest(graphPath: "me", parameters: requestParameters)
userDetails.startWithCompletionHandler { (connection, result, error:NSError!) -> Void in
if(error != nil)
{
print("\(error.localizedDescription)")
return
}
if(result != nil)
{
let userId:String = result["id"] as! String
let userFirstName:String? = result["first_name"] as? String
let userLastName:String? = result["last_name"] as? String
let userEmail:String? = result["email"] as? String
let userName:String? = result["name"] as? String
let userGender:String? = result["gender"] as? String
let userCover:UIImage? = result["cover"] as? UIImage
print(requestParameters)
print(userDetails)
print(userCover)
print("\(userEmail)")
let myUser:PFUser = PFUser.currentUser()!
// Save first name
if(userFirstName != nil)
{
myUser.setObject(userFirstName!, forKey: "firstNameColumn")
}
//Save last name
if(userLastName != nil)
{
myUser.setObject(userLastName!, forKey: "lastNameColumn")
}
// Save email address
if(userEmail != nil)
{
myUser.setObject(userEmail!, forKey: "email")
}
// Save email address
if(userGender != nil)
{
if (userGender == "male"){
myUser.setObject("Masculino", forKey: "genderColumn")
} else {
myUser.setObject("Feminino", forKey: "genderColumn")
}
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// Get Facebook profile picture
let userProfile = "https://graph.facebook.com/" + userId + "/picture?type=large"
let profilePictureUrl = NSURL(string: userProfile)
let profilePictureData = NSData(contentsOfURL: profilePictureUrl!)
if(profilePictureData != nil)
{
let profileFileObject = PFFile(data:profilePictureData!)
myUser.setObject(profileFileObject!, forKey: "photoUserColumn")
}
myUser.saveInBackgroundWithBlock({ (success:Bool, error:NSError?) -> Void in
if(success)
{
print("User details are now updated")
}
})
}
This code its not working just for the cover Image.
Any ideas?
Here's a working example using fb sdk in swift. I posted this answer in the other question as well but because this answer came up first for me on google I thought it'll be nice to put it here as well.
I needed to get the cover photo of a page so in the graphPath I used page id. This parameter can be easily changed to fit users / events / etc...
let request = FBSDKGraphRequest(graphPath: "\\(page.id)?fields=cover", parameters: [
"access_token": "your_access_token"
], HTTPMethod: "GET")
request.startWithCompletionHandler({(connection , result , error) in
if ((error) != nil) {
print("Error in fetching cover photo for \\(page.id): \(error)", terminator: "")
}
else {
if let data = result["cover"] as? NSDictionary {
self.fetchImageFromUrl(data["source"] as! String, cb: {(image: UIImage) -> Void in
//do something with image
})
}
})
func fetchImageFromUrl(url: String, cb: (UIImage) -> Void) {
let urlObj = NSURL(string: url)!
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let data = NSData(contentsOfURL: urlObj)
dispatch_async(dispatch_get_main_queue(), {
let image = UIImage(data: data!)!
cb(image)
});
}
}
P.S - I'm a newbie in swift / ios so this code might not be the best. Comments will be appreciated.
It can be useful.
let emailRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"email,name, id,cover"], tokenString: result?.token.tokenString, version: nil, httpMethod: "GET")
_ = emailRequest?.start(completionHandler: { (nil, resultParameters, error) in
if(error == nil) {
if let cover = (params?["cover"] as? NSDictionary)["source"]{
var coverUrl = cover as? String
}
}
})