【教學】Facebook SDK 三部曲(上):點一下,分享到Facebook(這一定有什麼誤會!)

讓使用者可以PO上Facebook的功能怎麼做?


你可以:
1. 利用iOS6.0 up的social framework,或是iOS6.0 up 的UIActivityViewController。
2. 利用Facebook SDK。
3. 利用Facebook Graph API。

這主題比較長,所以我們分上下篇來介紹,下篇介紹使用官方做好的UI界面來完成分享功能。

這篇先介紹自己用手工的方式來完成:





為了簡化流程,我們先使用Facebook SDK,Token取得也較容易。(因為偷懶不想用Objective C 寫OAuth2.0認證流程)


我們需要準備:
1. 稍微瞭解一下Facebook Graph API,可以參考這篇:【教學】Facebook SDK 二部曲:從Facebook抓取資料。
2. 做好登入功能的iOS專案,可以從這篇開始做:【教學】Facebook SDK 前傳:準備Social一下。
3. 多個Facebook帳號,Facebook App審核通過後,對每個帳號的分享功能有次數限制,要多PO要收費,換個帳號不花錢,如果在SandBox Mode就不用擔心。



開始唄!


先爬一下Graph API文件,你可以在Publishing項目中找到Publishing with the Graph API

然後在項目Posts跟Other Objects找到我們所需要使用的:
API:https://graph.facebook.com/[user_id]/feed
HTTP Method:POST
Arguments:message, picture, link, name, caption, description, source, place, tags



我們就示範PO:按一下就發佈"我是帥哥!!!"到Facebook塗鴉牆上,您覺得如何?


步驟:
1. 得到使用者授權"publish_actions"的權限,拿回Token 。
2. PO文。


我們使用Facebook SDK的FBSession Class:
+ openActiveSessionWithPublishPermissions:defaultAudience:allowLoginUI:completionHandler:


之後可得到有Publish Permission的Token,

再用FBRequestConnection Class:
+ startWithGraphPath:parameters:HTTPMethod:completionHandler:
或是
+ startForPostStatusUpdate:completionHandler:

設好參數,執行OK完成!!!


寫Code吧!

以下判斷考慮到目前Session是否可用(Session.isOpen)。

不論認證是否成功,Session一定會建立(Session.isOpen),但是卻沒Token可用,最常見就是使用者把認證是關掉了,Session建立但沒有Token,也可以改用檢查Session.state是否是FBSessionStateOpen來判定有沒有認證過。




建好一個UIViewController,View放上UIButton,連上Aciton,


寫上:

- (IBAction)sayButtonAction:(id)sender {
    
    NSArray *publishPermissions = @[@"publish_actions"];
   
    //  Check if this session have publish permission.
    if ([FBSession.activeSession.permissions indexOfObject:@"publish_actions"] == NSNotFound || !FBSession.activeSession.accessTokenData) {
        
        [FBSession openActiveSessionWithPublishPermissions:publishPermissions
                                           defaultAudience:FBSessionDefaultAudienceEveryone
                                              allowLoginUI:YES
                                         completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
            
                                             if (session.isOpen && !error) {
                                                [self publishStory]; 
                                             
                                             }else {
                                                 NSLog(@"open publish permission error : %@", error);
                                             }
        }];
        
    } else {
        [self publishStory];
    }
}

- (void)publishStory
{
    NSString *postWords = @"我是帥哥!!!";
    NSString *httpMethod = @"POST";
    NSString *endPoint = @"me/feed";
    
    NSMutableDictionary *arguments = [[NSMutableDictionary alloc] init];
    [arguments setValue:postWords forKey:@"message"];

    [FBRequestConnection startWithGraphPath:endPoint
                                 parameters:arguments
                                 HTTPMethod:httpMethod
                          completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
                              
                              if (error) {
                                  NSLog(@"Share Error : %@", error);
                                  
                              } else {
                                  NSLog(@"Result : %@", result);
                                  NSLog(@"Token : %@", FBSession.activeSession.accessTokenData);
                              }
    }];
    
////You can use this method, too.
//    [FBRequestConnection startForPostStatusUpdate:postWords completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
//        if (error) {
//            NSLog(@"Share Error : %@", error);
//            
//        } else {
//            NSLog(@"Result : %@", result);
//            NSLog(@"Token : %@", FBSession.activeSession.accessTokenData);
//        }
//    }];
}





 (這一定有什麼誤會...)



Coding完之後


同樣的,你也可以建立FBSession的實體,來管理不同的Token。

FBSession *withPublishSession = [[FBSession alloc] initWithPermissions:publishPermissions];
    [withPublishSession openWithBehavior:FBSessionLoginBehaviorWithFallbackToWebView completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
        ...
    }];


Facebook SDK也是通過Facebook Graph API,如果有必要的話可以用HTTP Request 的方式來取代FBRequestConnection。

ViewController.h
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <NSURLConnectionDataDelegate> {
    NSMutableData *receiveData;
}
- (IBAction)sayButtonAction:(id)sender;

@end



ViewController.m
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

#pragma mark - View Life Cycle

- (void)viewDidLoad
{
 [super viewDidLoad];
    
 [self initParameter];
}

#pragma mark - initParameter

- (void)initParameter {
    receiveData = [[NSMutableData alloc] init];
}

#pragma mark - ShareFunction

- (IBAction)sayButtonAction:(id)sender {
    
    //  me = 目前登入Facebook的User ID
    NSString *shareEndPoint = @"https://graph.facebook.com/me/feed";
    NSString *httpMethod = @"POST";
    NSString *tokenWithPublishAcitonsPermission = @"";
    NSString *words = @"我很帥!!!";
    
//    NSString *requestURL = [NSString stringWithFormat:@"%@%@",  shareEndPoint, tokenWithPublishAcitonsPermission];
    
    NSURL *url = [[NSURL alloc] initWithString:shareEndPoint];
    NSMutableString *argument = [[NSMutableString alloc] init];
    [argument appendString:@"access_token="];
    [argument appendString:tokenWithPublishAcitonsPermission];
    [argument appendString:@"message="];
    [argument appendString:words];
    
    NSData *body = [NSData dataWithBytes:[argument UTF8String] length:argument.length];
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    [request setHTTPMethod:httpMethod];
    [request setHTTPBody:body];
    
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    [connection start];
}

#pragma mark - NSURLConnection Data Delegate

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    NSLog(@"Got Response...");
    
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
    NSLog(@"Http Status Code : %d", httpResponse.statusCode);
    NSLog(@"Response Head : %@", httpResponse.allHeaderFields);
    
    [receiveData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    NSLog(@"Receiving Data...");
    
    [receiveData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    
    NSString *result = [[NSString alloc] initWithData:receiveData encoding:NSUTF8StringEncoding];
    NSLog(@"Result : %@", result);
}
@end

只不過要自己抓Token :p。



Note :

1. 如果使用FBSession靜態方法openActiveSessionWithPublishPermissions要求Read權限,但是裡面有屬於Publish權限的參數,如"email, publish_actions",在編譯的時候就會出現

FBSDKLog: FBSession: a permission request for read permissions contains unexpected publish or manage permissions
2013-07-20 17:25:48.760 FBLogin[3791:c07] *** Terminating app due to uncaught exception 'com.facebook.sdk:InvalidOperationException', reason: 'FBSession: Publish or manage permissions are not permitted to to be requested with read permissions.



2. 但是如果使用Facebook SDK要求Publish權限,參數裡面有屬於Read權限"email, publish_actions"一樣會有:


FBSDKLog: FBSession: a permission request for publish or manage permissions contains unexpected read permissions


不過不會阻止你編譯,過程會先跳出要求Read權限的畫面,再跳出要求Publish權限的畫面。
如果不想讓使用者登入兩次,可以嘗試一下,建立FBSession實體的方法結果亦同。


3. 出現:

Error Domain=com.facebook.sdk Code=5 "The operation couldn’t be completed. (com.facebook.sdk error 5.)" UserInfo=0x9490550 {com.facebook.sdk:ParsedJSONResponseKey={
    body =     {
        error =         {
            code = 2500;
            message = "An active access token must be used to query information about the current user.";
            type = OAuthException;
        };
    };
    code = 400;
}, com.facebook.sdk:HTTPStatusCode=400}

請檢查Token是否為null。


4.  出現The page you requested connot be display right now.......,認證太頻繁了,暫時被擋掉,等會就可用了。




繼續前進:【教學】Facebook SDK 三部曲(下):點一下,分享到Facebook(這是懶人包...)





參考文件:


Graph API

Permissions

Errors


參考範例:


Feed Dialog

Public to Feed





留言

  1. 請問要如何預設image再分享呢?就像分享文字那樣可以預設好要po的文字

    回覆刪除
  2. 如果需求不是很特殊的話,您可以用iOS6的Framework - SLComposeViewController

    例:
    // 建立
    SLComposeViewController *shareView = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];

    // 設定初始的文字及圖片
    [shareView setInitialText:describe];
    [shareView addImage:photo];

    // 設定完成後要執行的指令
    [shareView setCompletionHandler:^(SLComposeViewControllerResult result) {
    ......
    }];

    // 讓使用者看見
    [self presentViewController:shareView animated:YES completion:nil];

    要注意的是,這是直接使用登入在iPhone->"設定"裡的Facebook帳號進行分享,
    如果沒有設定過,SLComposeViewController在建立時會回傳nil,

    如果要支援iOS6以下,或是要讓使用者登入其他帳號,請考慮用Facebook SDK

    感謝你!

    回覆刪除

張貼留言

這個網誌中的熱門文章

【教學】Facebook SDK 首部曲:登入Facebook(這是我的一小步...卻是人類...咦?這麼多人啊?)

【給程式新手】陰魂不散的物件導向?

【教學】Facebook SDK 前傳:準備Social一下