iPhone用Twitterアプリのつくりかた

http://farm4.static.flickr.com/3561/3373700426_f9054e78c6.jpg
Twitterと連携したアプリを作成しているところなのですが、何とか自由にTLを取得したりつぶやきをポストできるようになったので、備忘録がてらその方法を紹介します。「iPhoneアプリ作ってみたいけど、ネタがない!」なんて方には参考になるかもしれません。

Twitterの認証方法

現在Twitter APIを利用するための認証方法としては、以下の2つが考えられます。

    • OAuth
    • xAuth

Basic認証が8月下旬に終了とのことで、OAuthを説明したエントリなんかがよくありますね。難しい話はOAuth.netの方に任せますが、基本的にこれからは、TwitterクライアントではOAuthを使用していくことになります。ですがこのOAuth、作成するクライアントによっては面倒な作業が必要になってきます。

OAuthではクライアント固有の、Consumer KeyとConsumer Secret Keyを使用します。またこれらのキーからユーザ自身がTwitterアカウント固有の、Access TokenとAccess Secret Tokenを取得し、それをもってユーザ認証を行ないます。よくTwitterを使用したWebアプリケーションの利用登録時、Twitter公式に飛ばされて「◯◯というアプリとあなたのTwitterアカウントを連携しますか?」といった申請を行ったことがある方も多いかと思います。これがまだWebアプリケーションなら、別ウィンドウでTwitter公式に飛んで、申請されたらWebアプリケーションのトップページにリダイレクトするだけで済みます。しかし作成しているTwitterクライアントがデスクトップアプリケーションなら、ユーザーにわざわざブラウザで作業してもらったり、クライアントに簡易ブラウザを実装したりと話が複雑になってきます。

そこで最近OAuthと並んで話題になっているのがxAuthです。Twitter公式側に自分の作っているクライアントを申請すれば、Consumer KeyとConsumer Secret Keyからプログラム側でAccess TokenとAccess Secret Tokenを取得できるのです。クライアント側で取得したTokenを保存しておけば、従来のBasic認証とほぼ変わらないシステムを作れるのです*1

xAuthでもAccess TokenとAccess Secret Tokenを使うことには変わりないので、今回はOAuthを使用したTwitter APIの利用方法を紹介します。

キー・トークンの取得

いきなり端折ってしまいますが、Consumer KeyやConsumer Secret Keyの取得は以下のTwitter公式ページより行ってください。作成しようと思っているクライアントの基本情報を登録するだけです。投稿機能もクライアントに入れるなら、Default Access typeはRead & Writeにしてください。

Twitter / アプリケーション

次にAccess TokenとAccess Secret Tokenを取得するにはid:shibasonさんの以下のエントリが参考になります。twitter-oauth.rbというRubyスクリプトの、Consumer Key等に関する部分を書き換えてください。

TwitterのbotをOAuthに対応させる - しばそんノート

いよいよXcodeを使ってコーディング

では早速取得したキー・トークンを使って簡単なアプリを作ってみましょう。

まずXcodeを起動し、新規プロジェクトを作成します。とりあえず「View-based Application」にします。

「MyTwitter」とでも名前を付けておきます。

Interface Builderは使用しない系男子

好みは分かれるかもしれませんが、僕はInteface Builderはあまり使用しないので、それらに関する項目を消します。まずはmain.mを以下のように修正します。

#import <UIKit/UIKit.h>

int main(int argc, char *argv[]) {
    
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, @"MyTwitterAppDelegate");
    [pool release];
    return retVal;
}

次に、プロジェクト内のMainWindow.xibを削除します。

最後にMyTwitter-Info.plistを開き、「Main nib file base name」というキーを選択しDeleteキーで削除します。

OAuthライブラリを導入

自力でOAuth認証を実装する気はないのでライブラリを使いましょう。調べてみるとOAConsumerというライブラリが広く使われているそうです。しかしそのままiPhoneアプリに組み込むには少々厄介なので、以下のライブラリを使わせてもらいます。

jdg's oauthconsumer at master - GitHub

ページ右上部分の「Download Source」というリンクからソースファイルをDLしてください*2。DLしたzipファイル、もしくはtarballを展開したら、全てのファイルをプロジェクトに追加します。

READMEにある通り、Security.frameworkとlibxml2.dylibをプロジェクトのフレームワークに追加します。追加すると以下のようなフレームワークが並びます。

最後にヘッダ検索パスの設定を行ないます。以下の画像のようにファイルツリー一番上の「MyTwitter」というプロジェクトファイルを選択し、メニュー一番右の「情報」という青いアイコンをクリックします。

以下のような設定画面が出てきますので、「ヘッダ検索パス」という項目を探してください。

「$SDKROOT/usr/include/libxml2」というパスを追加します。「再帰的」にはチェックを忘れずに!

OAuthConsumerを少々修正

ここまで進めて、とりあえずOAuthConsumerを使用することはできるのですが、コンパイル時に警告が出てしまうので少しソースを修正します。ちょっと自信ないというか無理矢理な修正ですが、おそらく動作に問題はありません。

まずOACall.mでは、140行目辺りの以下のifブロックをコメントアウトします。

// attachFileWithName:filename:data:っていうメソッドがないみたいです。
// if (self.files) {
//   for (NSString *key in self.files) {
//     [request attachFileWithName:@"file" filename:NSLocalizedString(@"Photo.jpg", @"") data:[self.files objectForKey:key]];
//   }
// }

OAToken.mではattributesアクセサメソッドに関する部分を、3箇所修正します。

...
// self.attributes = theAttributes;
self.attributes = (NSMutableDictionary *)theAttributes;
...
// - (void)setAttributes:(NSDictionary *)theAttributes {
- (void)setAttributes:(NSMutableDictionary *)theAttributes {
...
// self.attributes = [[self class] attributesWithString:theAttributes];
self.attributes = (NSMutableDictionary *)[[self class] attributesWithString:theAttributes];
...

TLを取得してみる

それではタイムラインを取得してみましょう。まずMyTwitterAppDelegate.mのapplication:didFinishLauchingWithOptions:メソッドを以下のように記述します。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
  viewController = [[MyTwitterViewController alloc] init];
  [viewController getTimeline];
  [window addSubview:viewController.view];
  [window makeKeyAndVisible];

  return YES;
}

ビューコントローラ側でTL取得メソッドを書きたいと思います。MyTwitterViewController.hのインターフェイス部では、

#import <UIKit/UIKit.h>

@interface MyTwitterViewController : UIViewController {
}
- (void)getTimeline;
@end

MyTwitterViewController.mではヘッダファイルをインポートし、3つのメソッドを実装します。

#import "OAuthConsumer.h"
...
- (void)getTimeline {
  NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/home_timeline.xml"];
  OAConsumer *consumer = [[[OAConsumer alloc] initWithKey:@"CONSUMER_KEY"
                                                   secret:@"CONSUMER_SECRET_KEY"] autorelease];
  OAToken *token = [[[OAToken alloc] initWithKey:@"ACCESS_TOKEN"
                                                secret:@"ACCESS_SECRET_TOKEN"] autorelease];
  OAMutableURLRequest *request = [[[OAMutableURLRequest alloc] initWithURL:url
                                                                  consumer:consumer
                                                                     token:token
                                                                     realm:nil
                                                         signatureProvider:nil] autorelease];
  [request setHTTPMethod:@"GET"];
  OADataFetcher *fetcher = [[[OADataFetcher alloc] init] autorelease];
  [fetcher fetchDataWithRequest:request
                       delegate:self
              didFinishSelector:@selector(ticket:didFinishWithData:)
                didFailSelector:@selector(ticket:didFailWithError:)];
}

- (void)ticket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data {
  NSString *timeline = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
  NSLog(@"%@", timeline);
}

- (void)ticket:(OAServiceTicket *)ticket didFailWithError:(NSError *)error {
  NSLog(@"Error");
}

CONSUMER_KEYやACCESS_TOKENといった部分は先程自分で取得したものに修正してください。コードの大部分はid:sugyanさんの以下のエントリを参考にしました。

Objective-CでTwitter APIを使う 色々 - すぎゃーんメモ

結果は...

早速ビルド&実行してみますと、以下のような具合になります。

ほうほう、ちゃんとXMLで返ってきてますね。あとはこれをパースするだけ...と思いきや!日本語が&#12460;とか文字実体参照になっているじゃありませんか!


と、長くなりすぎたので今日はここまで。次回はこの文字実体参照をアンエスケープする方法を紹介したいと思います。というか全然僕個人のネタがありませんね。ま、バラバラになっていた情報をまとめたということでw

*1:セキュリティ的にBasic認証同様の問題も含みますが

*2:もちろんgit cloneでもOK