API

Evernote and iOS, Sittin’ in a Tree

Posted by Brett Kelly on 24 May 2012

Posted by Brett Kelly on 24 May 2012

Comment

Part of Evernote’s appeal is its ubiquity. Our apps run on just about every major mobile platform in existence, run on both of the big two desktop operating systems and everywhere else (via the web). But we’re not interested in stopping there.

More and more of today’s mobile applications are including the ability to send information to and read information from Evernote. We love this and we want it to continue because the more ways you can access your memories, the better off you are (if you ask us, anyway). As a developer, you have the power to connect with our 30 million users and simultaneously increase the value of your application by giving them a way to connect with their external brain.

Today, we’re launching a series of tutorials for developers new to the Evernote platform (or development in general) who want to integrate their apps with Evernote.

This post will describe exactly how to get started integrating Evernote into your iOS application. We’ll set up a new project in Xcode, download and install the Evernote Software Development Kit (SDK) and create a basic application that talks to Evernote via the Cloud API.

Before we begin, here is what you’re going to need if you want to follow along at home:

  • An account on sandbox.evernote.com, Evernote’s development server. This will be the server used when connecting to the Evernote Cloud API during development. You can create a testing account here.
  • An Evernote API key (request one here). The API key will consist of two parts: a consumer key and a consumer secret. (Note: If you’re developing your own application, know that you’ll need to request that your API key be promoted to production before it can be distributed to users. You can do this at dev.evernote.com/support.)
  • The latest version of Xcode—4.3.2 at the time of this writing—installed on an Intel Mac.

Got all that? Good — let’s get started.

Our application is going to do exactly two things: display the current user’s username and display the total number of notes in that user’s account.

*Let me make it clear right now that this is an idea I cooked up out of thin air; when I began this little project, I had no idea if there was actually an API for easily accessing this information *

Laying the Groundwork

Before we start writing code and impressing people, we need to do some plumbing first. Namely, we need to create our XCode project and install the Evernote SDK for iOS.

Creating the XCode Project

  1. Fire up XCode and create a new project using File > New > Project
  2. When prompted for the project template, select “Application” under “iOS” in the menu on the left, then click “Single View Application”. Click “Next”.
    Screenshot
  3. The next screen will give a series of prompts regarding your new application:
  • Set Product Name to “EvernoteCounter”.
  • Set Company Identifier to anything you’d like. This is used to uniquely identify your application in the world, but we won’t be shipping this or anything, so the actual value is unimportant (though, if you plan on shipping your app, that won’t be the case). I have mine set to “com.somecompany”.
  • Set Class Prefix to “EC” (“EvernoteCounter” abbreviated). This will precede all of our class names when we start writing our code.
  • Set Device Family to “iPhone”.
  • Make sure all three checkboxes are deselected. When you’re finished, the box should look a lot like this: XCode Project Details
  • Finally, you’ll be prompted to select a location where your project will be saved. This can be anywhere you like.

Your XCode project is now set up! Sadly, it needs to sit tight for a couple of minutes while we take care of a few other things.

Downloading and Installing the Evernote SDK for iOS

If we want this strapping young application to be able to talk to Evernote’s Cloud API, we’re going to need the SDK. Let’s grab that now and add it to our project.

  1. Evernote’s various SDKs are hosted on Github, including the iOS SDK project.
  2. Click the “Downloads” link about halfway down on the right hand side.
  3. Once on the Downloads page, click “Download as zip”. This will grab the latest current revision of the SDK, zip it up and hand it over to you.
  4. Unzip the downloaded file and you’ll see a directory that looks a great deal like this: Evernote SDK Download

In the SDK download directory grab the evernote-sdk-ios directory and drag it into EvernoteCounter directory inside your XCode project:

XCode has a couple of questions about what you just did. The defaults are fine here — click “Finish”.

The Evernote SDK for iOS depends on the Security.framework component, so we need to include it in our application’s build process:

  1. Click on the project at the top left corner of the XCode window.
  2. Click “Build Phases” near the top center of the window.
  3. Expand the “Link Binary With Libraries” section, then click the plus sign at the bottom left.
  4. In the sheet that appears, begin typing “Security” in the search field at the top.
  5. When Security.framework appears in the list, click once to select it, then click “Add”: Choose Security.framework

Now that our environment is all set up the right way, it’s time to make the donuts. Or the mobile application. Either one.

Making the App

As mentioned earlier, this app is going to do exactly one thing: log into somebody’s Evernote account and display the total number of notes in that account.

Before we dig into the core functionality of our app, we need to configure it to authenticate with the Evernote Cloud API using OAuth. Thankfully, the iOS SDK makes this relatively painless and we can get the job done in just a couple of minutes.

Configuring OAuth

First, we need to modify our trusty app delegate, ECAppDelegate.m. By default, Xcode automatically creates the didFinishLaunchingWithOptions method for us. Before we make any modifications to this method, it will look like this:

EN-FirstENiOSApp.markdownClick the image to view this code on Github

In order for OAuth to work, we need to set up the EvernoteSession instance with the correct host and authentication credentials. Modify ECAppDelegate.m to look like this:

EN-FirstENiOSApp.markdownClick the image to view this code on Github

The EVERNOTE_HOST is the remote host with which we’ll be interacting. While your app is in development, you’ll want to connect to sandbox.evernote.com, our testing service. Before shipping your app, be sure to change EVERNOTE_HOST to www.evernote.com.

CONSUMER_KEY and CONSUMER_SECRET are the two parts of the API key we made sure we had at the beginning of this tutorial. You’ll need to replace the placeholder values with your actual key and secret before your app will run.

Next, we call EvernoteSession, passing the host, consumerKey and consumerSecret parameters with the values we just defined. Now, [EvernoteSession sharedSession] will return a reference to the singleton that will be used anytime the app needs to interface with the Evernote Cloud API.

Oh, and we can’t forget to include the EvernoteSession.h header file. Add the include statement just after our ECViewController.h is included at the top of ECAppDelegate.m:

EN-FirstENiOSApp.markdownClick the image to view this code on Github


Building the User Interface

It’s time to make a simple interface for our app. On the left-hand side, click ECViewController.xib. This will load an iPhone-sized canvas where we can drag, draw and arrange UI elements: buttons, text fields, etc. For this app, we’re going to need a couple of text fields (one for the Evernote username and one for the note count), a label for each text field and a button to get things going. (Note that the text fields are actually UILabels whose value is set dynamically — more on that in a bit).

Drag all of the UI elements out of the Object library onto your base view. It should look something like this when you’re finished:

EvernoteCounter UI - In Progress

We’re going to need IBOutlet declarations and an IBAction method to handle the clicking of our lone button. Let’s add those instance variables and method signature to our ECViewController.h file:

EN-FirstENiOSApp.markdownClick the image to view this code on Github

Next, let’s connect our two text labels (which will display the Evernote username and the note count) to their respective properties in ECViewController (usernameField and noteCountField).

  1. Click on ECViewController.xib in the project explorer on the left to bring up our UI.
  2. Then, right-click on “File’s Owner” under “Placeholders” to reveal the connections panel.
  3. Click the empty bubble to the right of usernameField and drag it onto the corresponding label, like so: Assign property to UILabel
  4. Perform the same action for noteCountField.

Now we need to attach our one button to the retrieveUserNameAndNoteCount method we defined earlier. To do this, hold the Control key and drag the button onto the “File’s Owner” placeholder. Once you release the mouse button, select retrieveUserNameAndNoteCount from the “Sent Events” pop-up.

We’ve got our text fields and button all wired up to do stuff, so now let’s build out the “under the hood” stuff in ECViewController.m. Here’s the file, unmodified, as generated by XCode:

EN-FirstENiOSApp.markdownClick the image to view this code on Github

In order to fulfill our feature requirements (display the user’s name and the number of notes in their account), we’re going to create two methods. The first one, naturally, will be the method called when our single button is tapped: retrieveUserNameAndNoteCount.

This method will:

  1. Authenticate with the Evernote Cloud API (and display an error message if unsuccessful)
  2. Retrieve the current user as an EDAMUser object. (“EDAM” stands for “Evernote Data Access and Management”, if you’re curious)
  3. Set the user’s username as the value of our usernameField UILabel.
  4. Call another method while will retrieve our total note count for the current user.

Here’s our complete method (which we’ll cover in detail):

EN-FirstENiOSApp.markdownClick the image to view this code on Github

Don’t worry — we’ll get through this together.

First, we grab a local instance of EvernoteSession (which, because it’s a singleton, is the same instance we initialized in ECAppDelegate.m). Then, we call authenticateWithViewController; this method takes two parameters: a copy of the current UIViewController (self, in this case) and two blocks. The first will be called if the authentication request fails and will accept an NSError instance explaining why. The second is called if the authentication succeeds. This method attempts to authenticate our session with the Evernote Cloud API (more on the guts of this in the “OAuth Exposed” section below). If there’s an error during authentication or the authentication fails for some reason, we’ll log this information using NSLog and display a dialog box (an instance of UIAlertView) on the screen informing the user that authentication didn’t pan out.

If the authentication does pan out, then we can move on with the meat of our app. It’s important to remember that, once an auth token is issued to your app, it will persist in the system keychain for a full year before the user needs to authorize the app again. However, if the user removes your app and reinstalls it later, they’ll need to go through the authorization process again.

First, we need to figure out whose account we’re working with. To do this, we create a local instance of EvernoteUserStore (userStore) and call its getUserWithSuccess method. This is an asynchronous call whose callback functions are implemented as blocks (anonymous functions, essentially). The first block takes a single EDAMUser parameter and indicates that the call was successful. The second block (failure) takes a single instance of NSError that will describe what exactly went south. If an error does occur, the application simply logs it and does nothing more.

If the API call is successful, we query our EDAMUser instance for the username property and set that as the value for our usernameField UILabel.

Last, we call our other method, countAllNotesAndSetTextField:

EN-FirstENiOSApp.markdownClick the image to view this code on Github

This method, as I hope the name adequately implies, counts the notes in the current user’s Evernote account and displays it on the screen. Let’s walk through how this works. Together.

First, we’re going to declare a counter variable called noteCount. This variable will be used to keep track of the total number of notes in the account (more on this in a second).

Then, we create a local instance of EvernoteNoteStore called noteStore; using this object, we’ll query the Evernote Cloud API for notes, notebooks, etc., using methods like listNotebooksWithSuccess (which we conveniently call on the next line). Because the Cloud API doesn’t offer a way to retrieve a count of all of the notes in a user’s account, we need to proceed thus to accomplish our second objective:

  1. Request a collection of all of the notebooks in the user’s account (using listNotebooksWithSuccess).
  2. Iterate over that collection of notebooks and retrieve the number of notes for each one (using findNoteCountsWithFilter).

The response to listNotebooksWithSuccess, like getUserWithSuccess, is a pair of blocks. The first handles the successful response from the server and takes a single NSArray parameter, which is a collection of EDAMNotebook objects — one for each notebook in the user’s account.

Each of the EDAMNotebook objects we have contains a unique GUID that uniquely identifies that notebook. Using that GUID, we create a EDAMNoteFilter instance that will allow us to find notes that are only part of that notebook. And, finally, with our EDAMNoteFilter as a parameter, we call findNoteCountsWithFilter to get our note count for this notebook (as an instance of EDAMNoteCollectionsCounts).

The second block parameter is called if findNotesWithFilter fails. It takes a single instance of NSError which the API will populate with the details of why the API call failed.

Once we have our count, we add it to our noteCount counter variable and update the noteCountField on the screen, producing this result:

OAuth Exposed

If the session isn’t authenticated (doesn’t already have an auth token issued by the API, in other words) when the user taps our single button, the app will spawn an instance of UIWebView displaying the Evernote Web site. From there, the user must login to their Evernote account, then authorize our app to access their account.

After the user taps “Authorize”, the web page will close and the application will continue as though the button has just been tapped. If all goes well, our username and total note count will be displayed on the screen (as pictured above).

In Closing

A few things before we wrap this beast up.

EvernoteCounter is designed to highlight the ease of integrating and using our iOS SDK. If this were a real, production application, a good deal more would have been done to ensure that potential error conditions were handled, “defensive” programming practices were utilized, etc. However, because I felt such things could easily make the code more difficult to read and understand, they were omitted in service of clarity.

The entire EvernoteCounter Xcode project is available for your perusal on Github. If you’d like to help make the code better, feel free to fork the project and submit a pull request with your changes. (Note that we aren’t looking for new features, only improvements that would make this app more valuable as a learning tool).

I’d love to hear what you guys think about all this. If you have any comments or questions, drop them in the comment section below and I’ll do what I can to assist.

View more stories in 'API'

11 Comments RSS

  • @CorettaJackson

    This is great to hear!!

    I recently updated to Evernote Premium and I wish I’d done so long ago!

    Let the note-taking & sharing begin : )

  • Dan Schilling

    Love the very detailed tutorial. Although, how much different would the code be with ARC and storyboard – which I don’t know why you guys didn’t use. I am new to iOS dev and would rather learn everything from ios5 and onwards.

    • Brett Kelly

      Hi Dan — I’m actually working on a document describing how our SDK can be used with an ARC-enabled project. Keep an eye on dev.evernote.com and I’ll get it up ASAP. Thanks for reading!

  • Andy Dent

    You left out one step – people need to edit the EvernoteCounter-Info.plist and twist open the topmost entry:
    URL types / Item 0 / URL Schemes
    the Item 0 within URL Schemes needs changing from your ID to match the CONSUMER KEY entered in the source code earlier PLUS A PREFIX of “en-”

    ie: the URL Scheme in github is currently “en-inkedmn” because your key is “inkedmn”.

  • Patrick Santana

    Hey Guys,

    The session should be created like that:

    [EvernoteSession setSharedSessionHost:EVERNOTE_HOST
    consumerKey:CONSUMER_KEY
    consumerSecret:CONSUMER_SECRET];

  • Patrick Santana

    Also, in the EvernoteCounter-Info.plist, it is necessary yo add:

    CFBundleURLTypes

    CFBundleURLSchemes

    en-your key

  • Patrick Santana

    Itt is a great api. Congratulations.

    I deliberated used wrong credentials and I see that the error returned was a HTML based message. It would be great to have a JSON response.

  • ddsakura

    I git clone the sample project from github,
    and set up the key/secret and CFBundleURLSchemes,
    but when I click “get note count!” button (in simulator)
    the sample app doesn’t redirect me to mobile safari.
    and give me the html response and seem the error is “User could not be authenticated.”
    does any step I miss? or it is a bug?
    thanks

    • ddsakura

      finally, I found I need to sign up a new api key, new api key can work well, but old api key will encounter User could not be authenticated problem

  • andrew

    Nice tutorial. Thanks..

    Any pointers to using the SDK on an Android app?