I couldn't find a swift doc for Facebook SDK. I'm using the latest version and I managed to retrieve name, age, mail and profile picture of the user. I can't find out how to find the hometown though.
When I try this :
conn.addRequest(req, completionHandler: { (connection: FBSDKGraphRequestConnection!, result: AnyObject!, error: NSError!) -> Void in
if(error != nil){
println(error)
} else {
let loc = result.objectForKey("hometown") // loc is nil
}
})
conn.start()
I found nil. I know that ".objectForKey("hometown")" should return a "Page" and not a "String" but I don't know how to handle a page.
Thanks for your help!
Cheers
EDIT : (thanks to Tobi)
I needed to add the user_location in login permissions and then, to find the location, I used :
let obj = result.objectForKey("location")
let location = obj.objectForKey("name") as! String
You need to make sure that the User Access Token you're using contains the user_hometown permission:
https://developers.facebook.com/docs/facebook-login/permissions#reference-user_hometown
Also, make sure that you really want the hometown and not the location (current city) of the user. The latter would be the user_location permission:
https://developers.facebook.com/docs/facebook-login/permissions#reference-user_location
Related
I'm trying to get the users first name using cloud kit however the following code is not getting the users first name and is leaving firstNameFromFunction variable empty. Does anyone know how to achieve this in iOS 10?
let container = CKContainer.default()
container.fetchUserRecordID { (recordId, error) in
if error != nil {
print("Handle error)")
}else{
self.container.discoverUserInfo(
withUserRecordID: recordId!, completionHandler: { (userInfo, error) in
if error != nil {
print("Handle error")
}else{
if let userInfo = userInfo {
print("givenName = \(userInfo.displayContact?.givenName)")
print("familyName = \(userInfo.displayContact?.familyName)")
firstNameFromFunction = userInfo.displayContact?.givenName
}else{
print("no user info")
}
}
})
}
}
the permission screen that comes up when asking for the first time, IMO, is very poorly worded. They need to change that. It says "Allow people using 'your app' to look you up by email? People who know your email address will be able to see that you use this app." This make NO sense. This has nothing to do with asking the user to get their iCloud first name, last name, email address.
Speaking of email address - this and the phone number from the lookupInfo property is missing - i.e. set to nil, even though those values are legit and correct. Filing a bug tonight.
First, you will need to request permission to access the user's information.
Then, you can use a CKDiscoverUserIdentitiesOperation. This is just like any other CKOperation (eg. the modify record operation). You just need to create a new operation with the useridentitylookupinfo. Then you will also need to create a completion block to handle the results.
Here is an example function I created:
func getUserName(withRecordID recordID: CKRecordID,
completion: #escaping (String) -> ()) {
if #available(iOS 10.0, *) {
let userInfo = CKUserIdentityLookupInfo(userRecordID: recordID)
let discoverOperation = CKDiscoverUserIdentitiesOperation(userIdentityLookupInfos: [userInfo])
discoverOperation.userIdentityDiscoveredBlock = { (userIdentity, userIdentityLookupInfo) in
let userName = "\((userIdentity.nameComponents?.givenName ?? "")) \((userIdentity.nameComponents?.familyName ?? ""))"
completion(userName)
}
discoverOperation.completionBlock = {
completion("")
}
CKContainer.default().add(discoverOperation)
} else {
// iOS 10 and below version of the code above,
// no longer works. So, we just return an empty string.
completion("")
}
}
First you need to ask the user for permission to be discovered.
Use CKContainer.default().requestApplicationPermission method passing .userDiscoverability on applicationPermission parameter.
The CKContainer.default().discoverUserInfo method is deprecated on iOS 10. Instead use CKContainer.default().discoverUserIdentity method.
Do something like:
CKContainer.default().requestApplicationPermission(.userDiscoverability) { (status, error) in
CKContainer.default().fetchUserRecordID { (record, error) in
CKContainer.default().discoverUserIdentity(withUserRecordID: record!, completionHandler: { (userIdentity, error) in
print("\(userIdentity?.nameComponents?.givenName)")
print("\(userIdentity?.nameComponents?.familyName)")
})
}
}
I have Facebook authentication integrated with parse using the following code:
PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions) {
(user: PFUser?, error: NSError?) -> Void in
if let user = user {
if user.isNew {
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: nil)
graphRequest.startWithCompletionHandler { (connection, result, error) -> Void in
user["email"] = result.valueForKey("email") as! String
user["firstName"] = result.valueForKey("first_name") as! String
user["lastName"] = result.valueForKey("last_name") as! String
user.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
// goto app
}
}
} else {
// goto app
}
} else {
// Canceled
}
}
So I use Parse's PFFacebookUtils to login the user, then add the extra fields email, firstName and lastName based on the user's Facebook info, then I log the user in. Just wondering if this is the right way to go about adding those additionals fields, and I was also wondering if there was a way to stop an email confirmation from going out in this scenario? I have a register via email option so I need email confirmation, but just not for Facebook login.
Yes as far as I know that is the correct way to set new field. Maybe you want to check for nil in the optionals instead of explicitly unwrapping like that?
And no I think every time you set the email on a PFUser it will send the authentication email if you have that option on in Parse.
One option to save the email without notifying them is to create your own emailId field and set it to that so that they don't get an email asking for authentication and when signing up a new user with email you can also set that field to be the same emailId (it is kind of messy cause you have the same value repeated) but its a workaround worth trying.
I have been trying to create an iOS app with SimpleAuth to authenticate Instagram.
In my AppDelegate.swift I have:
SimpleAuth.configuration()["instagram"] = ["client_id": "MY-CLIENT-ID", SimpleAuthRedirectURIKey: "MY-REDIRECT-URL"]
(Obviously inserting the client ID and redirect URI where needed)
And in my ViewController.swift I have:
#IBAction func instagramAuthenticate(sender: AnyObject) {
SimpleAuth.authorize("instagram", options: ["scope" : ["likes"]], completion: {
(responseObject : AnyObject!, error : NSError!) -> Void in
println("\(responseObject)")
})
}
For some reason when the user authorizes my app, the responseObject appears to return 'nil'. Possible meaning something went wrong.
I am relatively new to Swift/iOS and am not sure what I have done incorrectly. Thanks
Turned out my redirect URI was the reason it was returning nil. I changed it and everything worked perfectly! Thanks to HorseT in the comments above.
Edit: More in-depth answer below
All the following information can be found here.
Firstly, you must configure Instagram in your AppDelegate.swift
//Instagram Confifuration
SimpleAuth.configuration()["instagram"] = ["client_id": "YOUR-CLIENT-ID", SimpleAuthRedirectURIKey: "myApp://Auth/instagram"]
Make sure the SimpleAuthRedirectURIKey is equal to that in your app settings on the instagram developers page.
Next you need to authorize the user.
SimpleAuth.authorize("instagram", options: ["scope" : ["basic", "comments", "likes", "relationships"]], completion: {
(responseObject : AnyObject!, error : NSError!) -> Void in
if (responseObject != nil) {
var instagramResponse = responseObject as! NSDictionary
var accessToken : String = instagramResponse["credentials"]!["token"] as! String
println(accessToken)
} else {
println(error.localizedDescription)
}
}
This simply gets the response and prints the accessToken.
From here on you can access endpoints to retrieve further data.
Hopefully this helps!
So I've been banging my head on this for a couple days now, and I'm hoping someone here could shed some light on this for me!
So I'm using Parse in my Swift project, and am looking to leverage the Facebook integration to make logging in and signing up a user pretty effortless.
I have managed to get as far as logging in a user, but the part where I'm stuck is that I don't know how to access the data that I requested with permissions.
In my AppDelegate Swift file, I have this block of code..
// INITIALISE FACEBOOK
let permissions = ["email", "public_profile"]
PFFacebookUtils.initializeFacebook()
PFFacebookUtils.logInWithPermissions(permissions, {
(user: PFUser!, error: NSError!) -> Void in
if user == nil {
if (error == nil) {
println("User cancelled Facebook login")
} else {
println("FB Login Error \n(error)")
}
} else if user.isNew {
println("User has signed in through Facebook!")
} else {
println("User logged in through Facebook!")
}
})
Everything is all well and dandy, and I get the "User has signed in through Facebook!" message.
According to the Parse documentation, this then creates a new User object in my database.
In my database, I see that there is indeed a new user, but the only fields that are populated are..
ObjectID - random string characters
username - random string characters
authData - a facebook type ID.
Not the username or email.
From what I have gathered, I need to now further leverage the FacebookSDK and GraphUser, but I really dont know exactly how.. or at least not in Swift.
The Parse documentation says
"The Facebook iOS SDK provides a number of helper classes for interacting with Facebook's API. Generally, you will use the FBRequest class to interact with Facebook on behalf of your logged-in user. You can read more about the Facebook SDK here.
Our library manages the user's FBSession object for you. You can simply call [PFFacebookUtils session] to access the session instance, which can then be passed to FBRequests."
But I really dont know what to type or where to type it. :(
It feels like I'm really close with this, but I'm just hitting blanks..
If someone could be kind enough to shed some light into this (how to access the details I requested permission for, i.e. full name and email) I would be incredibly grateful!
Thank you.. :)
You may try this (for Swift):
// Obtain User Data via Facebook Login
func returnUserData()
{
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"name, email"])
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
// Process error
}
else
{
let userName: String = result.valueForKey("name") as! String
let Email: String = result.valueForKey("email") as! String
println(userName)
println(Email)
}
})
}
According to this: https://parse.com/questions/how-can-i-get-the-facebook-id-of-a-user-logged-in-with-facebook
You get the Facebook ID with this Objective-C
// After logging in with Facebook
[FBRequestConnection
startForMeWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
NSString *facebookId = [result objectForKey:#"id"];
}
}];
Which is this in Swift (not tested)
FBRequestConnection.startForMeWithCompletionHandler { connection, result, error in
if (!error) {
let facebookId = result["id"]
// use facebookID
}
}
Outside of asking the user to input their name, is there any way to get it off the device?
I tried this library, which attempts to extract the name from [UIDevice currentDevice] name], but that doesn't work in a lot of situations:
https://github.com/tiboll/TLLNameFromDevice
Is the user's name present in the phonebook or anywhere else that we have access to in iOS 6?
Well you could go through all the contacts in the AddressBook and see if any of them are marked with the owner flag.
Just be aware that doing this will popup the "this app wants access to the address book" message. Also Apple isn't very keen on these kind of things. In the app review guide it is specified that an app can not use personal information without the user's permission.
You could use Square's solution:
Get the device's name (e.g. "John Smith's iPhone").
Go through the contacts on the phone and look for a contact named "John Smith".
JBDeviceOwner and ABGetMe will both do this for you.
You could use CloudKit. Following a snippet in Swift (ignoring errors):
let container = CKContainer.defaultContainer()
container.fetchUserRecordIDWithCompletionHandler(
{
(recordID, error) in
container.requestApplicationPermission(
.PermissionUserDiscoverability,
{
(status, error2) in
if (status == CKApplicationPermissionStatus.Granted)
{
container.discoverUserInfoWithUserRecordID(
recordID,
completionHandler:
{
(info, error3) in
println("\(info.firstName) \(info.lastName)")
}
)
}
}
)
}
)
The above code was based on the code at http://www.snip2code.com/Snippet/109633/CloudKit-User-Info
to save folks time. in swift4:
let container = CKContainer.default()
container.fetchUserRecordID(
completionHandler: {
(recordID, error) in
guard let recordID = recordID else {
return
}
container.requestApplicationPermission(
.userDiscoverability,
completionHandler: {
(status, error2) in
if (status == CKContainer_Application_PermissionStatus.granted)
{
if #available(iOS 10.0, *) {
container.discoverUserIdentity(withUserRecordID:
recordID,
completionHandler:
{
(info, error3) in
guard let info = info else {
return
}
print("\(info.firstName) \(info.lastName)")
}
)
}
}
}
)
}
)
however: CKUserIdentity no longer exposes either first or last name
So this answer no longer works.
You can use:
NSLog(#"user == %#",[[[NSHost currentHost] names] objectAtIndex:0]);
I did receive compiler warnings that the methods +currentHost and -names were not found. Given the warning, I’m not sure of Apple’s intention to make this available (or not) as a publicly accessible API, however, everything seemed to work as expected without the need to include any additional header files or linking in additional libraries/frameworks.
Edit 1:
You may also take a look at this Link
Edit 2:
If you have integrated your app with Facebook you can easily retrieve the user info, see Facebook Fetch User Data
For SWIFT you can use
NSUserName() returns the logon name of the current user.
func NSUserName() -> String