Evernote APIを使うiPhoneアプリの作りかた

EvernoteのiPhoneアプリをよく使っています。アップロードはいいのですが、参照する方の機能がいまひとつに感じていたので、試しに作ってみようかと始めてみたら結構苦労したので書いておきます。

Evernoteのフォーラムを見るとhttp://digitalpericope.net/?p=1http://digitalpericope.net/?p=27チュートリアルのような位置づけぽいので、ここに沿って、iPhoneアプリ開発環境で、Evernote APIを使って、Notebookの一覧を取得するところまでの流れです。

API Keyを取得する

http://www.evernote.com/about/developer/api/から要求します。

数日後に、cunsumer keyとconsumer secretが送られてきて、sandboxを使えるようになります。僕の場合は、3日かかりました。

Xcodeで新規プロジェクトの作成

適当な名前で作成します。

Thriftをダウンロード

http://incubator.apache.org/thrift/download/からダウンロードする。最新が0.2.0だったのでthrift-0.2.0を使います。

それから、thrift-0.2.0/lib/cocoa/src/をEvernoteViewer/Classes/thrift-cocoaとしてコピーします

Evernote APIをダウンロード

https://www.evernote.com/about/developer/api/Evernote API(ZIP)というリンクからダウンロードします。最新が1.14だったので、evernote-api-1.14を使います。

それから、evernote-api-1.14/src/cocoa/をEvernoteViewer/Classes/evernote-cocoaとしてコピーします。

プロジェクトにThriftとEvernote APIを追加

Xcodeに戻り、'3rdParty'というグループを作成し、その下に'Evernote'というグループを作成する。

3rdPartyを右クリック→追加→既存のファイル...、と選択して、コピーした'thrift-cocoa'を選択する。
同じように、3rdParty/Evernoteを右クリック→追加→既存のファイル...、と選択して、コピーした'evernote-cocoa'を選択する。

ここでビルドすると大量のエラーがでるので、これを直していきます。

プロジェクト→プロジェクト設定を編集、でプロジェクトの情報ウィンドウを開き、ヘッダ検索パスに(headerで検索すると見つけやすいです)、'./Classes/thrift-cocoa'を設定し再帰的にチェックを入れる。

'3rdParty/Evernote/evernote-cocoa/thrift'を右クリック→削除、で参照を削除をクリック。

これで、ビルドに成功します。参考にした記事では、使用していないThriftのファイルの参照を削除していますが、そのままにしています。

Notebookを取得する

https://www.evernote.com/about/developer/api/evernote-api.htmの「7.Local Client API Usage Example」にJavaのサンプルがあるので、これをObjective-Cで書けばいいのですが、http://digitalpericope.net/?p=27を参考にしました。

ヘッダーを追加します。

#import "THTTPClient.h"
#import "TBinaryProtocol.h"
#import "UserStore.h"
#import "NoteStore.h"

適当な場所(例えばapplicationDidFinishLaunching)で以下のようにするとNotebookが出力されることを確認できます。USERNAME, PASSWORD, CONSUMER KEY, CONSUMER SECRETはアカウント情報と、送られてきたAPI Keyに直して下さい。

NSURL *userStoreURL = [NSURL URLWithString:@"https://sandbox.evernote.com/edam/user"];
NSString *noteStoreURLBase = @"http://sandbox.evernote.com/edam/note/";

THTTPClient *userStoreHTTPClient = [[[THTTPClient alloc] initWithURL:userStoreURL] autorelease];
TBinaryProtocol *userStoreProtocol = [[[TBinaryProtocol alloc] initWithTransport:userStoreHTTPClient] autorelease];
EDAMUserStoreClient *userStore = [[[EDAMUserStoreClient alloc] initWithProtocol:userStoreProtocol] autorelease];
	
BOOL versionOK = [userStore checkVersion:@"EDMATest" :[EDAMUserStoreConstants EDAM_VERSION_MAJOR] :[EDAMUserStoreConstants EDAM_VERSION_MINOR]];
if(versionOK == YES) {
	@try {
		EDAMAuthenticationResult *authResult = [userStore authenticate:@"USERNAME" :@"PASSWORD" :@"CONSUMER KEY" :@"CONSUMER SECRET"];
		EDAMUser *user = [authResult user];
		NSString *authToken = [authResult authenticationToken];
		
		NSURL *noteStoreURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", noteStoreURLBase, [user shardId]]];
		
		THTTPClient *noteStoreHTTPClient = [[[THTTPClient alloc] initWithURL:noteStoreURL] autorelease];
		TBinaryProtocol *noteStoreProtocol = [[[TBinaryProtocol alloc] initWithTransport:noteStoreHTTPClient] autorelease];
		EDAMNoteStoreClient *noteStore = [[[EDAMNoteStoreClient alloc] initWithProtocol:noteStoreProtocol] autorelease];
		
		NSArray *notebooks = [noteStore listNotebooks:authToken];
		for(int i = 0; i < [notebooks count]; i++) {
			EDAMNotebook *notebook = (EDAMNotebook*)[notebooks objectAtIndex:i];
			NSLog([notebook name]);
		}
	}
	@catch (NSException * e) {
		NSLog(@"Caught %@: %@", [e name], [e reason]);
	}
	@finally {
		NSLog(@"finally");
	}
}
else {
	NSLog(@"NO");
}

Thriftについて

Thriftは、facebookが開発したクロス言語RPCフレームワークで、サーバ間のデータのやりとりに使えます。データの定義があれば、各言語用のライブラリを生成してくれるので、サーバ・クライアントともに言語を問いません。

Evernote APIの例だと、Evernote側でデータを保持し、Thriftのライブラリを配布しているので、今回のようにObjective-Cだけでなく、JavaRubyなどで同じように実装することが可能になります。

http://incubator.apache.org/thrift/about/によると、facebookEvernoteだけではなく、last.fmなどが使っていたり、Vimeoで使えるエンジニアを募集していたりしていました。

Responsibilities
(中略)
・Develop internal application services (Beanstalk, Thrift, Solr, stats)

参考