facebook iOS sdk custom delegate and SSO authorization - iphone

I've been toying with the new facebook iOS sdk. I have gotten my project to the point where someone can login successfully. However I have 2 questions:
1) to hit the graph api you issue the following call: [facebookInstance requestWIthGraphPath:#"me" andDelegate:self]. Is it possible to specificy a delegate other than self? Currently all responses go to the (void)request: (FBRequest *) request didLOad:(id) result. But since my app may issue requests to the facebook api at different times and need different things to happen for each respective request issued, how can I specifiy which callback function the response should hit in my app? Is this possible?
2) Once the user has logged in, how can you check their authorization/login status so that I can disable the login button if they are already logged in? Consider the example of a user turning on the app for the 1st time and logging in. Then closing the app, and opening a few minutes later. I rather not show the user the login button the 2nd time and instead start pulling information to display such as their name.

1) There shouldn't be anything wrong with specifying a delegate other than self, as long as the object you provide as the delegate conforms to the FBRequestDelegate protocol. Alternately you can interrogate the FBRequest object you get in the delegate method to determine which request it was that just loaded and what the appropriate response is.
2) To make it so the user stays logged in, you need to save the accessToken (an NSString) and the expirationDate (an NSDate) properties of the Facebook object when the user logs in. Then, when you would log your user in, attempt to restore these values.
Some code snippets that may help:
- (void)fbDidLogin
{
NSString *tokenString = [[self facebook] accessToken];
NSDate * expirationDate = [[self facebook] expirationDate];
[[NSUserDefaults standardUserDefaults] setObject: tokenString forKey:#"FacebookToken"];
[[NSUserDefaults standardUserDefaults] setObject: expirationDate forKey:#"FacebookExpirationDate"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
And, when you need to log the user in:
NSString *tokenString = [[NSUserDefaults standardUserDefaults] objectForKey:#"FacebookToken"];
NSDate *expDate = [[NSUserDefaults standardUserDefaults] objectForKey:#"FacebookExpirationDate"];
if (tokenString != nil && expDate != nil)
{
[facebook setAccessToken:tokenString];
[facebook setExpirationDate:expDate];
}
if ([facebook isSessionValid])
{
//Your session is valid, do whatever you want.
}
else
{
//Your session is invalid
//(either the session is past the expiration date or there is no saved data for the login)
//you need to ask the user to log in
}

Related

Saving a bool to NSdefaults on AppWillTerminate not working

I am trying to logout a user when the application is terminated (since in this particular case the user data doesn't change very often there is no need to logout when going into background).
So here is my code:
- (void)applicationWillTerminate:(UIApplication *)application
{
User *user = [[User alloc]init];
[user logout];
}
I first tried to log the user out like so but it didn't work:
- (void)applicationWillTerminate:(UIApplication *)application
{
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"logged_in"];
}
Any ideas?
If you want the defaults to be updated immediately, you should sync after updating:
[[NSUserDefaults standardUserDefaults] synchronize];
As documented (khm, please look up the documentation), the NSUserDefaults class doesn't immediately persist the changes to disk, only once in a while.

how to disable re-login in iphone

I have developed an app which is related with signing in to an account and people can also get registered in my app, since those user info will be stored in a SQLite database.
The problem is that, when the user logs out of the account and then re-logs in, the app asks the user to login again. I dont want this to happen, as it should remember the user name and password and should login automatically.
Does anyone know how to get this done?
In your AppDelegate.m file , add the NSUserDefaults method ...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
if ([standardUserDefaults valueForKey:#"dbID"]==nil) {
[standardUserDefaults setObject:#"1" forKey:#"dbID"];
[standardUserDefaults synchronize];
}
}
and also you have sane the username and password save the NSUserDefaults.
and for log out functionality , add the code logout code where you want the logout the applications ...
-(IBAction)Logout :(id)sender {
[[NSUserDefaults standardUserDefaults] setObject:#"" forKey:#"dbID"];
[NSUserDefaults resetStandardUserDefaults];
}
in the login time check the dbID is null then user login with the username and password. if the dbID is not null the login the old username and password.
if u are exit the without logout the applications , then store the dbID is "1" in the NSUserDefaults and redirect the view controller and For save the user name and password in the your logon time...for save
[[NSUserDefaults standardUserDefaults] setValue:#"Your text field value" forKey:#"Username"];
[[NSUserDefaults standardUserDefaults] setValue:#"Your text field value" forKey:#"password"];
read the
NSString * _UserName = [[NSUserDefaults standardUserDefaults] stringForKey:#"Username"];
NSString * _password = [[NSUserDefaults standardUserDefaults] stringForKey:#"password"];
username and password save the NSUserDefaults is indicated the u have store the username and password in NSUserDefaults.
if the you have logout the application by button , the make the NUll username and password save the NSUserDefaults .. like
[[NSUserDefaults standardUserDefaults] setValue:#"" forKey:#"Username"];
[[NSUserDefaults standardUserDefaults] setValue:#"" forKey:#"password"];
Use NSUserDefaults. This one will work fine
NSUserDefaults *rememberDefault = [NSUserDefaults standardUserDefaults];
if ([[rememberDefault valueForKey:#"Autologin"] isEqualToString:#"Autologin_on"]) {
btnAutoLogin.selected =NO;
}else {
btnAutoLogin.selected =YES;
}
In your Button Action Method :
-(IBAction)btnOnOffSwitch:(UIButton *)sender{
if (sender.selected) {
sender.selected = NO;
}else {
sender.selected = YES;
}
}
and when you want to check use this:
NSUserDefaults *rememberDefault = [NSUserDefaults standardUserDefaults];
if([[rememberDefault valueForKey:#"Autologin"] isEqualToString:#"Autologin_on"])
{
write your code here. to push directly to your home screen. this should be checked in your login screen
}
may b this will help you.
for your condition when user successfully login first time at that time make 1 dictionary for storing username , password and user id else make 3 different nsuserdefault object for this 3 types.
and when user comes again in that login screen check that nsuser default value is empty or has some value so if the value is there than it has already logsin and u can directly redirect him to next page .. else display the login page..
here i have write only the logic not source code so u can try it out your self and learn more :)..
hope this will help you.

Facebook's FBConnect SDK issues on iOS

I'm using FBConnect sdk in order to publish posts to a user's profile via my application. I'm having a number of problems with this:
When the relevant code runs for the first time on the device, the user is re-directed, as wanted, to the facebook app/website, which asks him to authorize it. if the user authorizes it, it returns back to the application, which pops a "Connect to facebook" view controller which asks the user to log in. this is weird, as the user is already logged in, otherwise how could he authorize the app? but I guess this may be ok, as he hadn't logged in through the app yet. after he logs in, it does nothing. only the second time the code gets run, after he authorized the app, the user gets the posting dialog.
If the user hadn't authorized the app, when it comes back to my app after the authorization dialog, it asks the user to login ( just as if he authorized ), and does nothing after he had logged in. only the second time the code gets ran, the authorization dialog opens, with the optinos "Authorize" & "Leave App", instead of "Authorize" & "Don't authorize" / "Allow" & "Don't Allow".
In addition, if the user has deleted his authorization via his account's settings on facebook, instead of just asking him to re-authorize it, a facebook dialog pops ( instead of the post/authorization dialog ), saying: "An error occurred. Please try again later." Trying later doesn't help. it will pop always, even if u restart the app. the only way to make it go away is to re-install the app, which will cause it to re-pop the authoriziation dialog.
So here's what I want to achieve:
After the user authorizes the app, he wouldn't have to log in again.
After the user authorizes the app, the posting dialog will pop immedietly, without him having to re-run the code ( which is triggered, btw, with a button ).
If the user un-authorizes the app, he will be prompted again with the authorization dialog, instead of the error dialog
If he refused the authorization, I will call a function that displays an error/etc.
Here's the relevant code:
MyViewController.m
- (void)shareOnFacebook
{
Facebook *facebook = [[Facebook alloc] initWithAppId:myAppID];
[(MyAppDelegate *)[[UIApplication sharedApplication] delegate] setFacebook:facebook];
[facebook release];
facebook = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] facebook];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"FBAccessTokenKey"] && [defaults objectForKey:#"FBExpirationDateKey"]) {
facebook.accessToken = [defaults objectForKey:#"FBAccessTokenKey"];
facebook.expirationDate = [defaults objectForKey:#"FBExpirationDateKey"];
}
if (![facebook isSessionValid]) {
[facebook authorize:[NSArray arrayWithObjects:#"publish_stream", nil] delegate:(MyAppDelegate *)[[UIApplication sharedApplication] delegate]];
}
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
//Giving the dictionary some parameters for posting defaults
[facebook dialog:#"feed" andParams:dictionary andDelegate:self]; //Note: we have 2 different delegates! appDelegate for connections & url switching, and self for dialogs
}
MyAppDelegate.h
#interface MyAppDelegate : NSObject <UIApplicationDelegate, FBSessionDelegate, FBDialogDelegate>
{
Facebook *facebook; // kept for facebook sharing, accessed only from MyViewController although delegate methods are handeled in here
}
#property (nonatomic, retain) Facebook *facebook;
#end
MyAppDelegate.m
- (void)fbDidLogin
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[facebook accessToken] forKey:#"FBAccessTokenKey"];
[defaults setObject:[facebook expirationDate] forKey:#"FBExpirationDateKey"];
[defaults synchronize];
}
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
return [self.facebook handleOpenURL:url];
}
Is it possible that I'm missing a couple of delegate functions on MyViewController? Because I see for some reason I've marked it as implementing the FBDialogDelegate protocol, although he doesn't implement any function from there.
I'd be really glad if you guys would help me, as this is extremely frustrating for me. I couldn't find nothing about this on the internet, and I feel like im drowning in here.Tnx in advance!
First:
[facebook authorize:[NSArray arrayWithObjects:#"publish_stream",#"offline_access",nil] delegate:self];
The offline_access key here will keep your auth token alive forever (or, more specifically, until the user manually de-authorizes your application in their application settings in their Facebook account settings). Also, set your active VC as the delegate (more on that later).
Secondly:
-(void)popUserShareFeed {
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
//Giving the dictionary some parameters for posting defaults
[facebook dialog:#"feed" andParams:dictionary andDelegate:self];
}
Call this method (or one like it) in your -fbDidLogin delegate method. Also call it in your original method if the session was still valid, i.e.:
if (![facebook isSessionValid]) {
[facebook authorize:[NSArray arrayWithObjects:#"publish_stream", nil] delegate:(MyAppDelegate *)[[UIApplication sharedApplication] delegate]];
} else {
[self popUserShareFeed];
}
...and your new fbDidLogin:
- (void)fbDidLogin
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[facebook accessToken] forKey:#"FBAccessTokenKey"];
[defaults setObject:[facebook expirationDate] forKey:#"FBExpirationDateKey"];
[defaults synchronize];
[self popUserShareFeed];
}
(Note: you'll have to define this in MyViewController.m and use it as your FBSessionDelegate. It will be functionally equivalent. Your AppDelegate does not need to also be your FBSessionDelegate.
Third:
Implement the -fbDidNotLogin:(BOOL)cancelled FBSessionDelegate method, like so:
-(void)fbDidNotLogin:(BOOL)cancelled {
if (cancelled) {
... some alert about the user cancelling...
} else {
... some alert about how it failed for some reason...
}
}
Fourth, as far as your bizarro errors go: A) the Facebook SDKs in general are not great, and B) I'd only set the auth token and the expiration date on your facebook object if
A) you don't already have one instantiated (i.e., it's nil)
and
B) the expirationDate you're setting is in the future (i.e. timeIntervalSinceNow [the NSDate instance method] called on it returns > 0).
Sounds like you're experiencing the same issue described in this Facebook Platform Developer forum post. I'm encountering the same problem, but on the web. Only one response was given from Facebook in that thread, and it's wrong information.
Facebook has the worst developer docs and developer support ever, I wouldn't hold my breath waiting on a solution.
I had similar but not the same problem: message "An error occurred. Please try again later." was shown always.
The problem was with not properly configured App ID - it was provided by customer (so I'm not sure what exactly was wrong); everything works properly since I replaced it with my own test App ID (from previous app).
I have integrated FBConnect in so many applications , but never face such kind of critical issue. So, there would be something missing in your code:
Insted of checking FBAccessTokenKey & FBExpirationDateKey, simply try with session object of FBSession class of FBConnect.
Just try using mine code with few conidtions:
session = [[FBSession sessionForApplication:#"key" secret:#"AppSecretKey" delegate:self] retain];
[session resume];
_posting = YES;
// If we're not logged in, log in first...
if (![session isConnected]) {
loginDialog = nil;
loginDialog = [[FBLoginDialog alloc] init];
[loginDialog show];
}
// If we have a session and a name, post to the wall!
else if (_facebookName != nil) {
[self postToWall]; // Over here posting dialog will appear , if user has already logged in or session is running.
}
}
else {
[FBBtn setTitle:#"Login" forState:UIControlStateNormal]; // if you want to change the title of button
[session logout];
}
Additionally take care of releasing the session object in dealloc method only , rather than releasing it in any other method.
- (void)dealloc {
[super dealloc];
[session release];
session = nil;
}
Hope that would solve your problem.
Not a direct solution for your code problems, but...
Have you consider using an open-source library for this? ShareKit is a great example: http://getsharekit.com . The integration is dead simple and it does everything you need.
I was having the exact same issue, and used Ben Mosher's response above, but I also decided to create a simple singleton class for the Facebook object, so that in my AppDelegate I can handle the following function properly:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [[[FBManager defaultManager] facebook] handleOpenURL:url];
//return [facebook handleOpenURL:url];
}
My singleton class is both FBSessionDelegate and FBDialogDelegate, so it handles the corresponding methods.
This allows me to only prompt the user to login when they are actually trying to post something, instead of when the app launches.

Facebook SSO problems with iOS app

I'm trying to integrate Facebook to my app, I've implemented the SSO feature, however I ran into a bit of a snag, once I quit the app I am unable to restore the user's session. I store the token and expiry date as shown:
-(void)fbDidLogin {
NSString *tokenString = [[self facebook] accessToken];
NSDate * expirationDate = [[self facebook] expirationDate];
[[NSUserDefaults standardUserDefaults] setValue: tokenString forKey:#"FacebookToken"];
[[NSUserDefaults standardUserDefaults] setObject: expirationDate forKey:#"FacebookExpirationDate"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"Login");
}
this is the delegate method called upon successful login.
and resume the session:
NSString *tokenString = [[NSUserDefaults standardUserDefaults] stringForKey:#"FacebookToken"];
NSDate *expDate = [[NSUserDefaults standardUserDefaults] objectForKey:#"FacebookExpirationDate"];
if (tokenString != nil && expDate != nil)
{
[[facebookFetcher facebook]setAccessToken:tokenString];
[[facebookFetcher facebook] setExpirationDate:expDate];
}
if ([[facebookFetcher facebook] isSessionValid])
{
NSLog(#"YES");
}
else
{
NSLog(#"Bummer");
}
I've tried tackling the problem in a number of ways without luck. One thing I've noticed is that the expiry date seems to be a bit weird:4001-01-01 00:00:00 +0000 Any suggestions? Thanks.
Your answer is at the following link
Does the Facebook iOS SDK require the user to authenticate every time they use the app?
The date 4001-01-01 00:00:00 +0000 is seen when using the extended permission offline_access.
I ran into trouble with this because I was converting the date into "seconds since 1970" like how it's done on the Android Facebook SDK. If you convert 4001-01-01 to seconds using NSDate's timeIntervalSince1970, you'll get a negative number (-2147483648), so watch out.

facebook-ios-sdk logout

I am building a basic app for school that gets some info from facebook using the facebook-ios-sdk. However, when I log out of the app, it does not give me the option to log back in, even in the demo from facebook. I am checking to see if the sessions is still valid, and it always comes out invalid. That is another problem. Here is the code I have. Any help is appreciated.
- (void)viewDidLoad {
_facebook = [[Facebook alloc] init];
if ([_facebook isSessionValid] == NO) {
//show proper buttons for login
loginButton.hidden = NO;
logoutButton.hidden = YES;
}
else {
//show proper buttons for logout
loginButton.hidden = YES;
logoutButton.hidden = NO;
}
}
That is to check whether I am logged in or not. Then I have the proper buttons showing, but the code above is always returning that the session is invalid. Here are the functions I call to log in or out:
- (void)login {
[_facebook authorize:kAppId permissions:_permissions delegate:self];
}
/**
* Invalidate the access token and clear the cookie.
*/
- (void)logout {
[_facebook logout:self];
}
The facebook object says it has no valid session because its accessToken and/or expirationDate are nil. That's probably because it doesn't persist them itself. You probably need to record the accessToken and expirationDate by handling the login in an FBSessionDelegate's fbDidLogin method.
- (void)fbDidLogin {
[[NSUserDefaults standardUserDefaults] setValue: _facebook.accessToken forKey: #"access_token"];
[[NSUserDefaults standardUserDefaults] setValue: _facebook.expirationDate forKey: #"expiration_date"];
}
Use NSUserDefaults, for example, to persist those values to the device. Then, every time you alloc and init your _facebook object, immediately set the accessToken and expirationDate to the values you stored in NSUserDefaults.
That should fix the facebook object saying isSessionValid = NO always. As for the other problem, I have the same one :(