&tag(Twitter-OAuth-iPhone); *目次 [#tf833dcf] #contents *参考情報 [#s34a9dab] -[[bengottlieb/Twitter-OAuth-iPhone · GitHub:https://github.com/bengottlieb/Twitter-OAuth-iPhone]] *デモプロジェクトのビルド [#b2aeb473] -zipをダウンロードして展開。Demoフォルダの下にプロジェクトがある。 -OAuthTwitterDemoViewController.mのConsumerKeyとConsumerSecretを設定 #pre{{ #define kOAuthConsumerKey @"" //REPLACE ME #define kOAuthConsumerSecret @"" //REPLACE ME }} **トラブルシューティング [#j72d11fa] *** "Select and Copy the PIN"って何? [#m52c43f2] -callbackurlがセットされてるとうまくいかないのかも。 -[[Issue for Twitter applications with callback URL set · Issue #79 · bengottlieb/Twitter-OAuth-iPhone:https://github.com/bengottlieb/Twitter-OAuth-iPhone/issues/79]]に従ってSA_OAuthTwitterViewController.m を修正。 #pre{{ - (void) webViewDidFinishLoad: (UIWebView *) webView { _loading = NO; //[self performInjection]; if (_firstLoad) { [_webView performSelector: @selector(stringByEvaluatingJavaScriptFromString:) withObject: @"window.scrollBy(0,200)" afterDelay: 0]; _firstLoad = NO; } else { // This else clause modified to work with twitter apps that have the callback URL set: https://dev.twitter.com/apps/ // Bug details: https://github.com/bengottlieb/Twitter-OAuth-iPhone/issues/79 [_engine requestAccessToken]; if ([_delegate respondsToSelector: @selector(OAuthTwitterController:authenticatedWithUsername:)]) [_delegate OAuthTwitterController: self authenticatedWithUsername: _engine.username]; [self dismissModalViewControllerAnimated:YES]; } [UIView beginAnimations: nil context: nil]; _blockerView.alpha = 0.0; [UIView commitAnimations]; if ([_webView isLoading]) { _webView.alpha = 0.0; } else { _webView.alpha = 1.0; } } }} ***GETでパラメータがセットされてない [#d15b26da] -[[SA_OAuthTwitterEngine _sendRequestWithMethod:.... fails to apply params on GET · Issue #80 · bengottlieb/Twitter-OAuth-iPhone:https://github.com/bengottlieb/Twitter-OAuth-iPhone/issues/80]]おそらくバグ。 -以下のように修正。 #pre{{ if (!method && params) { fullPath = [self _queryStringWithBase:fullPath parameters:params prefixed:YES]; } }} *デモプロジェクトの仕組み [#wa6a5550] **起動時 [#s072c155] -OAuthTwitterDemoViewControllerのviewDidApperから開始。controllerがnilでないならば認証用のWebViewが表示されることになる。 #pre{{ UIViewController *controller = [SA_OAuthTwitterController controllerToEnterCredentialsWithTwitterEngine: _engine delegate: self]; if (controller) [self presentModalViewController: controller animated: YES]; else { [_engine sendUpdate: [NSString stringWithFormat: @"Already Updated. %@", [NSDate date]]]; } }} -SA_OAuthTwitterControllerのcontrollerToEnterCredentialsWithTwitterEngineではSA_OAuthTwitterEngineのisAuthorizedにより認証が必要かどうかの判定を行っている。 #pre{{ - (BOOL) isAuthorized { if (_accessToken.key && _accessToken.secret) return YES; //first, check for cached creds NSString *accessTokenString = [_delegate respondsToSelector: @selector(cachedTwitterOAuthDataForUsername:)] ? [(id) _delegate cachedTwitterOAuthDataForUsername: self.username] : @""; if (accessTokenString.length) { [_accessToken release]; _accessToken = [[OAToken alloc] initWithHTTPResponseBody: accessTokenString]; [self setUsername: [self extractUsernameFromHTTPBody: accessTokenString] password: nil]; if (_accessToken.key && _accessToken.secret) return YES; } [_accessToken release]; // no access token found. create a new empty one _accessToken = [[OAToken alloc] initWithKey: nil secret: nil]; return NO; } }} -OAuthTwitterDemoViewControllerのcachedTwitterOAuthDataForUsernameを利用し、[NSUserDefaults standardUserDefaults]からキャッシュデータを取得。キャッシュされているのは以下のような内容 oauth_token=xxxxxxxxxxx&oauth_token_secret=yyyyyyyyyyyyyyyyyyyyyyy&user_id=99999999&screen_name=xxxxxxx -とりだしたデータからOATokenをアロケートし保存。リクエストごとにセットされる。 **認証実証時 [#l3ad4f6f] -SA_OAuthTwitterEngine.mのsetAccessToken:withData:が呼び出され、さらに中で、_delegate storeCachedTwitterOAuthDataが呼び出されデータがキャッシュされる。 #pre{{ - (void) setAccessToken: (OAServiceTicket *) ticket withData: (NSData *) data { if (!ticket.didSucceed || !data) return; NSString *dataString = [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease]; if (!dataString) return; if (self.pin.length && [dataString rangeOfString: @"oauth_verifier"].location == NSNotFound) dataString = [dataString stringByAppendingFormat: @"&oauth_verifier=%@", self.pin]; NSString *username = [self extractUsernameFromHTTPBody:dataString]; if (username.length > 0) { [self setUsername: username password: nil]; if ([_delegate respondsToSelector: @selector(storeCachedTwitterOAuthData:forUsername:)]) [(id) _delegate storeCachedTwitterOAuthData: dataString forUsername: username]; } [_accessToken release]; _accessToken = [[OAToken alloc] initWithHTTPResponseBody:dataString]; } }} -ちなみに、username(=@xxxxで使われるscreen_name)は以下のメソッドで取り出されている。 #pre{{ - (NSString *) extractUsernameFromHTTPBody: (NSString *) body { if (!body) return nil; NSArray *tuples = [body componentsSeparatedByString: @"&"]; if (tuples.count < 1) return nil; for (NSString *tuple in tuples) { NSArray *keyValueArray = [tuple componentsSeparatedByString: @"="]; if (keyValueArray.count == 2) { NSString *key = [keyValueArray objectAtIndex: 0]; NSString *value = [keyValueArray objectAtIndex: 1]; if ([key isEqualToString:@"screen_name"]) return value; } } return nil; } }}