Using the Core API on iOS

The Core API is based on HTTP and OAuth and provides low-level calls to access and manipulate a user's Dropbox account.

If you want to follow along, first register a new app on the App Console. You'll need the app key to access the Core API. Then install the iOS SDK and you'll be ready to go.

Authenticating your app

The Core API uses OAuth v1, but the iOS SDK will take care of most of it so you don't have to start from scratch.

You'll need to provide your app key and secret as well as the permission you selected when creating the app. The permission will be represented by either the kDBRootAppFolder or kDBRootDropbox constants.

Once you have your app key and secret, you can create the DBSession object for your app. To do this, add the following code in your application delegate's application:didFinishLaunchingWithOptions: method:

YourAppDelegate.m

#import <DropboxSDK/DropboxSDK.h>

DBSession *dbSession = [[DBSession alloc]
      initWithAppKey:@"INSERT_APP_KEY"
      appSecret:@"INSERT_APP_SECRET"
      root:INSERT_ACCESS_TYPE]; // either kDBRootAppFolder or kDBRootDropbox
[DBSession setSharedSession:dbSession];

Now we're all set to start the authentication flow. We'll start by calling the -[DBSession linkFromController:] method which will ask the user to authorize your app. The linking process will switch to the Dropbox mobile app if it's installed so the user doesn't need to log in again. Otherwise, a Dropbox authorization view will be presented from the specified view controller.

Your view controller

- (IBAction)didPressLink {
    if (![[DBSession sharedSession] isLinked]) {
        [[DBSession sharedSession] linkFromController:self];
    }
}

Creating a URL scheme

The SDK coordinates with the Dropbox app (if it's installed) to simplify the auth process. But in order to smoothly hand the user back to your app, you need to add a unique URL scheme that Dropbox can call. You'll need to configure your project to add one:

  1. Click on your target in the Project Navigator, choose the Info tab, expand the URL Types section at the bottom, and finally, press the + button.
  2. In the URL Schemes enter db-APP_KEY (replacing APP_KEY with the key generated when you created your app).

Now that your app is registered for the correct scheme, you need to add the following code to your application delegate in order to complete the authentication flow:

YourAppDelegate.m

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
    sourceApplication:(NSString *)source annotation:(id)annotation {
    if ([[DBSession sharedSession] handleOpenURL:url]) {
        if ([[DBSession sharedSession] isLinked]) {
            NSLog(@"App linked successfully!");
            // At this point you can start making API calls
        }
        return YES;
    }
    // Add whatever other url handling code your app requires here
    return NO;
}

If you've made it this far, you have a simple app that uses the Core API to link to a Dropbox account. Next, we'll upload a file to Dropbox, get its metadata, and then download it back to our app.

Uploading files

Let's say we're building a text editing app and we want to use it to save your latest magnum opus to Dropbox. The DBRestClient is your gateway to accessing Dropbox once the user has linked their account.

Your view controller

#import <DropboxSDK/DropboxSDK.h>

@interface YourViewController () <DBRestClientDelegate>
@property (nonatomic, strong) DBRestClient *restClient;
@end
...

- (void)viewDidLoad {
    [super viewDidLoad];

    self.restClient = [[DBRestClient alloc] initWithSession:[DBSession sharedSession]];
    self.restClient.delegate = self;
}

Note that a DBSession can be linked with more than one Dropbox, for example you could allow users to connect with both their work and personal Dropboxes. In that case, you'll want to use the -[DBRestClient initWithSession:userId:] method to specify the account. You can get an array of all connected accounts from [DBSession sharedSession].userIds.

Now that you've created a DBRestClient object, you're ready to make requests. First, let's upload a file. -[DBRestClient uploadFile:toPath:withParentRev:fromPath:] takes a local path pointing to a file and a path where we want the file on our Dropbox. For this example, let's upload a local copy of working-draft.txt:

// Write a file to the local documents directory
NSString *text = @"Hello world.";
NSString *filename = @"working-draft.txt";
NSString *localDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *localPath = [localDir stringByAppendingPathComponent:filename];
[text writeToFile:localPath atomically:YES encoding:NSUTF8StringEncoding error:nil];

// Upload file to Dropbox
NSString *destDir = @"/";
[self.restClient uploadFile:filename toPath:destDir withParentRev:nil fromPath:localPath];

When calling this method, filename is the name of the file and toPath is the folder where this file will be placed in the user's Dropbox. If you are uploading a new file, set the parentRev to nil, which will prevent uploads from overwriting existing files. fromPath is the full path of the file you are uploading on the device.

All the methods on DBRestClient are asynchronous, meaning they don't immediately return the data they are meant to load. Each method has at least two corresponding DBRestClientDelegate methods that get called when a request either succeeds or fails. The success callback will give you the data you requested and the failure callback will contain an NSError object that has more details on why the request failed.

- (void)restClient:(DBRestClient *)client uploadedFile:(NSString *)destPath
    from:(NSString *)srcPath metadata:(DBMetadata *)metadata {
    NSLog(@"File uploaded successfully to path: %@", metadata.path);
}

- (void)restClient:(DBRestClient *)client uploadFileFailedWithError:(NSError *)error {
    NSLog(@"File upload failed with error: %@", error);
}

Make sure you call DBRestClient methods from the main thread or a thread that has a run loop. Otherwise the delegate methods won't be called.

If all goes well, the data in your local working-draft.txt will now be in the root of your app folder (or Dropbox folder, depending on your app's access type). The variable metadata will be an DBMetadata object containing the metadata of the newly uploaded file. In this case, we're outputting the path of the newly uploaded file so the output in the console should look like this:

File uploaded successfully to path: /working-draft.txt

Listing folders

Now that your file is in Dropbox, let's glance at the metadata by invoking the metadata method.

Your view controller

[self.restClient loadMetadata:@"/"];

The rest client will call your delegate with one of the following callbacks:

- (void)restClient:(DBRestClient *)client loadedMetadata:(DBMetadata *)metadata {
    if (metadata.isDirectory) {
        NSLog(@"Folder '%@' contains:", metadata.path);
        for (DBMetadata *file in metadata.contents) {
            NSLog(@"	%@", file.filename);
        }
    }
}

- (void)restClient:(DBRestClient *)client
    loadMetadataFailedWithError:(NSError *)error {
    NSLog(@"Error loading metadata: %@", error);
}

Metadata objects are how you get information on files and folders in a user's Dropbox. Calling loadMetadata: on "/" will load the metadata for the root folder, and since it's a folder the contents property will contain a list of files and folders in that folder.

Each file's metadata will include its current revision. Every time a change is made to the file, the rev field of the file's metadata changes as well. By saving the revision when you download the file, you'll be able to tell if that file has been updated by another computer or device and choose to download the newer revision of that file.

Downloading files

Some time has passed and you're ready to start editing that magnum opus of yours again. We'll need the -[DBRestClient loadFile:intoPath:] method to download the file.

Your view controller

[self.restClient loadFile:dropboxPath intoPath:localPath];

Here, dropboxPath is the path in the user's Dropbox (you probably got this from a metadata object), and localPath is the location on the local device you want the file to be put after it has been downloaded. To find out when the file download either succeeds or fails implement the following DBRestClientDelegate methods:

- (void)restClient:(DBRestClient *)client loadedFile:(NSString *)localPath
    contentType:(NSString *)contentType metadata:(DBMetadata *)metadata {
    NSLog(@"File loaded into path: %@", localPath);
}

- (void)restClient:(DBRestClient *)client loadFileFailedWithError:(NSError *)error {
    NSLog(@"There was an error loading the file: %@", error);
}

You can now read the contents of the file from localPath.