iPhone用TwitterクライアントでMPOAuthConnectionを使う

Google Code Archive - Long-term storage for Google Code Project Hosting.』のiPhone用サンプルアプリを動かす際の注意点。

  • iPhone用サンプルアプリは、SVNでチェックアウトしたディレクトリ(例えば、mpoauthconnection-read-only)の下層にある、「MPOAuthMobile」。2009年9月11日現在、revision 117。
  • Twitterにアプリケーションを登録して、OAuthのConsumer KeyやConsumer Secretを取得する際、Applilcation Typeは「Browser」を選ぶ。
  • Callback URLに、有効なURLを指定する。私は「承諾ありがとうございました」などと表示するページを用意し、そのURLを指定しました。別に空白ページでもいいけど...
  • RootViewController.mにConsumer KeyとConsumer Secretを入力する。(13と14行目)
  • 40行目のauthenticationURLは削除し、andBaseURLに「http://twitter.com/」を指定する。
 _oauthAPI = [[MPOAuthAPI alloc] initWithCredentials:credentials
                      andBaseURL:[NSURL URLWithString:@"http://twitter.com/"]];
  • httpsにするなら、MPOAuth/Resources/oauthAutoConfig.plistの.twitter.comキーに登録されているURLをhttpsに変更する。
  • iPhone Simulatorでサンプルアプリを起動すると、TwitterOAuth認証ページが開く。承認の後、成功すれば上記で指定したURLにリダイレクトされる。その後、ナビゲージョンツールバーの左側にあるボタンをタップする。テストをする際は、テキストフィールドに「statuses/friends_timeline.xml」などと入力する。
  • 認証をやり直す場合は、OAuthのRequestTokenとAccessTokenのKeyとSecretKeyがキーチェーンに保存されるので、iPhone Simulatorをリセットする必要があるが、これは面倒なので、アプリに認証をリセットするボタンを設け、そのボタンをタップされたらMPOAuthAPIクラスのdiscardServerCredentialsを呼ぶ。
- (IBAction)oauthResetButtonPressed:(id)sender {
 [_oauthAPI discardServerCredentials];
}
  • でも、iPhone Simulator 3.0以降だとキーチェーンから削除されないバグがある。MPOAuthAPI+KeychainAdditionsiPhone.mのremoveValueFromKeychainUsingNameにあるSecItemDeleteの戻り値(OSStatus)をログに出力してみると「errSecParam(-50)」だった。
- (void)removeValueFromKeychainUsingName:(NSString *)inName {
#if 0
 NSMutableDictionary *aKeychainItem = nil;
	
 [self findValueFromKeychainUsingName:inName returningItem:&aKeychainItem];
	
 if (aKeychainItem) {
  SecItemDelete((CFDictionaryRef)aKeychainItem);
 }
#else
 OSStatus status = noErr;
 NSString *serverName = [_baseURL host];
 NSString *securityDomain = [_authenticationURL host];
	
 NSMutableDictionary *searchDictionary = [NSMutableDictionary 
                      dictionaryWithObjectsAndKeys:(id)kSecClassInternetPassword, (id)kSecClass,
                      securityDomain, (id)kSecAttrSecurityDomain,
                      serverName, (id)kSecAttrServer, 
                      inName, (id)kSecAttrAccount,
                      nil]; 
 status = SecItemDelete((CFDictionaryRef)searchDictionary);
 fprintf( stderr, "Remove ItemDelete :: code = %d\n", status );
#endif
}