EvernoteAPI連携を試してみる

先日、Evernote Devcup 2013 Meetup 東北にて開発者枠にて登壇させて頂きました。Evernote APIは3年前にSOICHAでEvernote連携機能の実装以来なので、再度、復習がてらクラウドAPIを使った簡単なiOSのサンプルアプリを一から作ってみました。以前はsliftだったので自分でSDKの出力する形式だったのですが、最近はiOS専用にメンテナンスされているようなので使い勝手は良くなってました。ドキュメントもきちんと日本語で整備されているので、ノート作成程度であれば初めての実装でも1日かからないと思います。

EvernoteクラウドAPI実装手順

本番サーバへのアクセスにはアクティベーションが必要で2、3日程度かかるので、その間にsandbox環境にて実装します。尚、sandbox環境のアカウントとデータは本番サーバとは独立していて連動していないようです。


1. sandbox環境のログインアカウントを作成
開発にはsandboxを利用するのでここで新規アカウントを作成します。
http://sandbox.evernote.com/Registration.action


2. コンシューマキーの取得
EvernoteAPIはOAuth認証を使うのでここでコンシューマキーを取得します。
http://dev.evernote.com/intl/jp/documentation/cloud/
右上の「API KEY」から、使用するアプリケーション毎に取得します。
尚、ここで登録したアプリケーション名はOAuth認証時にユーザに表示されます。

API権限について

ベーシックアクセス:ノート、ノートブック、タグの新規作成、既存データの読込
フルアクセス:全APIのアクセス権限
※フルアクセスを利用する場合はアクティベーション時に理由の説明が必須になります。


3. SDK、必要なFrameworkの組込
GithubからEvernoteSDKをダウンロードし、Xcodeに追加します。
https://github.com/evernote/evernote-sdk-ios

Project Build PhasesのLink Binary With Librariesより「Security.framework」「StoreKit.framework」を追加します。

info.plistにURL schemeを追加します。URL SchemesのItemには「en-{ConsumerKey}」と記述します。


4. アプリ内へのEvernote APIの実装
AppDelegateのHeader

#import "EvernoteSession.h"
#import "ENConstants.h"


AppDelegate#didFinishLaunchingWithOptions

NSString *EVERNOTE_HOST = BootstrapServerBaseURLStringSandbox;
NSString *CONSUMER_KEY = @"your-key";
NSString *CONSUMER_SECRET = @"your-secret";
[EvernoteSession setSharedSessionHost:EVERNOTE_HOST
                                        consumerKey:CONSUMER_KEY
                                    consumerSecret:CONSUMER_SECRET];

セッションの確立時

    EvernoteSession *session = [EvernoteSession sharedSession];
    [session authenticateWithViewController:self completionHandler:^(NSError *error) {
         if (!error && session.isAuthenticated) {
            EvernoteUserStore *userStore = [EvernoteUserStore userStore];
            [userStore getUserWithSuccess:^(EDAMUser *user) {
                 NSLog(@"success evernote session");
            } failure:^(NSError *error) {} ];
         }
    }];

ノート作成時

#import "EvernoteSession.h"
#import "EvernoteUserStore.h"
#import "EvernoteNoteStore.h"
    static NSString *enmlTemplate = @"<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\"><en-note>%@</en-note>";

    EDAMNote *note = [[EDAMNote alloc] init];
    note.title = @"Title";
    note.tagNames = [NSArray arrayWithObject:@"Tag"];
    note.content = [NSString stringWithFormat:enmlTemplate, @"note contents"];

    [[EvernoteNoteStore noteStore]
     createNote:note
     success:^(EDAMNote *note) {
         [[[UIAlertView alloc] initWithTitle:@"Complete" message:@"Success created note." delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil, nil] show];
     }
     failure:^(NSError *error) {}];

EDAMNote#contentはENMLという独自のマークアップ言語を使います。
http://dev.evernote.com/intl/jp/start/core/enml.php
一部のHTML要素は使えないようなのでWebページをそのままクリッピングする場合はタグを変換してあげる必要がありそうです。


5. アクティベーション申請
sandbox上でノート作成の確認が取れたら、取得したコンシューマキーを本番サーバでもアクセスできるようにアクティベーション申請を行います。
http://dev.evernote.com/intl/jp/start/

Evernoteには日本人もいますので日本語でも大丈夫だとは思いますが、急いでいるのであれば英語で申請した方が早く承認されるかもしれません。


6. 本番サーバ接続
アクティベーションされた後は、AppDelegateのEVERNOTE_HOSTをBootstrapServerBaseURLStringUSに変更して本番サーバにてテストします。


OAuth認証

EvernoteSession#authenticateを実行した段階で認証が行われていない場合(有効期限が切れている場合)は、SDKによりWebのログイン画面が自動で表示されます。認証後、Evernoteサイトの設定のアプリケーションのタブに認証済みアプリが表示されるので、ここで認証の取り消しが行えます。


サンプルアプリ

行動ログをEvernoteに取るというアプリを想定して、現在地の地図とその記録時間をEvrenoteに書き込んでいくというiOSのサンプルを書いてみました。
地図の作成は緯度経度を元に、GoogleMapsのStaticMapでURLを作成してENMLに埋め込んでいます。また、住所の割り出しにはiOS SDKのCoreLocationのgeocorderを利用しています。

Githubソースコードを上げました。Xcodeにてビルドすればそのまま動かせると思います。
https://github.com/hmori/LocationHistory



発表資料

Evernote Devcup 2013 Meetup 東北で発表した資料です。



開発者視点ですが、Evernote連携はリソースをユーザーの領域を使うので、データ量の肥大化や負荷が集中した場合にEvrenoteサービスの利用料を心配する必要がありません。例えばEvernoteユーザが前提のアプリであれば、システムストレージをEvrenoteに置くなんて設計も可能です。共有とか文字認識などの機能も備えているのでそれを利用した面白いサービスは考えられそうですね。