Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error when using [FBSession openActiveSessionWithPublishPermissions: ..]

I'm updating an app to use the latest Facebook SDK in order to gain access to the iOS6 native Facebook support. It currently uses a pretty old version of the Facebook SDK.

The app requires the "publish_actions" permission from Facebook for the only thing it does with Facebook.

I initially thought I could use [FBSession openActiveSessionWithPublishPermissions: ...] but this fails on iOS6 when the user has Facebook configured in iOS6 settings. It fails because of this requirement, from the Facebook docs:

Note, to use iOS 6 native auth, apps need change the way they request permissions from users - apps must separate their requests for read and write permissions. The Facebook SDK for iOS supports these features and helps developers use them to build apps that work on multiple iOS versions and device configurations.

This is a big PITA, IMO. Our preference would be to prompt the user once for permission and be done with it, but the "new" ideal per Apple/Facebook is to prompt for specific permissions in-context when they're needed but not yet granted.

The plan at the moment is to retain our old behavior for iOS5 users and iOS6 users who don't have Facebook configured in Settings. And conform to the new double-prompt for iOS6 users who are using native-access.

The question is, what's the best way to do this? How should I go about detecting if the Facebook SDK will select the iOS6 native login vs the fallback mechanisms? Am I overlooking something obvious?

EDIT:

gerraldWilliam put me onto the right track. His solution would almost work except that ACAccountTypeIdentifierFacebook isn't available in iOS5. Also that if the user blocks FB access in Settings to the app then the accountsWithAccountType call will return an empty array.

It's possible to get around the first problem by asking for the account type matching identifier "com.apple.facebook" - this will return nil on iOS5, and a real account type object on iOS6.

But the second problem is unsolvable. My new plan is to always open the initial session on iOS6 with read-only permissions and prompt later, in context, for publish permission if required. On iOS5 I'll still open the initial session specifying the desired publish_actions permission. Here's the code:

ACAccountStore* as = [[ACAccountStore new] autorelease]; 
ACAccountType* at = [as accountTypeWithAccountTypeIdentifier: @"com.apple.facebook"]; 
if ( at != nil ) {
    // iOS6+, call  [FBSession openActiveSessionWithReadPermissions: ...]

} else  {
    // iOS5, call [FBSession openActiveSessionWithPublishPermissions: ...] 
}
like image 576
TomSwift Avatar asked Oct 10 '12 00:10

TomSwift


2 Answers

ACAccountStore *store = [[ACAccountStore alloc] init];

ACAccountType *accountType  = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
NSArray *accounts = [store accountsWithAccountType:accountType];
NSLog(@"accounts:%@", accounts);

if accounts is nil (or maybe it returns an empty array, I'm not sure), then the user has not configured Facebook in iOS6. You can test for that and if the value indicates that Facebook has not been configured for iOS6, you can call your fallback mechanism.

like image 44
geraldWilliam Avatar answered Sep 28 '22 16:09

geraldWilliam


Based on everything I've read on Facebook's Developer sites (which is somewhat contradictory) the workflow of a "publish only" app is not something to which they've given much thought, and Apple/iOS seems to have disregarded altogether.

Facebook provides some guidance in the docs you referenced:

Tip 5: Disabling the native Login Dialog

In some cases, apps may choose to disable the native Login Dialog to use new versions of the Facebook SDK but to avoid rewriting the ways they request permissions from users. To use the previous behavior of fast-app-switch for login, use the deprecated FBSession methods openActiveSessionWithPermissions and reauthorizeWithPermissions.

This is the route I am currently following. Slightly different, but same general effect.

if (FBSession.activeSession.isOpen  == NO) {
    // This will bypass the ios6 integration since it does not allow for a session to be opened
    // with publish only permissions!
    FBSession* sess = [[FBSession alloc] initWithPermissions:[NSArray arrayWithObject:@"publish_actions"]];
    [FBSession setActiveSession:sess];
    [sess openWithBehavior:(FBSessionLoginBehaviorWithFallbackToWebView) completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
        [self onSessionStateChange:session
                          andState:status
                          andError:error];
    }];

The upshot is, the app will always bypass the IOS6 integration for signing on for publish, and in most cases (since users typically will already have Facebook installed on the phone) switchover to the Facebook app for a single auth approval.

If the user elects to sign-on to our app using their Facebook account, I call openActiveSessionWithReadPermissions, which will use the IOS6 Facebook integration if present. If they subsequently decide to share, I then call reauthorizeWithPublishPermissions which will also use the IOS6 integration if available.

Given the minimal and confusing documentation available I cannot be sure if this is the "right" way to approach this, but it seems to work. You can use the same code for an IOS5 or IOS6 app since it only makes calls through the Facebook SDK. It also honors the not mixing read/publish permissions in the same request Facebook is now promoting.

like image 59
Howard Avatar answered Sep 28 '22 18:09

Howard