iPhoneでTwitterにOAuthでアクセスする方法(OAuthConsumer使用)

OAuthConsumerを入手

まず、OAuthConsumerを入手します。オリジナルのOAuthConsumerはiPhone向けに使用するには不都合があるので、iPhone向けに改良されたものを使用するのがいいと思います。

jdg/oauthconsumer – GitHub

Githubにあるので、git cloneでダウンロードします。

Consumerの生成

Twitterにアクセスし、アプリケーションの登録を済ませてください。
以下のようにconsumerを生成します。これは以下の工程で続けて使うのでインスタンス変数などに保存しておいてください。

_consumer = [[OAConsumer alloc] initWithKey:kTwitterConsumerKey
                                     secret:kTwitterConsumerSecret];

未認可のリクエストトークンを取得

まず、未認可のリクエストトークンをTwitterから取得します。

NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/oauth/request_token"];
   
OAMutableURLRequest *request =
    [[[OAMutableURLRequest alloc]
     initWithURL:url
     consumer:_consumer
     token:nil
     realm:nil
     signatureProvider:nil] autorelease];

[request setHTTPMethod:@"POST"];

OADataFetcher *fetcher = [[[OADataFetcher alloc] init] autorelease];

[fetcher fetchDataWithRequest:request
                     delegate:self
            didFinishSelector:@selector(requestTokenTicket:didFinishWithData:)
              didFailSelector:@selector(requestTokenTicket:didFailWithError:)];

取得が完了するとデリゲートが呼ばれますので、リクエストトークンを変数で保持します。
以下のようにWebViewで認可ページを表示します。

- (void)requestTokenTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data {
    if (ticket.didSucceed) {
        NSString *responseBody =
        [[[NSString alloc] initWithData:data
                               encoding:NSUTF8StringEncoding]
         autorelease];
       
        _requestToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody];
       
       
        // WebView
        NSString *urlString =
            [NSString stringWithFormat:
             @"https://api.twitter.com/oauth/authorize?oauth_token=%@",
             _requestToken.key];
       
        NSURLRequest *urlRequest =
            [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
       
        [_webView loadRequest:urlRequest];
    }
}

リクエストトークンを認可済みにする

次に先ほど取得したリクエストトークンをユーザに認可してもらいます。
OAuthではTwitter社のページにリダイレクトさせて行います。

先ほどのコードでWebViewに認可ページが表示されていると思います。
ログイン画面が表示されるので、ここでログインをすると、PINコードという数字が表示されます。このPINコードを次のステップで使用する必要がありますので、Javascriptを利用して取得します。

// WebViewのデリゲートを設定しておいてください
- (void)webViewDidFinishLoad:(UIWebView *)webView {
   
    if (_firstLoad) {
        [webView performSelector:@selector(stringByEvaluatingJavaScriptFromString:)
                         withObject: @"window.scrollBy(0,200)"
                         afterDelay: 0];
        _firstLoad = NO;
    } else {
        NSString *authPin = [self _getAuthPinInWebView:webView];
       
          if (authPin.length) {
            _requestToken.verifier = authPin;
            [self _getAccessToken];
               return;
          }
    }
   
}
// Twitter-OAuth-iPhoneから引用させていただきました
- (NSString *)_getAuthPinInWebView: (UIWebView *) theWebView {
     // Look for either 'oauth-pin' or 'oauth_pin' in the raw HTML
     NSString *js = @"var d = document.getElementById('oauth-pin'); if (d == null) d = document.getElementById('oauth_pin'); if (d) d = d.innerHTML; d;";
     NSString *pin = [[theWebView stringByEvaluatingJavaScriptFromString: js] stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
   
     if (pin.length == 7) {
          return pin;
     } else {
          // New version of Twitter PIN page
          js = @"var d = document.getElementById('oauth-pin'); if (d == null) d = document.getElementById('oauth_pin'); " 
          "if (d) { var d2 = d.getElementsByTagName('code'); if (d2.length > 0) d2[0].innerHTML; }";
          pin = [[theWebView stringByEvaluatingJavaScriptFromString: js] stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
       
          if (pin.length == 7) {
               return pin;
          }
     }
   
     return nil;
}

アクセストークンを取得

これで認証は最後です。

- (void)_getAccessToken {
   
    NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/oauth/access_token"];
   
    OAMutableURLRequest *request = [[[OAMutableURLRequest alloc]
                                    initWithURL:url
                                    consumer:_consumer
                                    token:_requestToken
                                    realm:nil
                                    signatureProvider:nil] autorelease];

    [request setHTTPMethod:@"POST"];
   
    OADataFetcher *fetcher = [[[OADataFetcher alloc] init] autorelease];
   
    [fetcher fetchDataWithRequest:request
                         delegate:self
                didFinishSelector:@selector(accessTokenTicket:didFinishWithData:)
                  didFailSelector:@selector(accessTokenTicket:didFailWithError:)];
}

- (void)accessTokenTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data {
    if (ticket.didSucceed) {
        NSString *responseBody =
        [[[NSString alloc] initWithData:data
                               encoding:NSUTF8StringEncoding]
         autorelease];
       
        _accessToken =
            [[[OAToken alloc] initWithHTTPResponseBody:responseBody] autorelease];
              
    }
   
}

これでアクセストークンを取得できました。
このトークンでAPIを利用します。
ちなみにトークンを保存・復元するにはstoreInUserDefaultsWithServiceProviderNameとinitWithUserDefaultsUsingServiceProviderNameを使います。詳しくはぐぐってください。

APIを叩く

APIの呼び出しも基本的には以上の流れと同じです。

- (void)updateStatus:(NSString *)status {
    NSString *urlString = @"http://api.twitter.com/1/statuses/update.json";

   
    NSURL *url = [NSURL URLWithString:urlString];
   
    OAMutableURLRequest *request = [[[OAMutableURLRequest alloc]
                                     initWithURL:url
                                     consumer:_consumer
                                     token:_accessToken
                                     realm:nil
                                     signatureProvider:nil] autorelease];
   
    [request setHTTPMethod:@"POST"];

    OARequestParameter *statusParam =
        [[[OARequestParameter alloc] initWithName:@"status"
                                            value:status] autorelease];
   
    NSArray *params = [NSArray arrayWithObjects:statusParam, nil];
    [request setParameters:params];
   
       
    OADataFetcher *fetcher = [[[OADataFetcher alloc] init] autorelease];
    [fetcher fetchDataWithRequest:request
                         delegate:self
                didFinishSelector:@selector(updateStatus:didFinishWithData:)
                  didFailSelector:@selector(updateStatus:didFailWithError:)];

}