This is my code. Help me to fetch work and institute details from my facebook account. Is i am doing something wrong?
if result.token != nil {
let profileReq = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "email, first_name,last_name,id,work,education"])
let connection = FBSDKGraphRequestConnection()
connection.addRequest(profileReq, completionHandler: { (connection, result, error) -> Void in
if error == nil {
print("Graph Request Result: \(result)")
if let email = result.valueForKey("email") as? String {
//For first name
let first_name = result.valueForKey("first_name") as! String
//For last name
let last_name = result.valueForKey("last_name") as! String
//For ID
let fb_id = result.valueForKey("id") as! String
//For Profile Picture
let profile_pic = "http://graph.facebook.com/" + fb_id + "/picture?type=large"
//For work details as Array
let wrkAr = NSMutableArray()
if let workAr = result.objectForKey("work") as? NSArray {
for i in 0..<workAr.count {
let obj = workAr.objectAtIndex(i) as! NSDictionary
var name = ""
if let employer = obj.objectForKey("employer") as? NSDictionary {
name = employer.valueForKey("name") as! String
}
var pos = ""
if let position = obj.objectForKey("position") as? NSDictionary {
pos = position.valueForKey("name") as! String
}
name = name + "_" + pos + "_" + "no"
wrkAr.addObject(name)
}
}
//For Education details as Array
let eduAr = NSMutableArray()
if let educationAr = result.objectForKey("education") as? NSArray {
for i in 0..<educationAr.count {
let obj = educationAr.objectAtIndex(i) as! NSDictionary
var name = ""
if let school = obj.objectForKey("school") as? NSDictionary {
name = school.valueForKey("name") as! String
}
name = name + "_"
eduAr.addObject(name)
}
}
Work and Education details permissions need to be reviewed by Facebook before you can get those details from the user profile. As per the docs:
user_work_history
user_education_history
If your app requests this permission Facebook will have to review how
your app uses it.
Basically you have to log into developers.facebook.com and request those permissions to be reviewed by Facebook for that specific app. Facebook will review your privacy policy and terms of use before giving you their approval. Only after that you will be able to retrieve that information from your users.
I would defensively validate the incoming value though as many people leave that empty on their Facebook profiles. Make sure you are accounting for empty/undefined values for those to 2 fields.
Related
I am using an api to get some data. The json has this data structure in one of its fields.
Here is the code to get access to my json:
let myUrl = NSURL(string:"http://openmensa.org/api/v2/canteens/\(choosenID)/days/" + currentDate + "/meals")!
URLSession.shared.dataTask(with: myUrl as URL) { (data, response, error) in
if error != nil {
print(error!)
} else {
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [[String:Any]] {
print(json)
for entry in json {
if let userId = entry["id"], let name = entry["name"], let category = entry["category"], let price = entry["prices"], let notes = entry["notes"] {
var meal = MealObject(id:userId as! Int, name:name as! String as! String, category:category as! String, price:0.0, notes: notes as! [String]);
print(price)
// DO MY OTHER STUFF...
}
}
} else {
print("JSON is not an array of dictionaries")
}
} catch let error as NSError {
print(error)
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}.resume()
print(json):
[["name": Macaroni & Cheese, "id": 2915045, "category": Tagesgericht 3, "prices": {
employees = "2.6";
others = "3.1";
pupils = "<null>";
students = "1.9";
}, "notes": <__NSArrayI 0x600000298380>(
Schwefeldioxid und Sulfite,
Senf,
Milch und Laktose,
Weizen,
Glutenhaltiges Getreide,
Alkohol,
mit Farbstoff
)
],
print(price):
{
employees = "1.9";
others = "2.4";
pupils = "<null>";
students = 1;
},
{
employees = "2.6";
others = "3.1";
pupils = "<null>";
students = "1.9";
}
I have no problem to get access to the id, the category, or the notes! The only problem are the prices.
How can I get access to this data structure? I want to save the double values to an array.
Paulw11 delivered the answer in his comment:
My unknown data structure is a dictionary inside the json.
I changed my code from this:
if let userId = entry["id"], let price = entry["prices"]
to this:
if let userId = entry["id"], let price = entry["prices"] as? [String:Any]]
Now I can use it like this:
var employer = price["employees"]
Thanks to Paulw11;)
Did you try using "SwiftyJSON" Cocoapods? If not, I would recommend installing "SwiftyJSON" .Then its as easy as shown below
let json = data
let employees = json["employees"]
let others = json["others"]
let pupils = json["pupils"]
let students = json["students"]
if you are interested, you can go through this link https://cocoapods.org/?q=swiftyjsYou may need to go through this if you don't know about cocoapods usage or installation
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).
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.
I have a custom User class which stores the phone number of the user.
class User {
let phoneNumber: String
}
How do I get the corresponding contact from the users contact book?
I tried the following but it seems like this works just for the contacts name because I'm always getting nil:
let predicate = CNContact.predicateForContactsMatchingName(userInstance.phoneNumber)
let keysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName), CNContactPhoneNumbersKey]
// Is already permitted
try! CNContactStore().unifiedContactsMatchingPredicate(predicate, keysToFetch: keysToFetch).first // This returns nil
I've searched in the docs but I didn't find a proper solution.
let contactStroe = CNContactStore()
let keysToFetch = [
CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName),
CNContactEmailAddressesKey,
CNContactPhoneNumbersKey,
CNContactImageDataAvailableKey,
CNContactThumbnailImageDataKey]
contactStroe.requestAccessForEntityType(.Contacts, completionHandler: { (granted, error) -> Void in
if granted {
let predicate = CNContact.predicateForContactsInContainerWithIdentifier(contactStroe.defaultContainerIdentifier())
var contacts: [CNContact]! = []
do {
contacts = try contactStroe.unifiedContactsMatchingPredicate(predicate, keysToFetch: keysToFetch)// [CNContact]
}catch {
}
for contact in contacts {
var phoneStr = ""
var nameStr = ""
var number: CNPhoneNumber!
if contact.phoneNumbers.count > 0 {
number = contact.phoneNumbers[0].value as! CNPhoneNumber
phoneStr = number.stringValue.stringByReplacingOccurrencesOfString("-", withString: "")
}
nameStr = contact.familyName + contact.givenName
if !nameStr.isEmpty && !phoneStr.isEmpty {
let friend = YFriendsModel()
friend.name = nameStr
friend.phone = phoneStr
self.friendArr.append(friend)
}
}
})
this is my way, you can have a test
You can't.
This is a stupid solution as a huge workaround.
Read each contact
Normalize the phone number (not the easiest thing to do!)
Cache contacts into a [String : Contact]
Then you can lookup contacts with contacts[phone_number]?
Swift 3
A nice solution, taking care also of efficiency:
func getAllContacts() {
let status = CNContactStore.authorizationStatus(for: CNEntityType.contacts) as CNAuthorizationStatus
if status == CNAuthorizationStatus.denied {
self.showAccessContactsDeniedAlert()
return
}
let contactStore = CNContactStore()
let keysToFetch = [
CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
CNContactEmailAddressesKey,
CNContactPhoneNumbersKey,
CNContactImageDataAvailableKey,
CNContactThumbnailImageDataKey] as [Any]
let request = CNContactFetchRequest(keysToFetch:keysToFetch as! [CNKeyDescriptor])
do {
try contactStore.enumerateContacts(with: request, usingBlock: { (contact:CNContact, stop:UnsafeMutablePointer<ObjCBool>) -> Void in
print(contact)
for email in contact.emailAddresses {
var dict = [String:String]()
dict["name"] = contact.familyName + contact.givenName
dict["email"] = email.value
self.allContacts.add(dict)
}
})
} catch {
//catch
}
}
In this case I save name and email into a dict and I add it to a class variable called allContacts.
Note that a contact can have more than one email, so I create a dict for any email address in this case
In Swift how do you parse the result of a fbk graph request? I have a nested dictionary and casting to [String: String] does not work. I have casted to NSDictionary which works for level 1 but anything nested started complaining about optionals and casting. I see from the changeling that FBGraphObject has been deprecated, so what is the correct approach now in SDK 4?
My data looks like
{
data = {
"is_silhouette" = 0;
url = "...";
};
}
I can do
var data = photoRes["data"] as? NSDictionary
to get
Optional({
"is_silhouette" = 0;
url = "...;
})
I'm not sure how to parse that object...
EDIT For now I have it working with
var data = photoRes["data"] as? NSDictionary
var urlStr = data!["url"] as? String
if urlStr != nil {
let url = NSURL(fileURLWithPath: urlStr!)
//my code...
}
But this is a complicated approach especially if the result coming back is highly nested. Is there a better way to go about this?
Create a dictionary :
class ViewController: UIViewController {
var dict : NSDictionary!
}
Fetching the data :
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
if (error == nil){
self.dict = result as NSDictionary
println(self.dict)
NSLog(self.dict.objectForKey("picture")?.objectForKey("data")?.objectForKey("url") as String)
}
})
}
Output should be :
{
email = "ashishkakkad8#gmail.com";
"first_name" = Ashish;
id = 910855688971343;
"last_name" = Kakkad;
name = "Ashish Kakkad";
picture = {
data = {
"is_silhouette" = 0;
url = "https://fbcdn-profile-a.akamaihd.net/hprofile-ak-xfa1/v/t1.0-1/s200x200/22501_915701971820048_9046303472199214595_n.jpg?oh=f3b3564f1450c13332b3067a135cad5d&oe=55C71792&__gda__=1443571904_c4667dcb08d85682edfd77a90ee9c3ab";
};
};
}
2015-05-25 22:12:34.015 SwiftFB[2713:7830] https://fbcdn-profile-a.akamaihd.net/hprofile-ak-xfa1/v/t1.0-1/s200x200/22501_915701971820048_9046303472199214595_n.jpg?oh=f3b3564f1450c13332b3067a135cad5d&oe=55C71792&__gda__=1443571904_c4667dcb08d85682edfd77a90ee9c3ab
This mess worked for me. I am using SWIFT 3.01 and FB Swift SDK
if let responseDictionary = response.dictionaryValue {
print(responseDictionary["name"] ?? "")
let a = responseDictionary["picture"] as! NSDictionary
let b = a["data"] as! NSDictionary
let c = b["url"]
print(c ?? "")