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
- Fire up XCode and create a new project using File > New > Project
- When prompted for the project template, select “Application” under “iOS” in the menu on the left, then click “Single View Application”. Click “Next”.
- 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:
- 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.
- Evernote’s various SDKs are hosted on Github, including the iOS SDK project.
- Click the “Downloads” link about halfway down on the right hand side.
- 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.
- Unzip the downloaded file and you’ll see a directory that looks a great deal like this:
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:
- Click on the project at the top left corner of the XCode window.
- Click “Build Phases” near the top center of the window.
- Expand the “Link Binary With Libraries” section, then click the plus sign at the bottom left.
- In the sheet that appears, begin typing “Security” in the search field at the top.
Security.frameworkappears in the list, click once to select it, then click “Add”:
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.
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:
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:
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
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
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
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:
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
Next, let’s connect our two text labels (which will display the Evernote username and the note count) to their respective properties in
- Click on
ECViewController.xibin the project explorer on the left to bring up our UI.
- Then, right-click on “File’s Owner” under “Placeholders” to reveal the connections panel.
- Click the empty bubble to the right of
usernameFieldand drag it onto the corresponding label, like so:
- Perform the same action for
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:
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:
This method will:
- Authenticate with the Evernote Cloud API (and display an error message if unsuccessful)
- Retrieve the current user as an
EDAMUserobject. (“EDAM” stands for “Evernote Data Access and Management”, if you’re curious)
- Set the user’s username as the value of our
- 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):
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
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
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
Last, we call our other method,
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
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:
- Request a collection of all of the notebooks in the user’s account (using
- Iterate over that collection of notebooks and retrieve the number of notes for each one (using
The response to
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
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:
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).
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.