FBFriendPickerViewController showing and empty table on iOS. Place Picker running fine - ios

I have this code, copied from FB samples (where it runs fine), but in my App is showing just a blank table for the Friend Picker. Place Picker is running fine showing a full table.
What´s wrong with Friend Picker?
In the AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[FBFriendPickerViewController class];
[FBPlacePickerViewController class];
return YES;
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
return [FBAppCall handleOpenURL:url sourceApplication:sourceApplication];
}
In the View Controller:
- (IBAction)pickFriendsButtonClick:(id)sender {
// FBSample logic
// if the session is open, then load the data for our view controller
if (!FBSession.activeSession.isOpen) {
// if the session is closed, then we open it here, and establish a handler for state changes
[FBSession openActiveSessionWithReadPermissions:#[#"public_profile", #"user_friends"]
allowLoginUI:YES
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
if (error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
} else if (session.isOpen) {
[self pickFriendsButtonClick:sender];
}
}];
return;
}
// Create friend picker, and get data loaded into it.
FBFriendPickerViewController *friendPickerController = [[FBFriendPickerViewController alloc] init];
friendPickerController.title = #"Pick Friends";
friendPickerController.delegate = self;
[friendPickerController loadData];
[friendPickerController presentModallyFromViewController:self animated:YES handler:nil];
}
- (IBAction)pickPlacesButtonClick:(id)sender{
// FBSample logic
// if the session is open, then load the data for our view controller
if (!FBSession.activeSession.isOpen) {
// if the session is closed, then we open it here, and establish a handler for state changes
[FBSession openActiveSessionWithReadPermissions:#[#"public_profile", #"user_friends"]
allowLoginUI:YES
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
if (error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
} else if (session.isOpen) {
[self pickPlacesButtonClick:sender];
}
}];
return;
}
// Initialize the place picker
FBPlacePickerViewController *placePickerController = [[FBPlacePickerViewController alloc] init];
// Set the place picker title
placePickerController.title = #"Pick Place";
// Hard code current location to Menlo Park, CA
placePickerController.locationCoordinate = CLLocationCoordinate2DMake(37.453827, -122.182187);
// Configure the additional search parameters
placePickerController.radiusInMeters = 1000;
placePickerController.resultsLimit = 50;
placePickerController.searchText = #"restaurant";
placePickerController.delegate = self;
// Load the place data
[placePickerController loadData];
// Show the place picker modally
[placePickerController presentModallyFromViewController:self animated:YES handler:nil];
}
- (void)facebookViewControllerDoneWasPressed:(id)sender {
NSLog(#"Done pressed");
[self dismissViewControllerAnimated:YES completion:NULL];
}
- (void)facebookViewControllerCancelWasPressed:(id)sender {
NSLog(#"Cancel pressed");
[self dismissViewControllerAnimated:YES completion:NULL];
}
Project:
Made a brand new Project with just a Single View.
Added 2 buttons and connected them with the action.
Copy/Paste the code from the sample.
Add the Facebook Framework.
Edit the plist file to add the Facebook Application numbers.
My table (Place Picker) is full for restaurants.
My table (Friend Picker) is still empty. What am I doing wrong?

step 1: open Facebook session if not exist
if ( !FBSession.activeSession.isOpen ) {
[FBSession openActiveSessionWithPermissions:#[#"public_profile", #"email", #"user_friends" ]
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
step 2: request to get friends list (include require fields)
FBRequest* friendsRequest = [FBRequest requestWithGraphPath:#"me/friends?fields=picture,name,username,location,first_name,last_name" parameters:nil HTTPMethod:#"GET"];
[friendsRequest startWithCompletionHandler: ^(FBRequestConnection *connection, NSDictionary* result, NSError *error) {
//store result into facebookFriendsArray
self.facebookFriendsArray = [result objectForKey:#"data"];
}];
step 3: reload data to tableView from facebookFriendsArray

A couple of things you need to consider that are not explained well by Facebook in the current docs.
The users appearing in the friend picker are only users that have installed the app themselves. This is newer, probably not applicable at the time of the original post.
You need the user_friends permission from the user to see any friends.
Some more here: Facebook iOS Select Friends Table Blank

According to the latest Facebook API (v 2.0) you can not pick friends list directly. By default you can access only three permissions that are email, public_profile and user_friends.
For any additional permission you are required to ask Facebook (you can do it from Facebook developer account where you have created app) and also read change log because again apps created on or after 30 April, 2014 can not access old APIs.
if you have app created before stated date then use old Facebook API (I would recommend 3.13.1) and deprecated function (openActiveSessionWithPermissions) to create FBSession.
I had same issue and took me long to figure out. let me know if you have any trouble.

Make sure the permissions array you are using on user sign up includes the user_friends permission. If you're copying code it's easy to miss.
NSArray *permissionsArray = #[ #"public_profile", #"user_friends"];
Reference the array on Sign Up:
[PFFacebookUtils logInWithPermissions:permissionsArray block:^(PFUser *user, NSError *error) {
...
];
Then do the following in FB developer dashboard:
Create at least 2 test users
Set them to friends with each other
And on your app:
Have each user log in and provide permissions for your app (FB will only show users who are friends AND using the app)
The second user should be able to see the first user in their friend list.

Related

Issue Logging in With Facebook on iOS App

In my app, my main screen is a TableView which shows a list of posts from a Facebook Page. I access those posts using Open Graph, which means a user has to be logged in first. So, I have it pop up with a UIAlertView which tells the user this. Clicking ok presents the FBLoginButton, which I have like this:
FBSDKLoginButton *loginButton = [[FBSDKLoginButton alloc] init];
// Optional: Place the button in the center of your view.
loginButton.center = self.view.center;
[self.view addSubview:loginButton];
Clicking the Login Button takes me to Facebook, where I give it permission. It then goes back to the app, but shows an empty TableView with a Facebook Logout button in the middle. My viewWillAppear in the app is like this:
if ([FBSDKAccessToken currentAccessToken]) {
[[[FBSDKGraphRequest alloc] initWithGraphPath:#"/v2.3/PAGEID/feed?limit=20" parameters:[NSMutableDictionary dictionaryWithObject:#"id, message, full_picture, link" forKey:#"fields"]]
startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (!error) {
//performs code to get posts sorted into array
}
else {
NSLog(#"%#", error);
}
}];
} else {
NSLog(#"Not Logged In");
UIAlertView *login = [[UIAlertView alloc] initWithTitle:#"Please Login" message:#"Stronger Marriages now requires a login to Facebook in order to access its latest posts and messages. Thank you!" delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[login show];
}
I had thought that once I have given it permission, it would go back to the app, run the viewWillAppear code, and see there was a currentAccessToken and perform the code, but this is not happening. If I now force close the app, it will show everything fine, with no logout button visible. How do I get it to do this once it redirects to app after logging in?
The easiest way to respond directly to a login via the FBSDKLoginButton is by making your ViewController implement the FBSDKLoginButtonDelegate protocol.
You can call the loginButton:didCompleteWithResult:error: function in this protocol to immediately respond to a login as soon as the user returns to your app from Facebook. It would look something like this:
- (void) loginButton:(FBSDKLoginButton *)loginButton
didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result
error:(NSError *)error {
if ([result token]) {
// Your code here
} else {
NSLog(#"Not Logged In");
// Show error here
}
I'm not sure why viewWillAppear doesn't get called, but I have a different solution. When the Facebook token changes, the SDK sends out a notification. You can subscribe to this, perhaps in your viewDidLoad, and run your code in the callback.
[[NSNotificationCenter defaultCenter] addObserverForName:FBSDKAccessTokenDidChangeNotification
object:nil
queue:[NSOperationQueue currentQueue]
usingBlock:^(NSNotification *note) {
NSLog(#"received access token change notif");
// do your stuff here
}];

FBFriendPickerViewController friend list is empty

I am trying to use FBFriendPickerViewController to get a list of facebook friends to send app invitations. The friend list is empty whenever I test the code. Please see the code below:
#implementation FacebookInviteViewController
- (void)showFriendPicker
{
FBFriendPickerViewController *friendPicker = [[FBFriendPickerViewController alloc] init];
friendPicker.title = #"Invite Friends";
friendPicker.delegate = self;
[friendPicker loadData];
AppController *appController = (AppController *)[[UIApplication sharedApplication] delegate];
[appController.navController presentViewController:friendPicker animated:YES completion:nil];
}
-(void)inviteFromFacebookSelected
{
if (!FBSession.activeSession.isOpen) {
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
if (error) {
UIAlertView *alertView =
[[UIAlertView alloc] initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
} else if (session.isOpen) {
[self showFriendPicker];
}
}];
} else {
[self showFriendPicker];
}
}
In the Settings class (subclassed from CCLayer) I call the following method when the facebook button is pressed
-(void)showFbConnect {
facebookInviteViewController = [[FacebookInviteViewController alloc] init];
[facebookInviteViewController inviteFromFacebookSelected];
}
How can I solve this issue?
Graph API version 2.0 and above will only return App using friends.That means you will only get list of those friends who have authorized your app. So if you have created a new app at facebook and if none of your friends from your friendlist have authorized your app than FBFriendPickerViewController will be empty.
Check the change log at official facebook docs
App Friends: 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.
If you want to test you can authorize your app from one of your friends account and than that friend will be shown in FBFriendPickerViewController
Small addition to #Bhumit's answer. You can go to your app page on Facebook and in the roles section add test users. Facebook creates test users for you at the click of a button. You can then manage these users and their friends.
This should help in testing.

iOS facebook login via custom view (not via external browser)

I have special requirement of client that he want to be able to login to Facebook from within the app itself, i mean he don't want app to open an external browser where user enters his details, he just want to go with native iOS view having username/mobile and password field.
I have already tried googling but could not find any solution so just want to know is it possible to do and if yes then how?
Thanks in advance.
Regards,
Mahesh.
Use following method :
-(void)openFacebookAuthentication
{
NSArray *permission = [NSArray arrayWithObjects:kFBEmailPermission,kFBUserPhotosPermission, nil];
FBSession *session = [[FBSession alloc] initWithPermissions:permission];
[FBSession setActiveSession: [[FBSession alloc] initWithPermissions:permission] ];
[[FBSession activeSession] openWithBehavior:FBSessionLoginBehaviorForcingWebView completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
switch (status) {
case FBSessionStateOpen:
[self getMyData];
break;
case FBSessionStateClosedLoginFailed: {
// prefer to keep decls near to their use
// unpack the error code and reason in order to compute cancel bool
NSString *errorCode = [[error userInfo] objectForKey:FBErrorLoginFailedOriginalErrorCode];
NSString *errorReason = [[error userInfo] objectForKey:FBErrorLoginFailedReason];
BOOL userDidCancel = !errorCode && (!errorReason || [errorReason isEqualToString:FBErrorLoginFailedReasonInlineCancelledValue]);
if(error.code == 2 && ![errorReason isEqualToString:kFBSdkUserLoginFail]) {
UIAlertView *errorMessage = [[UIAlertView alloc] initWithTitle:kFBAlertTitle
message:kFBAuthenticationErrorMessage
delegate:nil
cancelButtonTitle:kOk
otherButtonTitles:nil];
[errorMessage performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:YES];
errorMessage = nil;
}
}
break;
// presently extension, log-out and invalidation are being implemented in the Facebook class
default:
break; // so we do nothing in response to those state transitions
}
}];
permission = nil;
}
Here is my Post : Login with facebook in iPhone without redirecting to the web browser?

Facebook login via app with unverified user account in FB

I'm using facebook-ios-sdk-3.10, Using this SDK I'll login and fetch user details from FB Its working fine for me.
This is the code I'm uisng
- (IBAction)fbLogin_click:(id)sender
{
if (AppDelegate.fbsession.state != FBSessionStateCreated) {
// Create a new, logged out session.
NSArray *permissions = [NSArray arrayWithObjects:#"offline_access", #"email", #"publish_stream", #"read_stream",#"read_friendlists",#"manage_friendlists",#"friends_about_me",#"publish_actions", nil];
// create a session object, with defaults accross the board, except that we provide a custom
// instance of FBSessionTokenCachingStrategy
AppDelegate.fbsession = [[FBSession alloc] initWithAppID:nil
permissions:permissions
urlSchemeSuffix:nil
tokenCacheStrategy:nil];
}
FBSessionLoginBehavior behavior = FBSessionLoginBehaviorForcingWebView;
if (AppDelegate.fbsession.state != FBSessionStateCreatedTokenLoaded) {
// even though we had a cached token, we need to login to make the session usable
[AppDelegate.fbsession openWithBehavior:behavior completionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
if (error)
{
NSLog(#"Error");
}
[self GetFBUserDetails];
}];
}
}
-(void) GetFBUserDetails
{
if (AppDelegate.fbsession.isOpen)
{
[HUD show:YES];
// fetch profile info such as name, id, etc. for the open session
FBRequest *me = [[FBRequest alloc] initWithSession:AppDelegate.fbsession graphPath:#"me"];
self.pendingRequest= me;
[me startWithCompletionHandler:^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *user,
NSError *error) {
// because we have a cached copy of the connection, we can check
// to see if this is the connection we care about; a prematurely
// cancelled connection will short-circuit here
if (me != self.pendingRequest) {
return;
}
self.pendingRequest = nil;
// self.pendingLoginForSlot = -1;
// we interpret an error in the initial fetch as a reason to
// fail the user switch, and leave the application without an
// active user (similar to initial state)
if (error) {
return;
}
[AppDelegate.fbsession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession.activeSession closeAndClearTokenInformation];
FBSession.activeSession=nil;
[self FacebookCustomerRegister:user];
}];
}
}
In such case some user create Facebook account and not very his account through email, when he try to login via my app it shows empty screen after click login button, there is no action further. how can I notify the user "You not yet verify your FB account" and it not return to my app. how can I fetch the response from there ? refer screen short.
I give login details, after click login button that blank screen will appear after this no response from SDK and not return to App.
can anyone help me for this ?
add this code to your AppDelegate
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
return [FBSession.activeSession handleOpenURL:url];
}
read more :https://developers.facebook.com/docs/ios/login-tutorial

FBWebDialogs is Missing Session Cookie to validate user

I am fetching a facebook token from my server (where it was stored from a previous login on another device). I am using that to open a session and then I am making a relatively simple call with
[FBWebDialogs presentRequestsDialogModallyWithSession:[FBSession activeSession]
message:#"Message"
title:#"Title"
parameters:params
handler:^(FBWebDialogResult result,
NSURL *resultURL, NSError *error) {}}];
The web window that pops up has a message saying "An Error occured. Please try again later.". I click OK and I trigger the callback (which I omitted above). When I trace the resultURL I get
fbconnect://success?error_code=110&error_msg=Missing+user+cookie+%28to+validate+session+user%29
I can use the session to post on my wall just fine. What am I missing?
I found that the token retuned by Facebook contains additional metadata such as the c_user cookie which is used by all web views subsequently. When setting up a remote caching system you must store expiry date and refresh date on the remote server and return them for use in the TokenData object. If this is not done correctly them the correct metadata is not set.
Make sure you have "publish_actions" permission on your active Facebook session.
bool hasPublishPermission = NO;
for( NSString* permission in [FBSession.activeSession permissions] )
{
if( [permission isEqualToString:#"publish_actions"] )
{
hasPublishPermission = YES;
break;
}
}
if( !hasPublishPermission )
{
[FBSession openActiveSessionWithPublishPermissions:#[#"publish_actions"]
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:YES
completionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
if( status==FBSessionStateOpen )
{
//Present dialog
}
}];
}
else
{
//Present dialog
}
Also, make sure you have added your "FacebookAppID" to your project's plist. (See the tab, "Configure a new Xcode Project", at https://developers.facebook.com/docs/getting-started/facebook-sdk-for-ios/ ) This may cause the error you are describing.
Hope this helps
I have integrated Embedded webview in my app with Facebook sdk 3.5.3
I hope my code will give some idea to you...
-(IBAction)fblogin:(id)sender{
NSArray * arr=[NSArray arrayWithObjects:#"publish_actions",#"email",#"basic_info",#"user_location",#"user_birthday",#"user_likes", nil];
Interest_Status=[NSString stringWithFormat:#"%#",txt_interest.text];
[FBSession setActiveSession:session];
if (FBSession.activeSession.isOpen) {
if ([btn_Login.titleLabel.text isEqualToString:#"Logout"]) {
[btn_Login setTitle:#"Login" forState:UIControlStateNormal];
[btn_Login setImage:[UIImage imageNamed:#"FBLogin.png"] forState:UIControlStateNormal];
FBSessionTokenCachingStrategy *tokenCachingStrategy = [[FBSessionTokenCachingStrategy alloc]
initWithUserDefaultTokenInformationKeyName:nil];
tokenCachingStrategy=nil;
FBSession *seession=[FBSession activeSession];
[seession closeAndClearTokenInformation];
[session close];
[FBSession setActiveSession:nil];
session=nil;
session=[[FBSession alloc]initWithPermissions:arr];
self.ProfileLale.hidden=YES;
}
/*else if ([btn_Login.titleLabel.text isEqualToString:#"Login"]) {
[self updateForSessionChangeForSlot:1];
}*/
}else{
[session openWithBehavior:FBSessionLoginBehaviorForcingWebView
completionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
// this handler is called back whether the login succeeds or fails; in the
// success case it will also be called back upon each state transition between
// session-open and session-close
if (error)
{
NSLog(#"error=%# \n\n description=%# \n\n,",error,error.description);
[self switchToNoActiveUser];
}else{
[self updateForSessionChangeForSlot:1];
}
}];
}
}
- (void)updateForSessionChangeForSlot:(int)slot {
if (session.isOpen) {
// fetch profile info such as name, id, etc. for the open session
// Fetch user data
FBRequest *me = [[FBRequest alloc] initWithSession:session
graphPath:#"me"];
[me startWithCompletionHandler:^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *user,
NSError *error) {
// because we have a cached copy of the connection, we can check
// to see if this is the connection we care about; a prematurely
// cancelled connection will short-circuit here
// if (me != self.pendingRequest) {
// return;
// }
NSLog(#"user=%#",user);
// self.pendingRequest = nil;
// self.pendingLoginForSlot = -1;
// we interpret an error in the initial fetch as a reason to
// fail the user switch, and leave the application without an
// active user (similar to initial state)
if (error) {
NSLog(#"error=%#",error);
NSLog(#"Couldn't switch user: %#", error.localizedDescription);
[self switchToNoActiveUser];
return;
}else{
NSLog(#"user=%#",user);
[btn_Login setTitle:#"Logout" forState:UIControlStateNormal];
[btn_Login setImage:[UIImage imageNamed:#"FBLogout.png"] forState:UIControlStateNormal];
}
}];
} else {
// in the closed case, we check to see if we picked up a cached token that we
// expect to be valid and ready for use; if so then we open the session on the spot
if (session.state == FBSessionStateCreatedTokenLoaded) {
// even though we had a cached token, we need to login to make the session usable
[session openWithCompletionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
[self updateForSessionChangeForSlot:slot];
}];
}
}
}
- (void)switchToNoActiveUser {
/*UIAlertView *alter=[[UIAlertView alloc]initWithTitle:#"Message" message:#"No Internet connecton" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alter show];
*/
NSArray * arr=[NSArray arrayWithObjects:#"publish_actions",#"email",#"basic_info",#"user_location",#"user_birthday",#"user_likes", nil];
session = nil;
session=[[FBSession alloc]initWithPermissions:arr];
[btn_Login setTitle:#"Login" forState:UIControlStateNormal];
self.ProfileLale.hidden=YES;
[btn_Login setImage:[UIImage imageNamed:#"FBLogin.png"] forState:UIControlStateNormal];
}

Resources