I'm using facebook connect in an iOS app (ARC, running on iOS 5). it was working fine on both simulator and device but since this morning it has stopped working on the device, it does still work on the simulator. On the device i get the fbDinNotLogin method called.
Now, I know the differece is simulator uses mobile facebook and my app uses native iOS facebook app, and I also know that you can tweak the facebook.m file to force the app to do the login elsewhere but I don't want to do that.
loading my previous builds from yesterday (where everything was working fine) also gives me the same results. so same code that ran yesterday doesn't run today. any idea why this happens? below is my delegate .m file:
[EIDT] I get various different behaiviours from the native facebook app. sometimes it opens facebook app, and stays there not coming back to my app. also sometimes it just goes back to my app quickly without allowing facebook app to ask me for my permission. I'm very confused. [/EDIT]
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
user *userClass= [[user alloc] init];
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedOnce"])
{
// app already launched for the first time
}
else
{
// This is the first launch ever
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"HasLaunchedOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
[userClass CopyDbToDocumentsFolder];
}
facebook = [[Facebook alloc] initWithAppId:#"XXXXXXXXXX" andDelegate:self];
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:nil];
}
return YES;
}
-(void)fbDidLogout
{
NSLog(#"Facebook loggedOut");
}
- (void)fbDidNotLogin:(BOOL)cancelled
{
NSLog(#"Facebook Connect Failed");
}
- (void)fbDidLogin {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[facebook accessToken] forKey:#"FBAccessTokenKey"];
[defaults setObject:[facebook expirationDate] forKey:#"FBExpirationDateKey"];
[defaults synchronize];
}
- (void)fbSessionInvalidated
{
NSLog(#"Facebook Session Invalidated");
}
- (void)fbDidExtendToken:(NSString*)accessToken
expiresAt:(NSDate*)expiresAt
{
NSLog(#"Facebook Toekn was extended");
}
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
return [self.facebook handleOpenURL:url];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication: (NSString *)sourceApplication annotation:(id)annotation {
return [self.facebook handleOpenURL:url];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Although the SDK attempts to refresh its access tokens when it makes API calls,
// it's a good practice to refresh the access token also when the app becomes active.
// This gives apps that seldom make api calls a higher chance of having a non expired
// access token.
[[self facebook] extendAccessTokenIfNeeded];
}
#end
Turned out the problem was indeed with facebook and not my app! my developer account had been failing to save changes etc, but it's back to a working now.
I have recently added Facebook integration to my app, and everything works fine except when the user relaunches the app. Each time the app is restarted, Facebook has to go back through its authorization process. This involves switching out of the app to Safari/Facebook, then back to my app. How can I make Facebook save the info, or be able to get blanket permissions for my app so that I doesn't constantly reauthorize?
Here is my code from the applicationDidFinishLaunchingWithOptions: method:
facebook = [[Facebook alloc] initWithAppId:#"203604286395694" andDelegate:self];
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:nil];
}
Relevant Facebook delegate methods:
- (void)fbDidLogin {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[facebook accessToken] forKey:#"FBAccessTokenKey"];
[defaults setObject:[facebook expirationDate] forKey:#"FBExpirationDateKey"];
[defaults synchronize];
}
- (void) requestDialogButtonClicked {
NSMutableDictionary* params =
[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"invites you to check out cool stuff", #"message",
#"Check this out", #"notification_text",
nil];
[facebook dialog:#"apprequests"
andParams:params
andDelegate:self];
}
- (void)dialogDidComplete:(FBDialog *)dialog {
NSLog(#"dialog completed successfully");
}
Are you calling Facebook authorize: somewhere? That's how the fbDidLogin will be triggered. Assuming you are, the behavior indicates that either the token or the date (or both) is nil, or that the date is past expiration (unlikely).
Log the values upon writing and reading the user defaults. My guess is that the authorize either wasn't called, or failed (due to app key or some other problem not shown in the code), leaving the fbDidLogin method uncalled or saving nil values.
That's because you are not asking for permissions when you authorize your app .. "offline_access" provide a long term access token so you will not need to get a new access token every time the user wants to use the Facebook .. so what you need to authorize your app like this
if (![facebook isSessionValid]) {
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"user_likes",
#"read_stream",
#"offline_access"
nil];
[facebook authorize:permissions];
[permissions release];
}
Edit :
Please check the following in your implementation :
1.you need to add the following functions in your application delegate(the Facebook object here is your instance value of FaceBook Class).
// Pre 4.2 support
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
return [facebook handleOpenURL:url];
}
// For 4.2+ support
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [facebook handleOpenURL:url];
}
2.In your info.plist add to URL types > URL Schemes > your Facebook app ID with fb prefix (finally your value will be like this for ex. fb313714***).
I'm having a lot of trouble posting comments to Facebook. Here is how I have got the code setup; in my viewController class I have set up a button that when pressed checks if the user is connected to Facebook. If they're not connected I attempts to make a connection. Here is the code the .h and .m files:
.h file
#import <UIKit/UIKit.h>
#import "FBConnect.h"
#interface Info_Main_ViewController : UIViewController <FBSessionDelegate>
{
Facebook *facebook;
}
#property(nonatomic, retain)Facebook *facebook;
- (IBAction)shareButtonPressed:(id)sender;
- (void)setUpFacebookConnection;
.m file
- (IBAction)shareButtonPressed:(id)sender
{
if (facebook == nil)
{
// Setup Facebook connection
[self setUpFacebookConnection];
}
}
- (void)setUpFacebookConnection
{
facebook = [[Facebook alloc] initWithAppId:#"xxxxxx" andDelegate:self];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"FBAccessTokenKey"]
&& [defaults objectForKey:#"FBExpirationDateKey"])
{
facebook.accessToken = [defaults objectForKey:#"FBAccessTokenKey"];
facebook.expirationDate = [defaults objectForKey:#"FBExpirationDateKey"];
}
if (![facebook isSessionValid])
{
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"publish_actions",
nil];
[facebook authorize:permissions];
}
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [facebook handleOpenURL:url];
}
- (void)fbDidLogin
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[facebook accessToken] forKey:#"FBAccessTokenKey"];
[defaults setObject:[facebook expirationDate] forKey:#"FBExpirationDateKey"];
[defaults synchronize];
}
When I run this code and press the button it opens up safari with a page allowing the user to choose whether to allow the app access to Facebook. Once you accept this it switched back to my app, however the method fbDidLogin never gets called so I can't ever post any messages.
Please can someone help me out, I've spent ages trawling the internet for advice but all of the relevant articles are either outdated or they have the connection to Facebook setup in the app delegate class. Whereas in my situation I only want to user to connect when they choose (i.e. when they press the button).
This method:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [facebook handleOpenURL:url];
}
must be placed in your application delegate. You will have to change the reference to the facebook instance so that it's valid in the app delegate, of course.
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.
iOS beginner here. I'm using the following code to save my facebook accessToken and expirationDate in NSUserDefaults:
facebook = [[Facebook alloc] initWithAppId:#"225083222506272"];
[facebook authorize:nil delegate:self];
NSString *access=[facebook accessToken];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:access, #"accessToken",[facebook expirationDate], #"expirationDate",nil];
[defaults registerDefaults:appDefaults];
And I'm trying to retrieve accessToken and expirationDate in a later call with:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *access=[defaults valueForKey:#"accessToken"];
NSDate *date=[defaults objectForKey:#"expirationDate"];
[facebook fbDialogLogin:access expirationDate:date];
but access and date are null. What am I doing wrong?
The code here is not synchronous. It means it does not block after the call to [facebook authorize:nil delegate:self];. You should instead implement the fbDidLogin delegate method to be notified of when the user has actually logged in successfully. At that point, retrieve the access tokens and save them to user defaults.
Here's a partial sample:
- (void)userClickedFacebookLogin {
[facebook authorize:nil delegate:self]; // delegate is self
}
// Delegate method that you should implement to get notified
// when user actualy logs in.
- (void)fbDidLogin {
// now get the access token and save to user defaults
NSString *access = [facebook accessToken];
// ..
}
Also make sure that the class which has the above code implements the FBSessionDelegate protocol at minimum.
#interface MyClass <FBSessionDelegate> {
}
#end
Look at the DemoApp sample and specifically the DemoAppViewController class from Facebook to get a better idea.