Facebook iOS SDK and swift: how get user's profile picture
Asked Answered
W

10

28

i have integrated Facebook sdk in Xcode 6 (with swift). During the login i request the public_profile permission:

FBSession.openActiveSessionWithReadPermissions(["public_profile"], allowLoginUI: true, completionHandler: {
...
...

So i request the user's information:

FBRequestConnection.startForMeWithCompletionHandler { (connection, user, error) -> Void in
...
...

Why the user object doesn't contain the profile picture? How can i get the user profile picture? It's not part of the public_profile?

I get the following information:

2015-01-25 01:25:18.858 Test[767:23804] {
"first_name" = xxx;
gender = xxx;
id = xxxxxxxxx;
"last_name" = xxxxxx;
link = "https://www.facebook.com/app_scoped_user_id/xxxxxxxxx/";
locale = "xxxxx";
name = "xxxxxxx xxxxxxx";
timezone = 1;
"updated_time" = "2013-12-21T18:45:29+0000";
verified = 1;
}

P.S: xxx for privacy

Warton answered 25/1, 2015 at 0:41 Comment(1)
For xcode 8.3.3 and swift-4(beta) use : https://mcmap.net/q/502837/-ios-facebook-graph-api-profile-picture-linkSqueak
S
64

The profile picture is in fact public and you can simply by adding the user id to Facebook's designated profile picture url address, ex:

var userID = user["id"] as NSString     
var facebookProfileUrl = "http://graph.facebook.com/\(userID)/picture?type=large"

This particular url address should return the "large" version of the user's profile picture, but several more photo options are available in the docs.

Streamlined answered 25/1, 2015 at 0:58 Comment(6)
Hi. Some months late but, may I ask... where in the docs are those photo options available? I can't seem to find them on Graph API 2.4: developers.facebook.com/docs/graph-api/reference/v2.4/user/…Aspire
@AlejandroIván The doc page I linked to now says "This document refers to an outdated version of Graph API. Please use the latest version. Graph API Version v2.2", so perhaps those photo options are no longer available in 2.4.Streamlined
That's what I thought. Surprisingly, even if not documented "officially", using type=large or another ones (I'm using width=150&height=150) seem to work just fine. Thank you!Aspire
This answer pointed me in the right direction. So, to complete my function I added this: if let data = NSData(contentsOfURL: facebookProfileUrl!) { imageProfile.image = UIImage(data: data) } Thanks @LyndseyScottWeld
Thanks @LyndseyScott - for people using this in the future, don't forget to use 'https' instead of 'http' to silence the Apple Security complaints :)Marv
simple and sweetPulsatory
R
53

If you want to get the picture in the same request as the rest of the users information you can do it all in one graph request. It's a little messy but it beats making another request.

A more Swift 3 approach

let request = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, email, picture.type(large)"])
let _ = request?.start(completionHandler: { (connection, result, error) in
    guard let userInfo = result as? [String: Any] else { return } //handle the error

    //The url is nested 3 layers deep into the result so it's pretty messy
    if let imageURL = ((userInfo["picture"] as? [String: Any])?["data"] as? [String: Any])?["url"] as? String {
        //Download image from imageURL
    }
})

Swift 2

let request = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, email, picture.type(large)"])
request.startWithCompletionHandler({ (connection, result, error) in
    let info = result as! NSDictionary
    if let imageURL = info.valueForKey("picture")?.valueForKey("data")?.valueForKey("url") as? String {
        //Download image from imageURL
    }
})
Rubenstein answered 10/5, 2016 at 21:28 Comment(0)
S
25

With Facebook SDK 4.0, you can use:

Swift:

    let pictureRequest = FBSDKGraphRequest(graphPath: "me/picture?type=large&redirect=false", parameters: nil)
    pictureRequest.startWithCompletionHandler({
        (connection, result, error: NSError!) -> Void in
        if error == nil {
            println("\(result)")
        } else {
            println("\(error)")
        }
    })

Objective-C:

FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
                                  initWithGraphPath:[NSString stringWithFormat:@"me/picture?type=large&redirect=false"]
                                  parameters:nil
                                  HTTPMethod:@"GET"];
    [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection,
                                          id result,
                                          NSError *error) {
    if (!error){
       NSLog(@"result: %@",result);}
    else {
       NSLog(@"result: %@",[error description]);
     }}];
Slur answered 14/4, 2015 at 5:6 Comment(2)
this pointed me in the right direction for getting other user info things, see: #31314624Fosterfosterage
id/picture?type=normal&redirect=false worked great for me, thank you. redirect=false did wondersBackstay
R
14

Swift 4 approach :-

private func fetchUserData() {
    let graphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"id, email, name, picture.width(480).height(480)"])
    graphRequest?.start(completionHandler: { (connection, result, error) in
        if error != nil {
            print("Error",error!.localizedDescription)

        }
        else{
            print(result!)
            let field = result! as? [String:Any]
            self.userNameLabel.text = field!["name"] as? String
            if let imageURL = ((field!["picture"] as? [String: Any])?["data"] as? [String: Any])?["url"] as? String {
                print(imageURL)
                let url = URL(string: imageURL)
                let data = NSData(contentsOf: url!)
                let image = UIImage(data: data! as Data)
                self.profileImageView.image = image
            }
        }
    })
}
Rhodes answered 25/7, 2018 at 10:38 Comment(2)
your if-else statement is wrong. It should be if error == nil and you should change the codes as well.Morissa
@Morissa Its correct . if error != nil than it will print error.Rhodes
P
7

if you want get bigger picture , just replace "type = large" to width=XX&height=XX

but the biggest picture you can get is original picture

FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] 
                              initWithGraphPath:@"me/picture?width=1080&height=1080&redirect=false" 
                              parameters:nil 
                              HTTPMethod:@"GET"]; 

[request startWithCompletionHandler:^(
                            FBSDKGraphRequestConnection *connection,
                            id result, 
                            NSError *error) { 
if (!error) 
{ 
   NSLog(@"result = %@",result);
   NSDictionary *dictionary = (NSDictionary *)result; 
   NSDictionary *data = [dictionary objectForKey:@"data"]; 
   NSString *photoUrl = (NSString *)[data objectForKey:@"url"]; 
} 
else 
{ 
   NSLog(@"result = %@",[error description]); } 
}];
Peeved answered 9/7, 2015 at 6:28 Comment(0)
P
4

@Brandon Gao solution gave me a 200X200 thumbnail... To get a bigger size I used FBSDKProfile to get a path with size, that is also more modular and not hard-coded (although I did have to type in the graph.facebook.com part...)

let size = CGSize(width: 1080, height: 1080)
let path = FBSDKProfile.currentProfile().imagePathForPictureMode(.Normal, size: size)
let url = "https://graph.facebook.com/\(path)"
Alamofire.request(.GET, url, parameters: nil, encoding: ParameterEncoding.URL).response { 
    (request, response, data, error) -> Void in
    if  let imageData = data as? NSData,
        let image = UIImage(data: imageData) {
            self.buttonImage.setImage(image, forState: .Normal)
    }
}

Somehow I didn't get a 1080X1080 image though, FB gave me a 1117X1117... :\

Peale answered 20/5, 2015 at 11:16 Comment(1)
nice solution, but I needed to load the profile first: FBSDKProfile.loadCurrentProfileWithCompletionOliverolivera
P
4

For swift this is the simple way for get the url of the photo with and specific size:

    let params: [NSObject : AnyObject] = ["redirect": false, "height": 800, "width": 800, "type": "large"]
    let pictureRequest = FBSDKGraphRequest(graphPath: "me/picture", parameters: params, HTTPMethod: "GET")
    pictureRequest.startWithCompletionHandler({
        (connection, result, error: NSError!) -> Void in
        if error == nil {
            print("\(result)")


           let dictionary = result as? NSDictionary
           let data = dictionary?.objectForKey("data")
           let urlPic = (data?.objectForKey("url"))! as! String
           print(urlPic)



        } else {
            print("\(error)")
        }
    })

}
Priceless answered 21/5, 2016 at 17:9 Comment(0)
W
3

For Swift 5

First add the fields that you need

let params = ["fields": "first_name, last_name, email, picture"]

Create the graph request

let graphRequest = GraphRequest(graphPath: "me", parameters: params, tokenString: token.tokenString, version: nil, httpMethod: .get)
graphRequest.start { (connection, result, error) in }

You will get the result in json

{
  "first_name": "",
  "last_name": "",
  "picture": {
    "data": {
      "height": 50,
      "is_silhouette": false,
      "url": "",
      "width": 50
    }
  },
  "id": ""
}

According to the json response, catch the result

if let error = error {
            print("Facebook graph request error: \(error)")
        } else {
            print("Facebook graph request successful!")
            guard let json = result as? NSDictionary else { return }
            if let id = json["id"] as? String {
                print("\(id)")
            }
            if let email = json["email"] as? String {
                print("\(email)")
            }
            if let firstName = json["first_name"] as? String {
                print("\(firstName)")
            }
            if let lastName = json["last_name"] as? String {
                print("\(lastName)")
            }
            if let profilePicObj = json["picture"] as? [String:Any] {
                if let profilePicData = profilePicObj["data"] as? [String:Any] {
                    print("\(profilePicData)")
                    if let profilePic = profilePicData["url"] as? String {
                        print("\(profilePic)")
                    }
                }
            }
        }
    }

You can also get custom width profile image by sending the required width in the params

let params = ["fields": "first_name, last_name, email, picture.width(480)"]

This is how the whole code would like

if let token = AccessToken.current {
            let params = ["fields": "first_name, last_name, email, picture.width(480)"]
            let graphRequest = GraphRequest(graphPath: "me", parameters: params,
                                            tokenString: token.tokenString, version: nil, httpMethod: .get)
            graphRequest.start { (connection, result, error) in
                if let error = error {
                    print("Facebook graph request error: \(error)")
                } else {
                    print("Facebook graph request successful!")
                    guard let json = result as? NSDictionary else { return }
                    if let id = json["id"] as? String {
                        print("\(id)")
                    }
                    if let email = json["email"] as? String {
                        print("\(email)")
                    }
                    if let firstName = json["first_name"] as? String {
                        print("\(firstName)")
                    }
                    if let lastName = json["last_name"] as? String {
                        print("\(lastName)")
                    }
                    if let profilePicObj = json["picture"] as? [String:Any] {
                        if let profilePicData = profilePicObj["data"] as? [String:Any] {
                            print("\(profilePicData)")
                            if let profilePic = profilePicData["url"] as? String {
                                print("\(profilePic)")
                            }
                        }
                    }
                }
            }
        }

Check out Graph API Explorer for more fields.

Wordbook answered 14/5, 2020 at 20:54 Comment(0)
A
0

you can use this code For Swift 3.0 to get the user information

  func getFbId(){
if(FBSDKAccessToken.current() != nil){
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id,name , first_name, last_name , email,picture.type(large)"]).start(completionHandler: { (connection, result, error) in
    guard let Info = result as? [String: Any] else { return } 


    if let imageURL = ((Info["picture"] as? [String: Any])?["data"] as? [String: Any])?["url"] as? String {
        //Download image from imageURL
    }
if(error == nil){
print("result")
}
})
}
}
Alikee answered 12/2, 2018 at 11:43 Comment(0)
I
0

Thank you @Lyndsey Scott. For Kingfisher, please add enable request http to .plist file.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    <key>NSExceptionDomains</key>
    <dict>
        <key>http://graph.facebook.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
    </dict>
</dict>

Then set your user's picture profile to ImageView.

let facebookId = "xxxxxxx"
let facebookProfile: String = "http://graph.facebook.com/\(facebookId)/picture?type=large"
let url: URL = URL(string: facebookProfile)!
myImageView.kf.setImage(with: url)
Inelegance answered 20/7, 2018 at 17:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.