アプリからTwitter,Facebookに投稿する


##前提
・ mBaaSサービスのひとつであるParseを使用
・ 通信にAFNetworkingを使用

##下準備
Parseを使用して、Twitter,Facebookの認証を行うところまでは[こちら](http://dev.classmethod.jp/series/mbaas-な-parse-で遊ぼう/)にくわしく書かれているのでここでは割愛します。
あと[こちらのブログ](http://cccookie.hatenablog.com/entry/2014/03/23/224306)には詳しい手順を書きました。


この中でハマったところと言えば、Twitterのアプリ登録時の`Access level`を`Read-only`から`Read and Write`に変更してなくて、APIが無反応だったところでしょうか。

![twitter.png](https://qiita-image-store.s3.amazonaws.com/0/14605/87911a48-3d51-f971-ba19-f4b3d9087874.png "twitter.png")


##Twitter投稿

###メッセージのみを投稿

```objectivec:メッセージ投稿

//以下の項目をインポートしておく
#import <Parse/Parse.h>
#import <AFNetworking/AFNetworking.h>



//twitter 文章のみ投稿
-(void)tweet:(NSString *)message {
	
	//URLとパラメータを生成
	NSString* url = @"https://api.twitter.com/1.1/statuses/update.json";
	NSMutableDictionary* param = @{@"status":message}.mutableCopy;

	//リクエストにメソッド(POST)、URL、パラメータを設定
	NSMutableURLRequest *tweetRequest = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST"
																		   URLString:url
																		  parameters:param
																			   error:nil];

	//認証
	[[PFTwitterUtils twitter] signRequest:tweetRequest];
	
	//operationの定義
	AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:tweetRequest];
	
	//実行
	[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject){
		
		NSLog(@"success!");
		
	}failure:^(AFHTTPRequestOperation *operation, NSError *error){
		
		NSLog(@"fail!");
		NSLog(@"operation=%@",operation);
		NSLog(@"error=%@",error);

	}];
	
	[[NSOperationQueue mainQueue] addOperation:operation];
}
```

メッセージのみの投稿はこんな感じです。
簡単ですね。



###画像とメッセージを投稿
```objectivec:画像とメッセージを投稿

//以下の項目をインポートしておく
#import <Parse/Parse.h>
#import <AFNetworking/AFNetworking.h>



//twitter 画像添付バージョン
-(void)tweetWithImage:(NSString *)message image:(UIImage *)image{
	
	//受け取ったUIImageをNSData形式に変換
	NSData* data = UIImageJPEGRepresentation(image, 1.0);
	
	// AFHTTPRequestOperationManagerの定義
	AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager];
	manager.responseSerializer = [AFHTTPResponseSerializer serializer];
	
	//URLとパラメータを生成
	NSString* url = @"https://api.twitter.com/1.1/statuses/update_with_media.json";
	NSMutableDictionary* param = @{@"status":message}.mutableCopy;
	
	//リクエストにメソッド(POST)、URL、パラメータ、添付画像を設定
	NSMutableURLRequest *tweetRequest = [manager.requestSerializer multipartFormRequestWithMethod:@"POST"
																					  URLString:url
																					 parameters:param
										 
														   constructingBodyWithBlock:^(id<AFMultipartFormData> formData){

															   [formData appendPartWithFormData:data name:@"media[]"];
															   
														   }
																						  error:NULL];
	
	
	//認証！
	[[PFTwitterUtils twitter] signRequest:tweetRequest];
	
	//送信！
	AFHTTPRequestOperation *operation = [manager HTTPRequestOperationWithRequest:tweetRequest success:^(AFHTTPRequestOperation* operation, id responseObject){
		
		NSLog(@"success!");
		
	}failure:^(AFHTTPRequestOperation* operation, NSError* error){
		
		NSLog(@"operation=%@",operation);
		NSLog(@"eror=%@",error);
		
	}];
	
	
	// データを送信する度に実行される処理を設定する
	//プログレスバーなど
	[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long totalBytesWritten, long totalBytesExpectedToWrite) {
		// アップロード中の進捗状況をコンソールに表示する
		NSLog(@"bytesWritten: %@, totalBytesWritten: %@, totalBytesExpectedToWrite: %@, progress: %@",
			  @(bytesWritten),
			  @(totalBytesWritten),
			  @(totalBytesExpectedToWrite),
			  @((float)totalBytesWritten / totalBytesExpectedToWrite));
	}];
	
	[manager.operationQueue addOperation:operation];
}
```

画像添付の場合も基本的なパターンは同じです。
リクエストの設定で画像を設定しているところと、画像送信で少し待たされることを想定して進捗を取得できるようにしています。
あと、ビルドの環境によってはlongがlong longになるかもしれません。


TwitterのAPIに関しては[本家のドキュメント](https://dev.twitter.com/docs/api/1.1)を参考にするか、
最終的には本家にリンクされているのですが、[こちらのサイト](http://dx.24-7.co.jp/twitterapi1-1-rest-api/)がよくまとまっていてわかりやすかったです。


##Facebookの投稿
###メッセージの投稿

これが投稿の基本パターンになります。

```objectivec:メッセージ投稿

//例によって以下の項目をインポートする
#import <Parse/Parse.h>
#import <FacebookSDK/FacebookSDK.h>
#import <AFNetworking/AFNetworking.h>



-(void)fbpost:(NSString *)message{
	
	//プライバシー(公開範囲)の設定
	NSDictionary* privacy = @{@"value":@"CUSTOM", @"friends":@"ALL_FRIENDS"};
	
	NSMutableDictionary* params = @{@"message":message,
									@"privacy":[dictionary_to_JSON dictionaryToJSON:privacy],
									}.mutableCopy;
	
	//FBリクエストの作成
	FBRequest *request = [FBRequest requestWithGraphPath:@"me/feed"
											  parameters:params
											  HTTPMethod:@"POST"];
	
	
	//コネクションをセットしてすぐキャンセル→NSMutableURLRequestを生成するため???
	//ここはStack Overflowの受け売り
	FBRequestConnection *requestConnection = [request startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
	}];
	[requestConnection cancel];
	
	//リクエストの作成
	NSMutableURLRequest *urlRequest = requestConnection.urlRequest;
	
	//送信！
	AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
	[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
		// Do your success callback.
		NSLog(@"success!");
		
	} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
		// Do your failure callback.
		NSLog(@"fail!");
		NSLog(@"operation=%@",operation);
		NSLog(@"error=%@",error);
	}];
	

	//進捗状況の確認
	[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long totalBytesWritten, long totalBytesExpectedToWrite) {
		NSLog(@"Sent %ld of %ld bytes", totalBytesWritten, totalBytesExpectedToWrite);
	}];
	
	[[NSOperationQueue mainQueue] addOperation:operation];

}
```

プライバシーの設定はJSON形式で埋め込む必要があるため何らかの方法でNSDictionary→JSONの変換をする必要があります。
ここではdictionaryToJSONというクラスメソッドで変換をするという想定で記述しています。
NSMutableURLRequestの設定部分は[Stack Overflow](http://stackoverflow.com/questions/7938430/how-can-i-check-the-progress-of-my-facebook-ios-upload)を参考にしました。



テキストだけじゃなくて画像を添付する場合は以下のように書き換えます。

###画像添付の場合

```objectivec:画像添付

    NSMutableDictionary* params = @{@"message":message,
                                    @"privacy":[dictionary_to_JSON dictionaryToJSON:privacy],
									@"picture":data,
                                    }.mutableCopy;

    //FBリクエストの作成
    FBRequest *request = [FBRequest requestWithGraphPath:@"me/photos"
                                              parameters:params
                                              HTTPMethod:@"POST"];

```

paramsのところに`picture`を追加し、NSData形式の画像データを指定します。
また、requestの`me/feed`が`me/photos`にかわります。


###動画の添付の場合

```objectivec:動画添付

    NSMutableDictionary* params = @{@"message":message,
                                    @"privacy":[dictionary_to_JSON dictionaryToJSON:privacy],
								  @"movie.mp4":data,
									  @"title":@"タイトル",
                                    }.mutableCopy;

    //FBリクエストの作成
    FBRequest *request = [FBRequest requestWithGraphPath:@"me/videos"
                                              parameters:params
                                              HTTPMethod:@"POST"];

```

動画の場合は同じくNSData形式でデータを渡すことには変わりないのですが、
keyが動画のファイル名になるようです。
あとは、動画のタイトルが付加できます。
一方、requestの方は`me/videos`となります。


facebookの資料としては[本家のドキュメント](https://developers.facebook.com/docs/graph-api)のほか、[こちらのサイト](http://fb.dev-plus.jp/reference/coreconcepts/api/)は日本語での解説なので分かりやすかったです。