SLRequest を使用して Facebook の投稿を作成する際に問題を引き起こす主な原因は、基本的に 2 つあります。 1. ユーザーが Facebook でアプリのアクセス許可を削除します。これによりエラー 2500 が発生し、アプリを「再インストール」して権限を最初から取得する必要があることを意味します。2. トークンの有効期限が切れています。ここで行う必要があるのは、資格情報を更新することだけです。
私の問題は主に最初のものにあります。資格情報の更新は処理できましたが、「renewbigtime」(私が好きなように呼んでいます) しようとしたり、アプリを再インストールして権限を再度取得しようとすると、非常に困難になります。
これが私のFacebook投稿コードのレイアウトです(なぜ私がこのようにするのかについての説明についてはコメントを参照してください):
まず、ユーザーは設定ビュー コントローラーで Facebook 共有をオンにする必要があります。
-(void)facebookpost {
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType * facebookAccountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
NSArray *accounts = [accountStore accountsWithAccountType:facebookAccountType];
//why two permissions and dictionaries? Well, before you can post to Facebook, you have to get basic read permissions, such as email. If you attempt to obtain both of these permissions, you will fail. So, the app tries for permission of email first, if it succeeds, it tries for permission for publish_stream.
NSArray * permissions = @[@"email"];
NSArray * permissions2 = @[@"publish_stream"];
NSDictionary * dict = @{ACFacebookAppIdKey : @"289006474446717", ACFacebookPermissionsKey : permissions, ACFacebookAudienceKey : ACFacebookAudienceFriends};
NSDictionary * dict2 = @{ACFacebookAppIdKey : @"289006474446717", ACFacebookPermissionsKey : permissions2, ACFacebookAudienceKey : ACFacebookAudienceFriends};
[accountStore requestAccessToAccountsWithType:facebookAccountType options:dict completion:^(BOOL granted, NSError *error) {
if (granted && error == nil) {
//the following defaults just sets a key value which will be checked to see if the app should try and post anything
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"facebook"];
[[NSUserDefaults standardUserDefaults] synchronize];
//nothing gets posted yet, onto try for permissions to post
[accountStore requestAccessToAccountsWithType:facebookAccountType options:dict2 completion:^(BOOL granted, NSError *error) {
if(granted && error == nil) {
//good, it is now granted permission for both reading and writing
} else {
NSLog(@"1error is: %@",[error description]);
}
}];
} else {
NSLog(@"error is: %@",error );
if(error.code == 6){
//this is the error message that will appear if the user has not signed into Facebook from Settings app. alertmessage simply pops up an alert instructing them to please do so.
[self performSelectorOnMainThread:@selector(alertmessage)
withObject:nil
waitUntilDone:YES]; }
}
}];
}
さて、投稿コードに取り掛かります。このコードは、Table View の Detail View Controller にあります。テーブル ビューには記事が一覧表示され、いずれかをクリックすると、webView を使用して詳細ビューに表示されます。viewWillAppear で、アプリは「facebook」キーの bool 値をチェックします。NO の場合は、記事を表示するだけです。YES の場合、ウォールへの投稿を試みます (説明については、もう一度コメントを参照してください)。
-(void)writetowall {
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
NSArray *accounts = [accountStore accountsWithAccountType:accountType];
ACAccount *account = [accounts lastObject];
NSDictionary *parameters = @{@"message" : [NSString stringWithFormat:@"I'm reading %@ from the blog. Click the link to read it too.", _entry.articleTitle], @"link": _entry.articleUrl};
NSURL *URL = [NSURL URLWithString:@"https://graph.facebook.com/me/feed"];
SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeFacebook
requestMethod:SLRequestMethodPOST
URL:URL
parameters:parameters];
[request setAccount:account];
[request performRequestWithHandler:^(NSData *responseData,
NSHTTPURLResponse *urlResponse, NSError *error) {
NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData
options:kNilOptions
error:&error];
NSDictionary *errorDictionary = [responseDictionary valueForKey:@"error"];
if (errorDictionary) {
NSNumber *errorCode = [errorDictionary valueForKey:@"code"];
if ([errorCode isEqualToNumber:[NSNumber numberWithInt:190]]) {
//190 is code that you need to renew credentials. this is when tokens expire. so, if it happens, it goes to renew code (not included in this question as it is working fine)
NSLog(@"Renew");
[self renew];
}
if ([errorCode isEqualToNumber:[NSNumber numberWithInt:2500]]) {
//here is the 2500 code meaning the app has not been installed yet, or needs to be installed again with new permissions. so, I have it run the method renewbigtime which I will now list below
[self renewbigtime];
}
}
}];
}
ユーザーが Facebook AppCenter に移動し、アプリの横にある [X] をクリックすると、投稿しようとするとエラー コード 2500 が表示されるため、このメソッドがトリガーされます。パーミッション:
-(void)renewbigtime {
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType * facebookAccountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
NSArray *accounts = [accountStore accountsWithAccountType:facebookAccountType];
NSArray * permissions = @[@"email"];
NSArray * permissions2 = @[@"publish_stream"];
NSDictionary * dict = @{ACFacebookAppIdKey : @"289006474446717", ACFacebookPermissionsKey : permissions, ACFacebookAudienceKey : ACFacebookAudienceFriends};
NSDictionary * dict2 = @{ACFacebookAppIdKey : @"289006474446717", ACFacebookPermissionsKey : permissions2, ACFacebookAudienceKey : ACFacebookAudienceFriends};
[accountStore requestAccessToAccountsWithType:facebookAccountType options:dict completion:^(BOOL granted, NSError *error) {
if (granted && error == nil) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"facebook"];
[[NSUserDefaults standardUserDefaults] synchronize];
[accountStore requestAccessToAccountsWithType:facebookAccountType options:dict2 completion:^(BOOL granted, NSError *error) {
if(granted && error == nil) {
//here is where it should be granted and no errors for anything, so we redirect to writetowall method which should simply post to the wall
[self writetowall];
} else {
NSLog(@"1error is: %@",[error description]);
}
}];
} else {
NSLog(@"error is: %@",error );
if([[error description] isEqualToString:@"Error Domain=com.apple.accounts Code=6 \"The operation couldn’t be completed. (com.apple.accounts error 6.)\""]){
[self performSelectorOnMainThread:@selector(alertmessage)
withObject:nil
waitUntilDone:YES]; }
}
}];
}
問題は、この時点でアプリがループに陥ることです。エラー 2500 が発生した場合、資格情報を更新しようとしますが、エラー 2500、更新の試行、2500、更新の試行が引き続き発生します。renewbigtime セクションで他のエラー メッセージがトリガーされることはありません。