I'm trying to get a user's country, state and city using an FBGraphObject. The returned FBGraphObject contains the following piece of information:
hometown = {
id = 112118618814985;
name = "La Paz, Bolivia";
};
(My city is called La Paz, in the country Bolivia).
This could work wonderfully, if it actually would return the "state". If someone from Wichita, Kansas in the USA, ran my app, the result would be:
hometown = {
name = "Wichita, Kansas";
};
(That person's city is Wichita, in the State of Wichita, which is in the USA... The problem is the FBGraphObject doesn't tell me, this is in the USA).
When I first saw the graph object's hometown property, I immediately thought I could work with it if I just splat the string using the coma token, to get this:
La Paz
Bolivia
Then I'd immediately know that the first object represents a city, and the second one represents a country.
But for a country like the USA, while the first element would still represent a city, the second one represents an state, and therefore, I can't store the data tokenized from there.
How could I properly get a country, state, city using the FacebookSDK for iOS? I'm scratching my head because everyone who managed to do it seemed to get it to work with PHP, but I need this to work on the iPhone itself.
EDIT: For the record, this is how I'm trying to get everything:
[FBRequestConnection startForMeWithCompletionHandler:
^(FBRequestConnection *connection, id result, NSError *error) {
if(error == nil)
{
FBGraphObject<FBGraphUser, FBGraphLocation> *graph = result;
NSLog(#"%#", graph);
[[SPAccount sharedAccount] linkFacebookAccountWithGraphObject:graph
andCompletionBlock:^(BOOL linked) {}];
}
}];
And all of the following return nil:
graph.location.country
graph.country
graph.location.location.country
you can get the location through the location property on FBGraphUser. This will give you an object that conforms to FBGraphPlace. The location property on the FBGraphPlace conformer is an object that conforms to the FBGraphLocation protocol, which has properties such as:
city
country
latitude
longitude
state
street
zip
or
import FacebookSDK/FacebookSDK.h in your code
[FBSession openActiveSessionWithReadPermissions:#[#"email",#"user_location",#"user_birthday",#"user_hometown"]
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
switch (state) {
case FBSessionStateOpen:
[[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
if (error) {
NSLog(#"error:%#",error);
}
else
{
// retrive user's details at here as shown below
NSLog(#"FB user first name:%#",user.first_name);
NSLog(#"FB user last name:%#",user.last_name);
NSLog(#"FB user birthday:%#",user.birthday);
NSLog(#"FB user location:%#",user.location);
NSLog(#"FB user username:%#",user.username);
NSLog(#"FB user gender:%#",[user objectForKey:#"gender"]);
NSLog(#"email id:%#",[user objectForKey:#"email"]);
NSLog(#"location:%#", [NSString stringWithFormat:#"Location: %#\n\n",
user.location[#"name"]]);
}
}];
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
[FBSession.activeSession closeAndClearTokenInformation];
break;
default:
break;
}
} ];
Related
I am not able to get the permissions for user_birthday and user_hometown.
I tried it with this code before but it only asks for the public profile and ignores others.
[FBSession openActiveSessionWithReadPermissions:#[#"public_profile",#"user_birthday",#"user_hometown"]
allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (error) {
NBAppDelegate* appDel = (NBAppDelegate*)`[UIApplication sharedApplication].delegate;
[appDel sessionStateChanged:session state:status error:error];
}
if ([session isOpen]) {
[self loginWithFBToken:session name:sender];
}
}];
Then someone suggested to ask for additional permissions after getting the public profile, so i even tried that to no good.
Here is the code for that
- (void)loadFbDetails
{
NSArray *permissionsNeeded = #[#"user_hometown", #"user_birthday"];
// Request the permissions the user currently has
[FBRequestConnection startWithGraphPath:#"/me/permissions"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error){
// These are the current permissions the user has:
NSDictionary *currentPermissions= [(NSArray *)[result data] objectAtIndex:0];
// We will store here the missing permissions that we will have to request
NSMutableArray *requestPermissions = [[NSMutableArray alloc] initWithArray:#[]];
// Check if all the permissions we need are present in the user's current permissions
// If they are not present add them to the permissions to be requested
for (NSString *permission in permissionsNeeded){
if (![currentPermissions objectForKey:permission]){
[requestPermissions addObject:permission];
}
}
// If we have permissions to request
if ([requestPermissions count] > 0){
// Ask for the missing permissions
[FBSession.activeSession
requestNewReadPermissions:requestPermissions
completionHandler:^(FBSession *session, NSError *error) {
if (!error) {
// Permission granted
NSLog(#"new permissions %#", [FBSession.activeSession permissions]);
// We can request the user information
[self makeRequestForUserData];
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
}
}];
} else {
// Permissions are present
// We can request the user information
[self makeRequestForUserData];
}
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
}
}];
}
-(void)makeRequestForUserData
{
[FBRequestConnection startWithGraphPath:#"me?fields=birthday,hometown"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
// Sucess! Include your code to handle the results here
NSLog(#"user events: %#", result);
} else {
NSLog(#"error: %#" , error);
}
}];
}
All it does is recursively go between my ios app and the fb native app, returning only with the public_profile in the permissions array.
Looks like i am missing something?
It should work if you're using an admin user of the app. Once you want to use the extended permissions with other users, you have to get your app reviewed by Facebook first.
See my answer here: facebook extended permission
Facebook does not allow apps to access that information by default. You have to ask permission to Facebook for you to be able to use that information. Add a video and instructions for a Facebook employee review how you're using birthday and hometown intel.
I want to get facebookid of my friends. But seems like its sending different id's
The situation is i have a friends name "abc" when i loads the friends list then i am getting following response for friend "abc" from facebook
<__NSCFArray 0xce76290>(
{
id = 668201987254085;
name = "abc";
}
)
and my facebook id is "123764734754"returned by facebook
i am using below code for this
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
SLRequest *friendsListRequest = [SLRequest requestForServiceType:SLServiceTypeFacebook
requestMethod:SLRequestMethodGET
URL:URLIFY(#"https://graph.facebook.com/me/friends")
parameters:nil];
friendsListRequest.account = facebookAccount;
[friendsListRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (responseData) {
NSLog(#"Got a response: %#", [[NSString alloc] initWithData:responseData
encoding:NSUTF8StringEncoding]);
if (urlResponse.statusCode >= 200 && urlResponse.statusCode < 300) {
NSError *jsonError = nil;
NSDictionary *friendsListData = [NSJSONSerialization JSONObjectWithData:responseData
options:NSJSONReadingAllowFragments
error:&jsonError];
if (jsonError) {
NSLog(#"Error parsing friends list: %#", jsonError);
} else {
self.userList = friendsListData[#"data"];
}
} else {
NSLog(#"HTTP %ld returned", (long)urlResponse.statusCode);
}
} else {
NSLog(#"ERROR Connecting");
}
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
});
}];
But when i am logging in using user name "abc" then for abc (current login user) i am getting different id say "10008772786278"
same thing when i login then i got my facebook id"123764734754" but when my friend "abc" login then in his friends list response they got my id "897349579554"
why this thing happen? how to get same facebook id of the user that is returned after when he login
Please Try this code.
[FBSession openActiveSessionWithReadPermissions:#[#"basic_info"] allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState state, NSError *error){
NSLog(#"Error :%#",error);
if (session.isOpen && !error) {
[FBRequestConnection startWithGraphPath:#"me/friends" parameters:nil HTTPMethod:#"GET" completionHandler:^(FBRequestConnection *connection,id result, NSError *error){
if (!error) {
NSLog(#"result %#",result);
[array_firendList addObjectsFromArray:[result valueForKey:#"data"]];
NSLog(#"count %ld",(unsigned long)[array_firendList count]);
}
}];
Facebook recently changed a lot of stuff, see here: https://developers.facebook.com/docs/apps/changelog
See "App-scoped User IDs", you don´t get the real IDs anymore:
To better protect people's information, when people log into a version
of your app that has been upgraded to use Graph API v2.0, Facebook
will now issue an app-scoped ID rather than that person's orginal ID
Also important:
The /me/friends endpoint no longer includes the full list of a
person's friends. Instead, it now returns the list of that person's
friends who are also using your app.
To make sure you always get an App Scoped ID, use /v2.0/{object} instead of /{object}. For example, to get the ID of the logged in user you can use /v2.0/me, for getting the friend list you can use /v2.0/me/friends. This is only necessary if your App is created before May 2014, if you created it later it will only use v2.0 anyway.
Another hint: make sure you get the IDs (with /me or /me/friends) on the same platform and of course with the same App, don´t compare the IDs you get with the Graph API Explorer (for example) with the ones you get in the App.
I want to fetch friend list of login user without using "FBFriendPickerViewController". So I used Graph API to do so but its not giving me the list of friends. I can login successfully and can able to fetch login user's information as well. I have followed this link https://developers.facebook.com/docs/graph-api/reference/v2.0/user/friendlists.
I have tried this code of snippet till now
-(IBAction)loginWithFacebook:(id)sender {
if (FBSession.activeSession.state == FBSessionStateOpen || FBSession.activeSession.state ==FBSessionStateOpenTokenExtended) {
// Close the session and remove the access token from the cache
// The session state handler (in the app delegate) will be called automatically
[FBSession.activeSession closeAndClearTokenInformation];
}
else {
[FBSession openActiveSessionWithPublishPermissions:#[#"publish_actions",#"manage_friendlists",#"public_profile",#"user_friends"]
defaultAudience:FBSessionDefaultAudienceEveryone
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
[self sessionStateChanged:session state:status error:error];
}];
}
}
-(void)sessionStateChanged:(FBSession *)session state:(FBSessionState) state error:(NSError *)error
{
// If the session was opened successfully
if (!error && state == FBSessionStateOpen){
NSLog(#"Session opened");
// Show the user the logged-in UI
[[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
NSLog(#"%#",user);
NSLog(#"email::: %#",[user objectForKey:#"email"]);
}];
return;
}
if (state == FBSessionStateClosed || state == FBSessionStateClosedLoginFailed){
// If the session is closed
NSLog(#"Session closed");
}
// Handle errors
if (error){
NSLog(#"Error");
NSString *alertText;
NSString *alertTitle;
// If the error requires people using an app to make an action outside of the app in order to recover
if ([FBErrorUtility shouldNotifyUserForError:error] == YES){
alertTitle = #"Something went wrong";
alertText = [FBErrorUtility userMessageForError:error];
[self showMessage:alertText withTitle:alertTitle];
} else {
// If the user cancelled login, do nothing
if ([FBErrorUtility errorCategoryForError:error] == FBErrorCategoryUserCancelled) {
NSLog(#"User cancelled login");
// Handle session closures that happen outside of the app
} else if ([FBErrorUtility errorCategoryForError:error] == FBErrorCategoryAuthenticationReopenSession){
alertTitle = #"Session Error";
alertText = #"Your current session is no longer valid. Please log in again.";
[self showMessage:alertText withTitle:alertTitle];
} else {
//Get more error information from the error
NSDictionary *errorInformation = [[[error.userInfo objectForKey:#"com.facebook.sdk:ParsedJSONResponseKey"] objectForKey:#"body"] objectForKey:#"error"];
// Show the user an error message
alertTitle = #"Something went wrong";
alertText = [NSString stringWithFormat:#"Please retry. \n\n If the problem persists contact us and mention this error code: %#", [errorInformation objectForKey:#"message"]];
[self showMessage:alertText withTitle:alertTitle];
}
}
// Clear this token
[FBSession.activeSession closeAndClearTokenInformation];
}
}
Now after login I tried to fetch friend list for that I have written
- (IBAction)fetchFrinds:(id)sender {
[FBRequestConnection startWithGraphPath:#"/me/friendlists"
parameters:#{#"fields": #"id,name"}
HTTPMethod:#"GET"
completionHandler:^(
FBRequestConnection *connection,
id result,
NSError *error
) {
NSLog(#"%#",result);
}];
}
As per the Facebook Graph API 2.0 docs on Friendlists:
/{user-id}/friendlists
A person's 'friend lists' - these are groupings of friends such as "Acquaintances" or "Close Friends", or any others that may have been created. They do not refer to the list of friends that a person has, which is accessed instead through the /{user-id}/friends edge.
So, with your current request, you're getting the friend-lists rather than the list of friends.
For getting a list of friends, you need to refer to:
Facebook Graph API 2.0 docs on List of Friends
NOTE:
Facebook seems to have changed it's implementation.
You can no longer get the entire list of friends.
Now... the list will be limited to only those friends who also happen to use your app.
To quote Facebook Graph API 2.0 doc:
Permissions
A user access token with user_friends permission is required to view the current person's friends.
This will only return any friends who have used (via Facebook Login) the app making the request.
If by friendslist you mean a list of friends for the logged in user then the graph path is me/friends. Something like this works for me after you have opened an active FBSession with read permissions.
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"id,name,picture",#"fields",nil];
[FBRequestConnection startWithGraphPath:#"me/friends"
parameters:params
HTTPMethod:#"GET"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if(error == nil) {
FBGraphObject *response = (FBGraphObject*)result;
NSLog(#"Friends: %#",[response objectForKey:#"data"]);
}
}];
Note that the result of the FBRequestConnection request on success is an FBGraphObject with the required information returned for key 'data'.
You can open an active FBSession with read permission of just basic_info before making an FBRequestConnection for the list of friends.
Hope this helps
I have two questions related in iOS vs Facebook API.
1) How to customise the facebook login view when user click the login btn to get user data.
2) In my application i want to use the facebook API. In this way i can able to retrieve the Users Data in this below method. But how can i save these users datas in my app locally.
Highly appreciated for your help !!!
[FBSession openActiveSessionWithReadPermissions:#[#"email",#"user_location",#"user_birthday",#"user_hometown"]
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
switch (state) {
case FBSessionStateOpen:
[[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error){
if (error) {
NSLog(#"error:%#",error);
}
else
{
// retrive user's details at here as shown below
NSLog(#"FB user first name:%#",user.first_name);
NSLog(#"FB user last name:%#",user.last_name);
NSLog(#"FB user birthday:%#",user.birthday);
NSLog(#"FB user location:%#",user.location);
NSLog(#"FB user username:%#",user.username);
NSLog(#"FB user gender:%#",[user objectForKey:#"gender"]);
NSLog(#"email id:%#",[user objectForKey:#"email"]);
NSLog(#"location:%#", [NSString stringWithFormat:#"Location: %#\n\n",
user.location[#"name"]]);
self.fbUserDataDict = [NSDictionary dictionaryWithDictionary:user];
}
}];
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
[FBSession.activeSession closeAndClearTokenInformation];
break;
default:
break;
}
} ];
How about using something like Parse to store them locally ? You can also use SQLite. Though do you mind expanding a bit on what would you like to do ? Just store them locally ?
I've started Facebook integration for a project and I've run into a problem. I am attempting to store the logged in user as a local object so the information can be referenced later, but I can't seem to hold onto the information.
Here is my function for fetching the user data:
if(_session.isOpen)
{
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error)
{
[[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *user,
NSError *error)
{
if(!error)
{
NSLog(#"Username: %#",user.name);
[_user initWithDictionary:user];
NSLog(#"Username: %#",[_user objectForKey:#"name"]);
}
else
{
NSLog(#"Couldn't get user details!");
}
}];
}];
}//endif
In this case, the NLog gives "Username: (null)"
I'm pretty new to both ObjC and Facebook so I'm not sure what I'm doing wrong. Also, I tried to create a member variable :
#property (strong, nonatomic) NSDictionary<FBGraphUser> *loggedInUser;
and previously my code for storing the user was
if(!error)
{
NSLog(#"Username: %#",user.name);
_user = user;
NSLog(#"Username: %#", _user.name);
}
else
{
NSLog(#"Couldn't get user details!");
}
Since neither of these worked (the second worked insofar as the second NSLog gave the correct variable, but later attempts to access it outside this function caused a crash) I can only assume I am not storing the information correctly.
Can someone give me some pointers on what I'm doing wrong?
You need to print user.username not user.name