简体   繁体   中英

Access Facebook Accounts on OS X Mountain Lion

As Mountain Lion now officialy has Facebook integrated I wanted to play a little bit with Accounts.framework and Social.framework of OS X.

I set up an App in the Facebook Developer App and used the following code to request access to the Facebook Accounts of the logged in user:

ACAccountStore *acStore = [[ACAccountStore alloc] init];
ACAccountType *accType = [acStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:FB_APP_ID, ACFacebookAppIdKey, @"read_stream, publish_stream", ACFacebookPermissionsKey, ACFacebookAudienceFriends, ACFacebookAudienceKey, nil];


[acStore requestAccessToAccountsWithType:accType options:options completion:^(BOOL granted, NSError *error) {
    if (granted) {
        NSLog(@"Accounts: %@", acStore.accounts);
        NSLog(@"Access granted");
    } else {
        NSLog(@"Access denied");
    }
}];

Now I always get the error Error Domain=XPCObjectsErrorDomain Code=2 "The operation couldn't be completed. (XPCObjectsErrorDomain error 2.)"

When I launched the App from Xcode the first 2-3 times, OS X displayed the confirmation dialog "XYZ wants to access your Facebook Accounts", I clicked ok and I got an error saying something like "The Application is not yet installed". This error now "disappeared" and I'm getting the error noted above.

My question is: Do I have to configure something special in my Xcode Project (Info.plist) or in the Facebook Developer App to make it work with OS X? Or am I missing something in the code? Samples and Tutorials regarding this seem to be very rare :-/

I already watched the WWDC 2012 Video about the Twitter/Facebook Integration but it uses almost exactly the code I used.

Any help is appreciated :-)

Cheers, Björn

Update
I solved the issue, I just did not read the docs carefully enough ;-) I have to pass the permissions as an NSArray and not as a string. I've modified the options dictionary to look like this:

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: FB_APP_ID, ACFacebookAppIdKey, [NSArray arrayWithObjects:@"read_stream", @"publish_stream", @"email", @"user_likes", nil], ACFacebookPermissionsKey, ACFacebookAudienceFriends, ACFacebookAudienceKey, nil];

Now OS X shows an alert that asks me if I want to allow the App to post to Facebook on my behalf, I click OK and a new error appears resulting in no access to the Facebook accounts:

Error Domain=com.apple.accounts Code=7 "The Facebook server could not fulfill this access request: The app must ask for a basic read permission at install time."

I already modified the permissions to be just email or just user_likes but it all resulted in the same error. If I only request access to read_stream the access gets granted but results in the OAuth error 190 with the message Error validating access token: User XXXXXX has not authorized application XXXXXX.

Update 2:
I now solved all my problems, see my answer below.

Alright, I finally solved it :-)

When you first request access to a users Facebook accounts, you may only request permissions from the user listed under "User and Friend permissions" in Facebook's Permission Reference.

Once the user granted access and with that also installed the application on Facebook, you may request any additional permissions required by your App. It's important that you may not ask for read and write permissions at the same time, one after the other! So requesting the permission read_stream and publish_stream in the same request will not work.

This is the basically the code I used:

self.store = [[ACAccountStore alloc] init];

ACAccountType *accType = [self.store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];

NSMutableDictionary *options = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                    FB_APP_ID, ACFacebookAppIdKey,
                                    [NSArray arrayWithObjects:@"email", @"user_about_me", @"user_likes", nil], ACFacebookPermissionsKey, ACFacebookAudienceFriends, ACFacebookAudienceKey, nil];    

[self.store requestAccessToAccountsWithType:accType options:options completion:^(BOOL granted, NSError *error) {
    if (granted && error == nil) {
        self.accounts = self.store.accounts;    
        [options setObject:[NSArray arrayWithObjects:@"read_stream, read_mailbox, read_requests", nil] forKey:ACFacebookPermissionsKey];
        [self.store requestAccessToAccountsWithType:accType options:options completion:^(BOOL granted, NSError *error) {
            if (granted && error == nil) {
                completionHandler(granted, error);
            } else {
                NSLog(@"Access denied 2");
                NSLog(@"%@", [error description]);
            }
        }];
    } else {
        NSLog(@"Error: %@", [error description]);
        NSLog(@"Access denied");
    }
}];

Hope this will help somebody :-)

I would like to add that there is an additional caveat in the Facebook docs:

// if a user has *never* logged into your app, you MUST include one of
// "email", "user_location", or "user_birthday".  Other read 
// permissions can also be included here.

Failure to do this leads to the same error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM