Permalink
204 lines (144 sloc) 12.8 KB

Getting Started with the Evernote Cloud SDK for iOS

This document gives a few quick examples and some discussion of the primary classes. For installation instructions, please check out the README.md

##Using the Evernote SDK

Hello World!

Here's a quick example of how easy it is to create and upload a new note from your app:

let note = ENNote()
note.content = ENNoteContent(string: "Hello, World!")
note.title = "My First Note"
ENSession.shared.upload(note, notebook: nil) { (noteRef: ENNoteRef?, error: Error?) in
	// ...
}
ENNote * note = [[ENNote alloc] init];
note.content = [ENNoteContent noteContentWithString:@"Hello, World!"];
note.title = @"My First Note";
[[ENSession sharedSession] uploadNote:note notebook:nil completion:^(ENNoteRef * noteRef, NSError * uploadNoteError) {
	// ...
}];

This creates a new, plaintext note, with a title, and uploads it to the user's default notebook. All you need to do first is get your app setup with the SDK. Here's how.

Adding Resources

Let's say you'd like to create a note with an image that you have. That's easy too. You just need to create an ENResource that represents the image data, and add it to the note before uploading:

let note = ENNote()
note.content = ENNoteContent(string: "Check out this awesome picture!")
note.title = "My Image Note"
let resource = ENResource(image: myImage)
note.add(resource)
ENSession.shared.upload(note, notebook: nil) { (noteRef: ENNoteRef?, error: Error?) in
	// ...
}
ENNote * note = [[ENNote alloc] init];
note.content = [ENNoteContent noteContentWithString:@"Check out this awesome picture!"];
note.title = @"My Image Note";
ENResource * resource = [[ENResource alloc] initWithImage:myImage]; // myImage is a UIImage object.
[note addResource:resource];
[[ENSession sharedSession] uploadNote:note notebook:nil completion:^(ENNoteRef * noteRef, NSError * uploadNoteError) {
	// ...
}];

You aren't restricted to images; you can use any kind of file. Just use the appropriate initializer for ENResource. You'll need to know the data's MIME type to pass along.

Creating a note using HTML or web content.

The SDK contains a facility for capturing web content as a note. This content can be remote of course (generated by your service) or could be loaded locally from resources within your app. You can use +[ENNote populateNoteFromWebView:completion:] to create an ENNote object from the contents of a loaded UIWebView object.

ENNote.populateNote(from: webView) { (note: ENNote?) in
	// upload note if not nil
}
[ENNote populateNoteFromWebView:webView completion:^(ENNote * note) {
	if (note) {
		// upload note
	}
}];  

This method will capture content from the DOM. Images in the page will be captured as ENResource objects in the note (not true of images provided as CSS styles.) Please note that this is not a comprehensive "web clipper", though, and isn't designed to work fully on arbitrary pages from the internet. It will work best on pages which have been generally designed for the purpose of being captured as note content.

If your app doesn't already have your content into visible web views, you can always create an offscreen UIWebView and populate a note from it once loaded. When doing this, please bear in mind that the dimensions of the web view (even when offscreen) can affect the rendered contents. Also note that UIWebView's delegate methods don't indicate when the whole page has "completely" loaded if your page includes linked (remote) resources.

Downloading and displaying an existing note

If you have an ENNoteRef object, either because you uploaded a note and kept the resulting note ref, or because you got one from a findNotes.. operation (below), you can download the content of that note from the service like this (progress optionally sets a block that gets status updates during download):

ENSession.shared.download(noteRef, progress: nil) { (note: ENNote?, error: Error?) in
}
[[ENSession sharedSession] downloadNote:noteRef progress:nil completion:^(ENNote * note, NSError * error) {
}];

But what can you do with a note? Well, you could change parts of the object, and reupload it to e.g. replace the existing note on the service. (See the documentation for uploadNote...). But you can also display it to the user. We've made this easy-- rather than serializing it to HTML and fussing with attached image resources, we've provided a method to generate a single Safari "web archive" from the note; this is a bundled data type which UIWebView natively knows how to load directly. Let's say you have a UIWebView ready to go, called webView:

[note generateWebArchiveData:^(NSData *data) {
	[webView loadData:data MIMEType:ENWebArchiveDataMIMEType textEncodingName:nil baseURL:nil];
}];

This generates the web archive and hands it to the web view. (The generation is asynchronous, but is immediate.) Note that the provided constant ENWebArchiveDataMIMEType has the MIME type for this special kind of data.

Finding notes in Evernote

The SDK provides a simplified search operation that can find notes available to the user. Use an ENNoteSearch to encapsulate a query. (There are a few basic search objects you can use, or create your own with anything valid in the Evernote search grammar). For example, to search for the 20 most recent notes containing the word "redwood", you could use search like this:

ENSession.shared.findNotes(with: ENNoteSearch(search: "redwood"),
                             in: nil,
                             orScope: .personal,
                             sortOrder: .recentlyCreated,
                             maxResults: 20)
{ (findNotesResults: [ENSessionFindNotesResult]?, error: Error?) in
  for result in findNotesResults ?? [] {
    // Each ENSessionFindNotesResult has a noteRef along with other important metadata.
    print("Found note with title: \(result.title ?? "")")
  }
}
[[ENSession sharedSession] findNotesWithSearch:[ENNoteSearch noteSearchWithSearchString:@"redwood"]
                                    inNotebook:nil
                                       orScope:ENSessionSearchScopeDefault
                                     sortOrder:ENSessionSortOrderRecentlyCreated
                                    maxResults:20
                                    completion:^(NSArray * findNotesResults, NSError * findNotesError) {
                                      if (findNotesResults) {
                                        for (ENSessionFindNotesResult * result in findNotesResults) {
                                          // Each ENSessionFindNotesResult has a noteRef along with other important metadata.
                                          NSLog(@"Found note with title: %@", result.title);
                                        }
                                      }
                                    }];

If you specify a notebook, the search will be limited to that notebook. If you omit the notebook, you can specify different combinations of search scope (personal, business, shared notebooks, etc), but please be aware of performance considerations.

Performance Warning Doing a broadly scoped search, and/or specifying a very high number of max results against a user's account with significant content can result in slow responses and a poor user experience. If the number of results is unbounded, the client may run out of memory and be terminated if there are too many results! Business scope in particular can produce an unpredictable amount of results. Please consider your usage very carefully here. You can do paged searches, and have other low-level controls by using the advanced API.

What else can I do?

Other things ENSession can do for you is enumerate all notebooks a user has access to, replace/update existing notes, search and download notes, and fetch thumbnails. You should be able to get started with what's in the headers, starting with ENSession.h.

If you want to do more sophisticated work with Evernote, the primary interface that this SDK provides may not offer all of the functionality that you need. There is a lower-level API available that exposes the full breadth of the service capabilities at the expense of some learning overhead. Have a look at this guide to advanced functionality to get started with it.

##See it in action

Before we get into how to work with the simple object model to programmatically interact with Evernote, give it a spin the even easier way:

Using the Sample App

The SDK comes with a simple sample application, called (shockingly) EvernoteSDKSample so you can see the workflow for basic functionality. This is set up as a target within the Xcode project. Building this project will also build the SDK and link to it as a library. This app demonstrates authentication, creating simple notes, web clips, finding and displaying notes, and using the ENSaveToEvernoteActivity subclass of UIActivity (below).

Note You will still need to edit the AppDelegate of the sample to include your consumer key and secret.

Using the UIActivity subclass (share sheet)

You can let your users send your content into Evernote without building any UI or interacting with the object model at all. You can use the ENSaveToEvernoteActivity class when opening the standard iOS activity panel. The SaveToEvernoteActivity knows how to handle items of type NSString and UIImage (and also can handle pre-created ENResource and ENNote objects). This will place an Evernote logo icon in the activity sheet that the user can choose. They'll get a convenient UI for selecting notebook, title, tags, etc. Use the ENSaveToEvernoteActivityDelegate protocol to be notified whether Save to Evernote activity succeeded, just implement the following function:

- (void)activity:(ENSaveToEvernoteActivity *)activity didFinishWithSuccess:(BOOL)success error:(NSError *)error;

Sample code to use ENSaveToEvernoteActivity:

ENSaveToEvernoteActivity * saveActivity = [[ENSaveToEvernoteActivity alloc] init];
saveActivity.delegate = self;
saveActivity.noteTitle = @"Default title";
NSArray * items = [NSArray arrayWithObject:(self.textView.text)];
UIActivityViewController * activityController = [[UIActivityViewController alloc] initWithActivityItems:items
                                                                                  applicationActivities:@[saveActivity]];
[self presentViewController:activityController animated:YES completion:nil];

##Basic Concepts

Evernote Concepts

The object model in the SDK is designed to reflect a distilled version of the object model you're familiar with as an Evernote user. The most fundamental object in Evernote is the "note" (represented by an ENNote). A note is one chunk of content visible in a user's account. Its body is stored in a form of markup, and may have attached image or file "resources." A note also has a title, timestamps, tags, and other metadata.

Notes exist inside of notebooks, and a user has at least one of these in their account. A user can move notes between notebooks using their Evernote client. Users can also join notebooks shared by other users. A user who is also a member of a Business account will have access to business notebooks that they've created or joined.

The public objects in the SDK generally map to these objects.

ENNote

An ENNote represents the complete set of content within a note (title, body, resources). This object, which you create and populate to upload, or receive as the result of a download operation, doesn't point to any specific note on the service; it's just a container for the content.

An ENNote can sport an array of ENResource objects that are like file attachments. A note has some content (represented by ENNoteContent) that makes up the "body" of the note. You can populate this from plaintext, HTML, etc.

ENNoteRef

On the other hand, an ENNoteRef is an immutable, opaque reference to a specific note that exists on the service, in a user's account. When you upload an ENNote, you'll receive an ENNoteRef in response that points to the resulting service object. This object has convenience functions to serialize and deserialize it if you'd like to store it to access that service note at a later date.

ENNotebook

An ENNotebook represents a notebook on the service. It has several properties that can tell you its name, business or sharing status, etc.

ENSession

The ENSession singleton (accessible via -sharedSession) is the primary "interface" with the SDK. You'll use the session to authenticate a user with the service, and the session exposes the methods you'll use to perform Evernote operations.