I am using the sample program to learn the facebook-ios-sdk, I found a problem: if I logged into Facebook on my device and run that sample app, everything is fine, however, when I delete my Facebook account from my device and run that sample app again, I can still pass the login process and SCViewController can still be seen (There is a fast-app-switch to Facebook app process, but only I need to do is to click the "OKey" button, I don't need to fill any email/password information to log into the Facebook).
I checked the code and found that after my account is removed from the device, the token in FBSession.activeSession.accessToken is still considered as valid. Is there any problem? and How can I clear the token and make the log in dialog pop up? I have already invoked [FBSession.activeSession closeAndClearTokenInformation] when log out, the token should be cleared, according to the Facebook sdk document, but it is not the case.
the environment I use: XCode 4.6.1, iPad 6.1 simulator and facebook-ios-sdk v3.2.1.
updated: paste some code here:
in SCAppDelegate.m, I added 3 functions, which is not in the sample code but in the SDK online document:
- (void)showLoginView
{
UIViewController* topViewController = [self.navigationController topViewController];
UIViewController* modalViewController = [topViewController modalViewController];
// If the login screen is not already displayed, display it. If the login screen is
// displayed, then getting back here means the login in progress did not successfully
// complete. In that case, notify the login view so it can update its UI appropriately.
if (![modalViewController isKindOfClass:[SCLoginViewController class]]) {
SCLoginViewController* loginViewController = [[SCLoginViewController alloc]
initWithNibName:#"SCLoginViewController"
bundle:nil];
[topViewController presentModalViewController:loginViewController animated:NO];
} else {
SCLoginViewController* loginViewController = (SCLoginViewController*)modalViewController;
[loginViewController loginFailed];
}
}
- (void)sessionStateChanged:(FBSession*)session state:(FBSessionState)state error:(NSError*)error
{
switch (state) {
case FBSessionStateOpen: {
UIViewController* topViewController = [self.navigationController topViewController];
if ([[topViewController modalViewController]isKindOfClass:[SCLoginViewController class]]) {
[topViewController dismissModalViewControllerAnimated:YES];
}
}
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
[self.navigationController popToRootViewControllerAnimated:NO];
[FBSession.activeSession closeAndClearTokenInformation];
[self showLoginView];
break;
default:
break;
}
if (error) {
UIAlertView* alertView = [[UIAlertView alloc]initWithTitle:#"Error" message:error.localizedDescription delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
- (void)openSession
{
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:YES completionHandler:^(FBSession* session, FBSessionState status, NSError* error){
[self sessionStateChanged:session state:status error:error];}];
}
Then in SCLoginViewController.m, I add a button, instead of using the existing FBLoginView object, to do the login job. The handler function for that button is as follows:
- (IBAction)performLogin:(id)sender {
//[self.spinner startAnimating];
SCAppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
[appDelegate openSession];
}
Then in SCViewController.m, I add another button to do the log out job. The handler function for that button is as follows:
- (IBAction)logoutButtonWasPressed:(id)sender {
[FBSession.activeSession closeAndClearTokenInformation];
}
other code is almost the same as that in the sample code.
Apart from the clearing the token, you also need to clear the cookie that is stored in Safari when you use it to log into Facebook.
The following works for me with Facebook SDK 3+ on iOS 5.1+:
[FBSession.activeSession closeAndClearTokenInformation];
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for(NSHTTPCookie *cookie in [storage cookies])
{
NSString *domainName = [cookie domain];
NSRange domainRange = [domainName rangeOfString:#"facebook"];
if(domainRange.length > 0)
{
[storage deleteCookie:cookie];
}
}
Related
i am using the facebook login button provided by the fb sdk for implementing the facebook login in my app.When i am logging out the facebook button does change back to login again.but when i click on it,the safari app opens showing "you have alreay authorised the app"click confirm or cancel.Actually i needed the facebook login and password screen here.I cannot switch user until i reset the simulator.how to reset the contents in safari programmatically each time i logout so that the login screen is shown each time.
Please note that when i clear the website data of safari manually it shows the login page again.can it be done programmatically.
code i am using for login is as follows
//creating the login button
FBLoginView *loginView =
[[FBLoginView alloc] initWithReadPermissions:
#[#"public_profile", #"email", #"user_friends"]];
loginView.frame=CGRectMake(50, 500, 225, 55);
loginView.delegate=self;
[self.view addSubview:loginView];
//delegate method when logged in
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView
user:(id<FBGraphUser>)user {
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
[defaults setObject:[user objectForKey:#"id"] forKey:#"LoggedInUserID"] ;
[self checkandsaveNewUserInBackend:user];
[self performSegueWithIdentifier:#"Login" sender:self];
}
//logout code
- (IBAction)logoutButtonPressed:(id)sender {
[FBSession.activeSession closeAndClearTokenInformation];
[self.navigationController popToRootViewControllerAnimated:YES];
}
try this it user clicks on logout and remove all keys stored in userdefault/cookies
NSLog(#"Logged out facebook");
NSHTTPCookie *cookie;
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (cookie in [storage cookies])
{
NSString* domainName = [cookie domain];
NSRange domainRange = [domainName rangeOfString:#"facebook"];
if(domainRange.length > 0)
{
[storage deleteCookie:cookie];
}
}
Try this...
[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession setActiveSession:nil];
May work for you...
And for clear cookies from browser...follow this link \
http://www.iossnippet.com/snippets/web/how-to-delete-cookies-nshttpcookie-in-objective-c-ios/
In the
//logout code
- (IBAction)logoutButtonPressed:(id)sender {
Use following code
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];
// If the session state is not any of the two "open" states when the button is clicked
} else {
// Open a session showing the user the login UI
// You must ALWAYS ask for public_profile permissions when opening a session
[FBSession openActiveSessionWithReadPermissions:#[#"public_profile"]
allowLoginUI:YES
completionHandler:
^(FBSession *session, FBSessionState state, NSError *error) {
}];
}
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?
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.
Here is a simple scenario, I am using FBLoginView which show a login button and on click application go for fast switching but i want to check a bool value of terms and conditions before app go for fast switch. There is not way i am able to find to achieve this scenario.
- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView {
// Upon login, transition to the main UI by pushing it onto the navigation stack.
LGAppDelegate *appDelegate = (LGAppDelegate *)[UIApplication sharedApplication].delegate;
[self.navigationController pushViewController:((UIViewController *)appDelegate.mainViewController) animated:YES];
}
- (void)acceptTermsAndConditions {
if (!_checkboxButton.checked) {
NSString *alertMessage, *alertTitle;
alertTitle = #"Terms to Use";
alertMessage = #"Please accept the terms & condition to use this application.";
UIAlertView* av = [[UIAlertView alloc] initWithTitle:alertTitle
message:alertMessage
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[av show];
[av release];
}
}
- (void)loginView:(FBLoginView *)loginView
handleError:(NSError *)error{
NSString *alertMessage, *alertTitle;
// Facebook SDK * error handling *
// Error handling is an important part of providing a good user experience.
// Since this sample uses the FBLoginView, this delegate will respond to
// login failures, or other failures that have closed the session (such
// as a token becoming invalid). Please see the [- postOpenGraphAction:]
// and [- requestPermissionAndPost] on `SCViewController` for further
// error handling on other operations.
if (error.fberrorShouldNotifyUser) {
// If the SDK has a message for the user, surface it. This conveniently
// handles cases like password change or iOS6 app slider state.
alertTitle = #"Something Went Wrong";
alertMessage = error.fberrorUserMessage;
} else if (error.fberrorCategory == FBErrorCategoryAuthenticationReopenSession) {
// It is important to handle session closures as mentioned. You can inspect
// the error for more context but this sample generically notifies the user.
alertTitle = #"Session Error";
alertMessage = #"Your current session is no longer valid. Please log in again.";
} else if (error.fberrorCategory == FBErrorCategoryUserCancelled) {
// The user has cancelled a login. You can inspect the error
// for more context. For this sample, we will simply ignore it.
NSLog(#"user cancelled login");
} else {
// For simplicity, this sample treats other errors blindly, but you should
// refer to https://developers.facebook.com/docs/technical-guides/iossdk/errors/ for more information.
alertTitle = #"Unknown Error";
alertMessage = #"Error. Please try again later.";
NSLog(#"Unexpected error:%#", error);
}
if (alertMessage) {
[[[UIAlertView alloc] initWithTitle:alertTitle
message:alertMessage
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
}
}
- (void)loginViewShowingLoggedOutUser:(FBLoginView *)loginView {
// Facebook SDK * login flow *
// It is important to always handle session closure because it can happen
// externally; for example, if the current session's access token becomes
// invalid. For this sample, we simply pop back to the landing page.
LGAppDelegate *appDelegate = (LGAppDelegate *)[UIApplication sharedApplication].delegate;
if (appDelegate.isNavigating) {
// The delay is for the edge case where a session is immediately closed after
// logging in and our navigation controller is still animating a push.
[self performSelector:#selector(logOut) withObject:nil afterDelay:.5];
} else {
[self logOut];
}
}
- (void)logOut {
[self.navigationController popToRootViewControllerAnimated:YES];
}
I've read http://developers.facebook.com/docs/howtos/link-to-your-native-app/ and I am confused on how I am supposed to handle deep linking in 3.0. Say the user clicks an appRequest for my app and FB opens my app with a special URL. I have my Appdelegate's openURL method do:
return [FBSession.activeSession handleOpenURL:url];
The tutorial says:
If your app requires an authorized user, handle the processing of the target URL in the
SDK callbacks implemented after a successful login, the fbDidLogin method.
However, the fbDidLogin delegate method is no longer called because in 3.0 we switch to using FBSession.activeSession instead of using a facebook.m object. In fact, none of the FBSessionDelegate methods will ever be called because the facebook object's state is never changed. So where should I process the URL?
You would likely handle this in the handler you've set up when opening a session.
Say for example that you opened the session using something like:
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
[self sessionStateChanged:session
state:state
error:error];
}];
You could put put the deep linking handling code in the method set to handle session changes that you can define, ex:
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen:
if (!error) {
// Handle deep link
}
break;
case FBSessionStateClosed:
self.user = nil;
break;
case FBSessionStateClosedLoginFailed:
self.user = nil;
[FBSession.activeSession closeAndClearTokenInformation];
break;
default:
break;
}
if (error) {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
}
To see a working sample for deep link handling, see https://github.com/fbsamples/ios-social-cafe/