iOS5 から Twitter が標準で利用できるようになったので使ってみた。
ちなみに、実装アプリとしてうちの会社でリリースした六曜が検索できるアプリ「Rokuyou」の占い投稿で利用してます(^_^)
Twitter API Content tagged with iOS5 が結構充実しているかと思います。
Twitter を利用するには、Twitter.framework を追加し、ソースに Twitter.h をimport が必要。
#import
※なぜか自動補完が効かない(?)
ちなみに、Twitter.h は TWRequest.h と TWTweetComposeViewController.h を import します。
#import
#import
メールと同様に、Tweet も予め用意されたUI画面から投稿します。
アカウントはiOS5 標準のTwitterアカウント設定を利用(正式には ACAccount)するので、初めて利用する場合は、TWTweetComposeViewController が生成されると自動的にナビゲートされます。 アプリ独自にアカウントを保存する実装が要らないので凄く便利。
利用できるメソッドもそれほど多くないです。
enum TWTweetComposeViewControllerResult {
TWTweetComposeViewControllerResultCancelled,
TWTweetComposeViewControllerResultDone
};
typedef enum TWTweetComposeViewControllerResult TWTweetComposeViewControllerResult;
typedef void (^TWTweetComposeViewControllerCompletionHandler)(TWTweetComposeViewControllerResult result);
UIKIT_CLASS_AVAILABLE(5_0) @interface TWTweetComposeViewController : UIViewController {
}
//Tweet が可能かどうか?
+ (BOOL)canSendTweet;
//初期のメッセージ
- (BOOL)setInitialText:(NSString *)text;
//添付画像追加
- (BOOL)addImage:(UIImage *)image;
//添付画像を全て削除
- (BOOL)removeAllImages;
//URLを追加
- (BOOL)addURL:(NSURL *)url;
//全てのURLを削除
- (BOOL)removeAllURLs;
//Tweet 完了後のハンドラー
@property (nonatomic, copy) TWTweetComposeViewControllerCompletionHandler completionHandler;
- (void)openTweet
{
UIImage *image = [self captureScreen];
TWTweetComposeViewController * composeViewController = [[TWTweetComposeViewController alloc] init];
[composeViewController setInitialText:[self createComment]];
[composeViewController addImage:image];
[self presentModalViewController:composeViewController animated:YES];
}
Tweet を投稿、キャンセル後のハンドラーを取得する事ができますが、completionHandler プロパティにblock文を記述します。 処理の種類はTWTweetComposeViewControllerResult 型で判別します。
TWTweetComposeViewController * composeViewController = [[TWTweetComposeViewController alloc] init];
[composeViewController setInitialText:@"デフォルトコメント"];
composeViewController.completionHandler =
^(TWTweetComposeViewControllerResult result) {
switch (result) {
case TWTweetComposeViewControllerResultDone:
NSLog(@"TWTweetComposeViewControllerResultDone");
break;
case TWTweetComposeViewControllerResultCancelled:
NSLog(@"TWTweetComposeViewControllerResultCancelled");
break;
default:
NSLog(@"other");
break;
}
[self dismissModalViewControllerAnimated:YES];
};
この際、dismissModalViewControllerAnimated: などで終了しておかないと、思わぬ挙動となるので注意が必要です。
TWTweetComposeViewController 予め用意されているコンポーネントですが、 Twitter API を直接利用するには TWRequest を使って、URL、パラメータを指定してリクエストします。
Use TWrequest to send an image with a text to Twitter in IOS5 を参考に画像とテキストを同時に投稿します。
まず、Twitter のメディア投稿 API URLは、Twitter Developer - POST statuses/update_with_media を参照
例えば、画像付きテキストの投稿 URL は
https://upload.twitter.com/1/statuses/update_with_media.json
TWRequest インスタンス生成時に NSURL、TWRequestMethod を指定します。 ※パラメータ(NSDictionary) は任意
TWRequestMethod は以下の3種類
TWRequestMethodGET,
TWRequestMethodPOST,
TWRequestMethodDELETE
データ追加は 各オブジェクト をNSData 変換して addMultiPartData で TWRequest に追加します。
そして最後の送信処理は、performRequestWithHandler でリクエストしますが、これが少々癖があります。 非同期処理なので、Twitter Developer では block 文で記述するのが推奨(と言うかこれしかできない?)されています。
アカウントを取得したい場合は、ACAccountStore で取得可能ですが、複数アカウントが設定できるため、返り値は NSArray です。 ACAccountStore を利用するには、Accounts.framework の読み込みが必要です。
- (NSArray *)fetchAccounts
{
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
NSArray *accounts = [NSArray array];
[accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:
^(BOOL granted, NSError *error) {
if (granted) {
_accounts = [accountStore accountsWithAccountType:accountType];
}
}];
return accounts;
}
これも気になるのが、withCompletionHandler でしょうか? アカウント取得後の処理も非同期処理なので、それを考慮しないといけません。
ACAccountStore で利用できるプロパティは、以下の通り。
- (id)initWithAccountType:(ACAccountType *)type;
@property (nonatomic, readonly) NSString *identifier;
@property (nonatomic, retain) ACAccountType *accountType;
@property (nonatomic, copy) NSString *accountDescription;
@property (nonatomic, copy) NSString *username;
@property (nonatomic, retain) ACAccountCredential *credential;
Identifier は読み込み専用。 ACAccountType の各プロパティは読み込み専用の為、事実上 ACAccountTypeIdentifierTwitter しか利用できないかと思います。 ACAccountCredential は、現時点で OAuthToken の情報を保持します。
以上を踏まえて、投稿とタイムラインの取得をしてみます。 アカウントは、最初のアカウントを取得しているのでちょっと手抜きです。
- (void)requestTweet:(NSString *)message :(UIImage *)image
{
ACAccountStore *store = [[ACAccountStore alloc] init];
ACAccountType *twitterAccountType = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[store requestAccessToAccountsWithType:twitterAccountType
withCompletionHandler:^(BOOL granted, NSError *error) {
if (!granted) {
} else {
NSArray *twitterAccounts = [store accountsWithAccountType:twitterAccountType];
if ([twitterAccounts count] > 0) {
NSURL *url =
[NSURL URLWithString:
@"https://upload.twitter.com/1/statuses/update_with_media.json"];
TWRequest *request = [[TWRequest alloc] initWithURL:url parameters:nil
requestMethod:TWRequestMethodPOST];
[request setAccount:[twitterAccounts objectAtIndex:0]];
if (image != nil) {
NSData *imageData = UIImagePNGRepresentation(image);
[request addMultiPartData:imageData
withName:@"media[]" type:@"multipart/form-data"];
}
NSString *status = message;
[request addMultiPartData:[status dataUsingEncoding:NSUTF8StringEncoding]
withName:@"status" type:@"multipart/form-data"];
[request performRequestWithHandler:
^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
NSDictionary *dict =
(NSDictionary *)[NSJSONSerialization
JSONObjectWithData:responseData options:0 error:nil];
NSLog(@"%@", dict);
dispatch_async(dispatch_get_main_queue(), ^{
});
}];
}
}
}];
}
ACAccountStore *store = [[ACAccountStore alloc] init];
ACAccountType *twitterAccountType = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[store requestAccessToAccountsWithType:twitterAccountType
withCompletionHandler:^(BOOL granted, NSError *error) {
if (!granted) {
} else {
NSArray *twitterAccounts = [store accountsWithAccountType:twitterAccountType];
if ([twitterAccounts count] > 0) {
ACAccount *account = [twitterAccounts objectAtIndex:0];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[params setObject:@"1" forKey:@"include_entities"];
NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/home_timeline.json"];
TWRequest *request =
[[TWRequest alloc]
initWithURL:url parameters:params requestMethod:TWRequestMethodGET];
[request setAccount:account];
[request performRequestWithHandler:
^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (error != nil) {
NSLog(@"%@", error);
} else {
NSError *jsonError;
NSArray *timeline =
[NSJSONSerialization
JSONObjectWithData:responseData
options:NSJSONReadingMutableLeaves
error:&jsonError];
if (jsonError == nil) {
NSLog(@"%@", timeline);
} else {
NSLog(@"%@", jsonError);
}
}
}];
}
}
}];
これで Twitter アプリは一通りできるのではないでしょうか?