Face book connect is not working - iphone

I have integrated Facebook connect in my iphone application.
when user clicks on a button i am calling a method which has the following code.
session1 = [[FBSession sessionForApplication:kApiKey secret:kApiSecret delegate:self] retain];
dialog = [[[FBLoginDialog alloc] initWithSession:session1] autorelease];
[dialog show];
when the user login into the Facebook with his username and password, if the user name and password are incorrect it is showing the message correctly.
but when the user enters correct user name and password, the entire face book window is closing without giving any message.

Vodkhang has the right answer, but also know that since Facebook connect stores info in the user defaults, you should insert a
if (![session1 resume]) {
before you invoke the dialog. This will ensure that future uses of the app will not generate the same login dialog.
The didLogin: delegate function will still be invoked when the session is resumed, so you can still do whatever you need with the FBUID. One simple thing you can do is create a hidden Label in Interface Builder and assign the FBUID to that label in the didLogin function. That way you can always pull that label's text if you need the FBUID later.

It works correctly. The facebook window closes mean your user login successfully. You should handle some delegate:
#pragma mark FBSessionDelegate
- (void)session:(FBSession*)session didLogin:(FBUID)uid {
}
- (void)sessionDidNotLogin:(FBSession*)session {
}
- (void)session:(FBSession*)session willLogout:(FBUID)uid {
}
- (void)sessionDidLogout:(FBSession*)session {
// NCLog(#"FacebookHelper logged out");
}
Then you will know what happens to the login process

Related

Facebook iOS seems lost session when return to app after clicking Okay to You have already authorized app

I have upgraded my app from Facebook SDK 2 to 3.1.
I have a Post button on the RecordsScreen. If the user is not login to Facebook, the login page will appear and if the user is login already, another nib will be loaded to prompt the user to enter a message for posting to his/her own wall.
I have already login. And after that, every time when I click the Post button, the page about the app is already authorized and ask you whether to continue by clicking Okay appears. After clicking Okay, the app terminates and starts again launching from the beginning. Every time when I click the Post Button, this same page appears again. It look like it cannot find a valid session or the token is lost.
I have tested this on the Simulator and the device. Same thing occurs. Deployment target is iOS5.1.
The only parameter I have not entered is the iPhone App Store ID. Will this affect the above behavior?
I have tried a lot of times already and could not find a solution.
Any help is appreciated.
Thanks!
aobs
Edited on Jan 4:
I found out that every time openSessionWithAllowLoginUI is called. The state FBSessionStateClosedLoginFailed is returned. There is a problem with login. But the user has login already since the Already Authorized page appears.
The reason is applicationWillTerminate executes right after openSessonWithAllowLoginUI. Can anyone shed light on this?
In the appDelegate.h, I import the FacebookSDK/FacebookSDK.h and in appDelegate.m, the following is implemented:
-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [FBSession.activeSession handleOpenURL:url);
}
-(void)applicationDidBecomeActive:(UIApplication *)application {
[FBSession.activeSession handleDidBecomeActive];
}
-(void)applicationWillTerminate:(UIApplication *)application {
[FBSession.activeSession close];
}
The mainViewController is a multi-view controller that will switch nibs.
I have implemented a class FBHandler to handle Facebook login/logout. FBHandler.h contains #import "Facebook.h" and FBHandler is a class that contains
-(void)sessionStateChanged:(FBSession *)session state:(FBSessionState)state error:(NSError *)error {
switch(state) {
case FBSessionStateOpen:
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
[FBSession.activeSession closeAndClearTokenInformation];
default:
break;
}
[[NSNotificationCenter defaultCenter]postNotificationName:FBSessionStateChangedNotification object:session];
// If there is an error, display the alert view. I have skipped this code.
}
-(BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
return [FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:allowLoginUI completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
One of the nibs - RecordsScreen.xib contains the Facebook login/logout buttons. In the RecordsScreen.m (a place where the user can see his/her score and login or logout from Facebook), the following is added to viewDidLoad:
fbHandler = [[FBHandler alloc] init];
[fbHandler openSessionWithAllowLoginUI:NO];
// Also, we will listen to FBSessionStateChangedNotification in viewDidLoad. Code is skipped here.
// The implementation of sessionStateChanged in RecordsScreen:
-(void)sessionStateChanged:(NSNotification *)notification {
if (FBSession.activeSession.isOpen) {
if (self.facebook == nil) {
self.facebook = [[Facebook alloc]initWithAppId:FBSession.activeSession.appID andDelegate:nil];
self.facebook.accessToken = FBSession.activeSession.accessToken;
self.facebook.expirationDate = FBSession.activeSession.expirationDate;
}
} else {
self.facebook = nil;
}
}
In RecordsScreen.m, if the user clicks the login in button,
if (!FBSession.activeSession.isOpen) {
// Login to Facebook.
[fbHandler openSessionWithAllowLoginUI:YES];
} else {
// If user is login, post to wall.
[self postScoreToWall];
}
I found the problem. In the plist, "Application does not run in background" was set to YES. Setting to NO solved the problem.
In the code that you are showing you only acquire the basic set of read permissions for your session. There needs to be at least a call to reauthorizeWithPublishPermissions: passing the appropriate permissions.
I just had a similar problem, I resolved it by changing two things, when doing the login I am not using the two step permission escalation method that Facebook suggests but I try to acquire the permissions necessary on the login by using openActiveSessionWithPublishPermissions.
You also need to make sure that handleDidBecomeActive: gets called at the end of the Facebook login process before you try to make another call to the sdk. That might not happen if you have a series of blocks that execute the various steps of this process.
I did not work with the older version of this sdk but it seemed a lot more intuitive.

iPhone Gigya integration sharing Facebook, twitter inconsistency

I am currently integrating facebook and twitter for iphone with gigya.
For Twitter sometimes its sharing and sometimes don't. Facebook also happening same as well.
lately facebook not even opening its login in screen. On device unlike simulator delegate methods like LoginDidFail, DidLogin called more than once.not sure why.
I am not storing any object to store provider info when login happens.
Can you please let me know why this inconsis
This seems like a multi part question.I would need more information to get a clearer understanding. Please provide code snippets if possible. Meanwhile, please see see my responses below:
Inconsistent Sharing
This might be something to do with how your userAction is being defined.
(http://wiki.gigya.com/030_API_reference/010_Client_API/010_Objects/UserAction_object)
Login Screen not loading
Typically this is down to social Network Applications not set up correctly.
(http://wiki.gigya.com/035_Socialize_Setup/005_Opening_External_Applications)
Event Delegate methods called repeatedly
This may be down do multiple instances of the GSAPI class.
Hope that helps.
I am using following code snippet
GSAPI *gsAPI // declared this in header file
gsAPI = [[GSAPI alloc] initWithAPIKey:XX viewController:self]; // i kept this in viewDidload
// add this code to have facebook and twitter on provider list. this was put in in one method which will be called when user tries to share
GSDictionary *pParams5 = [[GSDictionary new] autorelease]; [pParams5 putStringValue:#"facebook,twitter" forKey:#"enabledProviders"];
[gsAPI showAddConnectionsUI:pParams5 delegate:self context:nil];
//this method called when login fails -(void)gsLoginUIDidFail:(int)errorCode errorMessage:(NSString*)errorMessage context:(id)context {
}
// this method called on successful login
- (void) gsLoginUIDidLogin:(NSString*)provider user:(GSDictionary*)user context:(id)context {
GSDictionary *userAction = [[GSDictionary new] autorelease];
[userAction putStringValue:#"title" forKey:#"title"];
[userAction putStringValue:#"userMessage" forKey:#"userMessage"];
[userAction putStringValue:#"desc" forKey:#"description"];
[userAction putStringValue:#"imageurl" forKey:#"linkBack"];
GSDictionary *pParams5 = [[GSDictionary new] autorelease];
[pParams5 putGSDictionaryValue:userAction forKey:#"userAction"];
[gsAPI sendRequest:#"socialize.publishUserAction" params:pParams5 delegate:self context:nil];
}
-(void) gsDidReceiveResponse:(NSString*)method response:(GSResponse*)response context:(id)context {
//showing alert messages on successful sharing
//this method getting called more than twice on device
}

Require user to go through login screen before giving access to iPhone app?

On iPhone, how do I show a login screen to get username and password before giving access to iPhone app? Also, does the iPhone store a cookie to the secure website like a web browser?
I was thinking of giving users to my website a long API key to store in the settings of their iPhone instead of asking them to login with a username/password (seems to be the Slicehost iPhone app approach.) Which is the best way to get a user to login securely? I have full control over the design of the iPhone app and website so have a lot of flexibility.
I have this need in a couple of apps, and I use the following pattern:
In the controller for the first view that gets presented to the user, I have the following test, where UserPrefsManager is a singleton that knows the user credentials. This call causes a modal view to appear (FirstTimeWelcomeViewController) which tells the person that they need to register.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UserPrefsManager * prefs = [UserPrefsManager sharedInstance];
if (![prefs isLoggedIn])
{
FirstTimeWelcomeViewController * vc = [[[FirstTimeWelcomeViewController alloc] initWithNibName:#"FirstTimeWelcomeViewController" bundle:nil] autorelease];
[self presentModalViewController:vc animated: false];
}
else
{
if (![[RWXLocationSingleton sharedInstance] hasLocation]) {
[[RWXLocationSingleton sharedInstance] findLocationWithAccuracy:kCLLocationAccuracyThreeKilometers withObject:self andSelector:#selector(updateLocationsView)];
}
[[self tableView ]reloadData];
}
}
FirstTimeWelcomeViewController is basically a screen with buttons that greets people and takes them to the various ways to log in:
-(IBAction) createAccount
{
UIViewController * parent = [self parentViewController];
CreateAccountViewController * vc = [[[CreateAccountViewController alloc] initWithNibName:#"CreateAccountViewController" bundle:nil] autorelease];
[self dismissModalViewControllerAnimated:false];
[parent presentModalViewController:vc animated: false];
}
imagine that these also exist for forgotPassword, and loginACcount... same pattern. This causes the current view to be replaced by a view handling the specific case that they've pressed the button for.
taking the 'loginAccount' method, you've opened the LoginAccountViewController, and it has a method called loginButton, which works something like this...
-(IBAction) loginButton
{
NSString * u = [self.username text];
NSString * p = [self.password text];
//
// app specific logic that tests various inputs and creates a user object.
//
// goes here...
//
if([user checkValid])
{
UserPrefsManager * prefs = [UserPrefsManager sharedInstance];
[prefs setPassword:p];
[prefs setUsername:u];
[self dismissModalViewControllerAnimated:FALSE];
}
//
// more app specific stuff
//
}
And that's pretty much that. You have to use one of the standard ways for putting stuff in the keychain or user defaults to save your information. check that the one you pick lasts between restores if it is something that is annoying for the user to recreate. The first part is the most useful bit, thought the rest might be useful for context.
I'd recommend looking at a technology such as OAuth (http://oauth.net/). This enables the user to authorize access to their account to an application without having to actually enter their username and password into it. Also means you dont have to worry about secure storage of the users credentials, and if their passwords change etc it doesn't matter.
It's used by facebook / twitter and a lot of other big name companies so its not going away (Its actually in the process of getting approved as an offical standard).
You can't restrict access to the app itself but it is trivial to present an initial view that ask for the username and password. If the user does not present the correct information then the app will not allow them to progress to the next view which actually loads the web site.
Likewise, it would be trivial to store a key in the app's sandboxed folders such that neither the user nor anyone else could access it save through the app.

Facebook Connect for iPhone - want to log in and post in one step

This is a repost from the Facebook developer forums, where no-one has responded yet.
This is what I would like to do:
user touches Connect button
code retrieves session and attempts to resume
if session does not resume, pop up login dialog
pop up feed dialog (after user has successfully logged in)
What actually happens in the case where a login is needed:
user touches Connect button
login dialog comes up (but user never sees it)
feed dialog immediately comes up on top of it
feed dialog spins forever because it is unable to connect
There doesn't seem to be a way to use the delegate methods to tell if the user has finished logging in; dialogDidSucceed never seems to be called for the login dialog. For that matter, there doesn't seem to be a way to tell if they cancelled out either (in which case going on to the feed dialog would be pointless).
Am I attempting the impossible?
- (void) login {
session = [FBSession sessionForApplication:... secret:... delegate:self];
FBLoginDialog *dialog = [[[FBLoginDialog alloc] initWithSession:session] autorelease];
dialog.delegate = self;
[dialog show];
}
- (void) session:(FBSession *)newSession didLogin:(FBUID)newUid {
session = newSession;
uid = newUid;
FBFeedDialog* dialog = [[[FBFeedDialog alloc] init] autorelease];
dialog.delegate = self;
dialog.templateBundleId = ...
dialog.templateData = ...
[dialog show];
}
While Ed's answer is correct, he's not explaining why.
When you send the show message the first dialog, it shows, but doesn't wait for it to close.. the program execution moves along to the next line. Therefore you are asking the next dialog to show, which it does – right on top of the previous one. This is true for dialogs or alert views on the iPhone platform.
Ed's answer is showing the first dialog but not continuing. What is not obvious, is that when the user successfully logs in, the session delegate is sent the -didLogin: message. You may have expected a dialog delegate message?
Be careful though, as other situations that you code may result in the session login, and it will run the code in the delegate method.. and you may not want that!
An example of this is when the session resumes. To keep it straight-forward, assume you have two actions in your app, and both publish a short story to the user feed. When you ask the user to login – or resume – their existing session, the session delegate message -didLogin: will be sent. You need to make sure your implementation of -didLogin: handles both situations, and both actions.
As an aside, consider using the latest SDK and the stream.publish request, or the FBStreamDialog class (instead of FBFeedDialog)for pushing the story to facebook.
(I'm "answering my own question" because this was too long to leave as a comment on the previous entry)
I don't think I explained the problem clearly enough... let me try again. The code below is executed when the user touches the "share on facebook" button:
// get session
if (session == nil) {
session = [FBSession sessionForApplication.....];
}
// log in if necessary
if (![session resume]) {
FBLoginDialog* dialog = [FBLoginDialog alloc...];
[dialog show];
}
// post feed story
FBFeedDialog* dialog = [FBFeedDialog alloc...];
dialog.delegate = self;
dialog.templateBundleID = ...;
[dialog show];
This does not work, for obvious reasons - both dialogs come up right away. While I see that splitting it into two methods would help, the main problem is that I have nothing on which to trigger bringing up the feed dialog. dialogDidSucceed doesn't seem to get called for the login dialog, and there doesn't seem to be anything else I can look for. Most apps split this into two buttons, meaning the user has to touch a second button in order to initiate posting a feed story. I was hoping to avoid that, but I can't find a way to do it.

iPhone Facebook Connect logout crash after changing views

I've implemented Facebook Connect in my app just like the sample app that Facebook provides and it works well. After a user chooses to share data via Facebook they are taken to a new view and presented with the FB login dialog. When the user is done they exit the FB sharing view and return to my app's previous view. The user stays logged in as long as they don't logout - even if they exit the FB sharing view. This is good and as expected.
I'm using the same viewDidLoad method as the sample SessionViewController.m, and this is where _session is initialized:
- (void)viewDidLoad {
[_session resume];
_loginButton.style = FBLoginButtonStyleWide;
}
However I noticed that if the user presses the Logout button after exiting and re-loading the FB sharing view it will throw SIGABRT or EXC_BAD_ACCESS and crash the app. The EXC_BAD_ACCESS error occurs at the [dialog show] line of the Login button's touchUpInside method:
- (void)touchUpInside {
if (_session.isConnected) {
[_session logout];
} else {
FBLoginDialog* dialog = [[[FBLoginDialog alloc] initWithSession:_session] autorelease];
[dialog show];
}
Even though the user is connected the touchUpInside method is seeing a disconnected session... Sometimes instead of crashing after pressing the Logout button the logout will be successful but the view's status text remains "Logged in as ..." and the set status/upload image buttons are not hidden. Trying to log in again throws a SIGABRT, which looks due to a nil _session.sessionKey in FBRequest.m:344:
[_params setObject:_session.sessionKey forKey:#"session_key"];
Is there something I should be retaining or doing differently across view changes?
EDIT: I found another user having this same issue on the Facebook Developer Forums:
http://forum.developers.facebook.com/viewtopic.php?pid=193727#p193727
There is no solution posted but if I find one I'll update this question.
_session is nil at that point, right (that's consistent with the "always showing not connected"). Where do you initialize _session?
ETA: This is your code, which is taking the place of SessionViewController provided by Facebook Connect, right?
I can't figure out how _session could have been released, but that's what it seems like.
Adding:
You might want to change your button handler to
[_session resume];
and then do whatever you need to do in the didLogin delegate handler. That way the _session instantiates the FBLoginDialog for you.