Evernote APIのラッパ、EVNConnectを作った
ヒーホー。
Evernote APIの自家製ラッパを作りました。
githubにおいてあります。kent013/EVNConnect · GitHub
- 注1:thriftで生成されたevernote-apiの実装の都合上、リクエストそのものは同期です。(追記:非同期もサポートしました)
せっかちなひとむけ
- kent013/EVNConnect · GitHubをgit clone/ダウンロード
- ENVConnect/ENVConnectをコピー
- ライブラリの設定をする。
- oauthconsumer/KissXMLはソースをコピーするだけじゃ駄目なのでドキュメント読んで。
- URL schemeの設定をする
- コード書く
- 現状サポートしているAPIはEvernote.hを参照の事
はじめに
自分的に次はEvernoteだったので、とりあえずEvernote APIとか読んでたんですが、API呼び出しに必要なauthTokenの取得コードが
EDAMAuthenticationResult* authResult = [userStore authenticate:username :password : consumerKey :consumerSecret];
となってて、usernameとpasswordを入力に与えないといけないみたいで。
正直、UI考えたりするのが面倒くさいので、ううーっとなっていました。
で、いろいろ調べてたら(OFFLINE) Community Messageという投稿がみつかりました。
Julien Boedecさんという方が、OAuthが終わったときに取得できるshardIdとauth_tokenを使えばuserstore初期化する必要ないよ。アクセス先の、shardIdとauthTokenさえ分かればnoteStore使えるよ。
的な事を言ってたので、おおお、とおもい、やってみた次第です。
機能
1, OAuth認証
OAuthConsumerを使いました。
私はiPhoneでしか使わないし、マルチタスクサポートしてないiOSは対象外なので、ダイアログは実装してません。
[evernote_ login]
と書くと、Safariに切り替わって認証が始まります。
2, Request Delegate
EvernoteのAPI実装はThriftを使っているんですが、それに実装されているTHTTPClientは同期的なリクエストをしていました。
NSURLConnectionのsendSyncronousRequestはdelegateを受け取ってくれなくて、アップロードの進捗とかを外部から知る事ができません。
なので、THTTPClientを継承したクラスでasynchronousなリクエストを送り、delegateを設定できるクラスを作りました。ただし、EDAMNoteStoreの実装がsynchronousなリクエストを前提としているので、アップロードが完了するまで処理をブロックするような実装をしました。なので、UIの描画などがおかしくならない様に呼び出し側できちんと実装してあげる必要があります。
追記:結局,自分が利用する用途ではNSOperation中で上記実装を動かそうと思っていたのですが,どうもうまく行かないので,sendSynchronousRequestを送るラッパメソッドと,非同期な普通にNSURLConnectionを使った実装を用意しました.が,正直createNoteしか私は使わないので,ラッパはそれしか実装していません.
ただし,非同期に動作させるための実装はEvernoteNoteStoreClient.mに書いてあるので,必要ならば比較的簡単に実装できるかと思います.
@protocol EvernoteRequestDelegate <NSObject> @optional - (void)requestLoading:(EvernoteRequest*)request; - (void)request:(EvernoteRequest*)request didReceiveResponse:(NSURLResponse*)response; - (void)request:(EvernoteRequest*)request didFailWithError:(NSError*)error; - (void)request:(EvernoteRequest*)request didLoad:(id)result; - (void)request:(EvernoteRequest*)request didLoadRawResponse:(NSData*)data; - (void)request:(EvernoteRequest*)client didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite; @end
のようなNSURLConnectionDelegate/NSURLConnectionDataDelegate的なdelegateを用意しています。
3, EDAMNoteStoreのラッパ
適当にWrapしましたが、私が必要な物しか実装してない上に、未テストなものが多いので、必要なら実装/デバッグしてください。現状サポートしているAPIはEvernoteRequestにあります。
使いかた
- EVNConnect/EVNConnect以下のソースをコピー
- ライブラリの設定
- KissXMLとOAuthConsumerはlibxml2.dylibが必要
- KissXMLはsearch header pathにlibxml2のパスを設定する必要
- RegexKitLiteはlibicucore.dylibが必要
- PDKeychainBindingsControllerはSecurity.Frameworkが必要
- URL schemeの設定をする
- evernoteインスタンスの作成時に必要なcallbackSchemeの設定
- URL schemeを使ってアプリを起動する(Xcode 4.2の場合) - 強火で進め
- コードを書く
基本的にはEvernoteクラスのインスタンスを作って、ログインして、Request取得して実行って感じです。
#import "EVNConnect.h" @interface MainViewController : UIViewController<EvernoteSessionDelegate, EvernoteRequestDelegate>{ __strong Evernote *evernote_; } @property (nonatomic, readonly) Evernote *evernote; @end
みたいに宣言しておいて、
evernote_ = [[Evernote alloc] initWithAuthType:EvernoteAuthTypeOAuthConsumer consumerKey:EVERNOTE_CONSUMER_KEY consumerSecret:EVERNOTE_CONSUMER_SECRET callbackScheme:@"evnconnecttest://authorize" useSandBox:YES andDelegate:self];
とかしてインスタンスを作ります。consumerKey/consumerSecretはEvernoteで申請した奴で、callbackSchemaはProjectのInfoのURL Typeで指定した奴です。
そしたら、
[evernote_ loadCredential];
とすると保存されたauthTokenとshardIdなどが読み出されます。
次に、
[evernote login]
とすると、loadCredentialで読み出された情報が無効なとき、safariに遷移して認証が行われるはずです。
ここまでで、とりあえず認証は終わりですがcredentialをsaveしたりclearしたりするために、EvernoteSessionDelegateをimplementsして
-(void)evernoteDidLogin{ [evernote_ saveCredential]; } - (void)evernoteDidLogout{ [evernote_ clearCredential]; } - (void)evernoteDidNotLogin{ [evernote_ clearCredential]; }
などとしておくと良いでしょう。
最後に、同期的なリクエストを送る場合には,
EDAMNotebook *notebook = [evernote_ notebookNamed:@"test"];
非同期なメッセージを送る場合には,
EDAMResource *resource1 = [evernote_ createResourceFromUIImage:[UIImage imageNamed:@"sample1.jpg"]]; [evernote_ createNoteInNotebook:notebook title:@"testnote" content:@"testnotemogemoge" tags:[NSArray arrayWithObjects:@"Photo", @"Bear", nil] resources:[NSArray arrayWithObject:resource1] andDelegate:self];
とすればいいです.
現状サポートしているAPIはEvernote.hを見てください。
以上〜。