libcurlをiPhoneアプリからつかう方法 (ついでにopensslも) | tech.kayac.com - KAYAC engineers' blog
を読んで、面白そうだなーと思い Cの世界でTwitter OAuthを叩くところまでやってみようと思った。調べたらOAuth用のCライブラリもあるようで。
liboauth download | SourceForge.net
とりあえずシミュレータで動かせるかどうかやってみる
結局openssl+libcurlは必要なようなのでまずはそこから。
$ curl -O "http://www.openssl.org/source/openssl-1.0.0a.tar.gz" $ tar zxvf openssl-1.0.0a.tar.gz $ cd openssl-1.0.0a $ CC=/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc ./config --prefix=${PWD}/../libraries $ perl -i~ -pe 's!^CFLAG=!$&-isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.0.sdk!' Makefile $ make $ make install $ cd .. $ ls libraries/lib engines libcrypto.a libssl.a pkgconfig
opensslできた。次libcurl。
$ curl -O "http://curl.haxx.se/download/curl-7.21.1.tar.gz" $ tar zxvf curl-7.21.1.tar.gz $ cd curl-7.21.1 $ ./configure --prefix=${PWD}/../libraries --disable-shared --with-ssl CFLAGS="-arch i386 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.0.sdk -I${PWD}/../libraries/include -L${PWD}/../libraries/lib" CC=/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc $ grep "SSL support" config.log SSL support: enabled (OpenSSL) $ make $ make install $ cd .. $ ls libraries/lib engines libcrypto.a libcurl.a libcurl.la libssl.a pkgconfig
できた。そして最後にliboauth。
$ curl -O "http://liboauth.sourceforge.net/pool/liboauth-0.8.8.tar.gz" $ tar zxvf liboauth-0.8.8.tar.gz $ cd liboauth-0.8.8 $ PKG_CONFIG_PATH=${PWD}/../libraries/lib/pkgconfig ./configure --prefix=${PWD}/../libraries --disable-shared CFLAGS="-arch i386 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.0.sdk" CC=/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc $ make $ make install $ cd .. $ ls libraries/lib engines libcrypto.a libcurl.a libcurl.la liboauth.a liboauth.la libssl.a pkgconfig
全部入った…ぽい。
Xcodeで新しいプロジェクトを作成、上記のインストールディレクトリの libraries/lib 以下の"libcrypto.a", "libcurl.a", "liboauth.a", "libssl.a"をそれぞれプロジェクトに追加。プロジェクトの設定でヘッダ検索パスに libraries/include を指定、 あとzlibへの依存もあるということなので"Other Linker Flags"に"-lz"を追加。
とりあえず****AppDelegate.mに以下のように書いてみた。手抜きにつきconsumer_keyとかは全部直書き。
liboauthの使い方に関しては下記の記事を参考にさせていただきました。
C/C++でTwitterのXAuth認証を行う - 休日奮闘記
#import "HogeAppDelegate.h" #import <oauth.h> @implementation HogeAppDelegate @synthesize window; #pragma mark - #pragma mark Application lifecycle - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. char *consumer_key = "**********************"; char *consumer_secret = "****************************************"; char *access_token = "**************************************************"; char *access_token_secret = "******************************************"; char *req_url = oauth_sign_url2( "http://api.twitter.com/statuses/mentions.json", NULL, OA_HMAC, "GET", consumer_key, consumer_secret, access_token, access_token_secret ); NSLog(@"result: %s", oauth_http_get(req_url, NULL)); [window makeKeyAndVisible]; return YES; } ...
実行してみるとDebug Consoleにmentionsのjson文字列が出力された! ちゃんと認証されたらしい。
xAuthを使ってaccess_token, access_token_secretを取得するのも試してみた。
char *consumer_key = "**********************"; char *consumer_secret = "****************************************"; int argc = 4; char **argv = (char **)malloc(sizeof(char *) * argc); argv[0] = strdup("https://api.twitter.com/oauth/access_token"); argv[1] = strdup("x_auth_username=sugyan"); argv[2] = strdup("x_auth_password=********"); argv[3] = strdup("x_auth_mode=client_auth"); char *req_url = oauth_sign_array2( &argc, &argv, NULL, OA_HMAC, NULL, consumer_key, consumer_secret, NULL, NULL ); for (int i = 0; i < argc; i++) { free(argv[i]); } free(argv); NSLog(@"result: %s", oauth_http_post(req_url, NULL));
…が、
result: (null)
となってしまい、どうもうまく取れず。oauth_http_**** はエラーハンドリングもできないようで微妙である。libcurlをつかって
#import <curl/curl.h> ... char *consumer_key = "**********************"; char *consumer_secret = "****************************************"; int argc = 4; char **argv = (char **)malloc(sizeof(char *) * argc); argv[0] = strdup("https://api.twitter.com/oauth/access_token"); argv[1] = strdup("x_auth_username=sugyan"); argv[2] = strdup("x_auth_password=********"); argv[3] = strdup("x_auth_mode=client_auth"); char *req_url = oauth_sign_array2( &argc, &argv, NULL, OA_HMAC, NULL, consumer_key, consumer_secret, NULL, NULL ); for (int i = 0; i < argc; i++) { free(argv[i]); } free(argv); CURL *curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, req_url); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); CURLcode result = curl_easy_perform(curl); if (result == CURLE_OK) { NSLog(@"success!"); } else { NSLog(@"error: %s", curl_easy_strerror(result)); } curl_easy_cleanup(curl); }
とやってみたら無事にaccess_token, access_token_secretが取れた。liboauthのoauth_http_****でsslがつかえてないっぽい。。ビルドの設定が何か足りてないのかな…?
iPhone実機で
opensslは最新1.0.0aは上記のやり方だとごっそりエラーが出てきてしまって手に負えなそうだったので0.9.8oでごまかすことにした。
$ curl -O "http://www.openssl.org/source/openssl-0.9.8o.tar.gz" $ tar zxvf openssl-0.9.8o.tar.gz $ cd openssl-0.9.8o $ CC=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc ./config --prefix=${PWD}/../libraries $ perl -i~ -pe 's!^CFLAG=!$&-isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.0.sdk!' Makefile $ perl -i~ -pe 's!-arch i386!-arch armv6!' Makefile $ perl -i~ -pe 's!sig_atomic_t intr_signal!int intr_signal!' crypto/ui/ui_openssl.c $ make $ make install
libcurl, liboauthはconfigureオプションに少々追加する程度で大丈夫そう。
$ cd curl-7.21.1 $ ./configure --prefix=${PWD}/../libraries --host=arm-apple-darwin --with-random=/dev/urandom --disable-shared --with-ssl CFLAGS="-arch armv6 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.0.sdk -I${PWD}/../libraries/include -L${PWD}/../libraries/lib" CC=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc $ make $ make install
$ cd liboauth-0.8.8 $ PKG_CONFIG_PATH=${PWD}/../libraries/lib/pkgconfig ./configure --prefix=${PWD}/../libraries --host=arm-apple-darwin --disable-shared CFLAGS="-arch armv6 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.0.sdk" CC=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc $ make $ make install
これでちゃんと実機でも動いた。
感想
まぁCだけでもライブラリ使って動かすことができるらしい、というのは分かった。けどそれほどメリットは感じなかったので、Twitter APIをちょっと叩く程度の用途なら素直にObjective-C用のライブラリを使うのがいいのではないかなー、と。明らかにパフォーマンスに差がある、とかなら考えるけど…
libcurlでのhttpアクセスはNSURLConnectionのdelegate methodたちを実装する手間を考えるとラクかも知れないけど、4.0以降ならGrand Central Dispatch (GCD)で非同期処理させてNSURLConnectionでは sendSynchronousRequest:returningResponse:error: を使って一気にデータを取得するようにするとそれほど面倒でもない気がする。
とりあえずアプリケーション作成時には、後でどうにでも出来るようにOAuthのリクエストURLを作る部分とHTTPアクセスする部分のインタフェースをちゃんと用意しておいて裏で差し替え可能なように設計しておくといいのかな。