Using the Sync API on iOS

The Sync API takes care of syncing all your data with Dropbox through a familiar, file system-like interface. It's like giving your app its own, private Dropbox client.

Here are the four things you'll need to work with when building on the Sync API:

Account manager

The account manager (DBAccountManager) is your starting point. It lets your app start the authentication process to link with a user's Dropbox account. Once the app is linked, you can create a file system object.

File system

The file system object (DBFilesystem) acts like a private, local file system that is automatically synced to Dropbox. You can perform all the standard operations you'd expect, such as listing files and folders, and editing, moving, or deleting them. Once the file system is created, it immediately starts syncing the file info (though not files' contents) for everything your app can see based on its permission.

Files

Once you've created or opened a file (DBFile), you can start working with data. The Sync API will automatically download the file so you can read it. Write to the file and the Sync API will push any changes back to the server.

Observers

You can also observe changes to a file or path so you can update your app's state when new data is available. When an observer is called, check the file status to see what's changing.

If you want to follow along, set up a Sync API project before you dive in.

Heads up: The Sync API doesn't support the Full Dropbox permission. Learn more about the available permissions for API apps.

Linking accounts

To start interacting with the Sync API, you'll need to create a DBAccountManager object. This object lets you link to a Dropbox user's account which is the first step to working with data on their behalf. A good place to create this object is in your app delegate's -application:didFinishLaunchingWithOptions: method.

YourAppDelegate.m
Be sure to replace APP_KEY and APP_SECRET with the real values for your app which could be found in the App Console.
#import <Dropbox/Dropbox.h>

- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)opts {
    DBAccountManager *accountManager =
        [[DBAccountManager alloc] initWithAppKey:@"APP_KEY" secret:@"APP_SECRET"];
    [DBAccountManager setSharedManager:accountManager];

    return YES;
}

The next step is to link to a user's account. Make this call from an action, such as a 'Link to Dropbox' button in your app.

Your view controller
- (IBAction)didPressLink {
    [[DBAccountManager sharedManager] linkFromController:YOUR_ROOT_CONTROLLER];
}

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. Once the user completes the authorization step, Dropbox will redirect them back to your app using the URL scheme you registered when setting up the SDK. Your app needs to handle those requests to complete the auth flow.

YourAppDelegate.m
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
sourceApplication:(NSString *)source annotation:(id)annotation {
    DBAccount *account = [[DBAccountManager sharedManager] handleOpenURL:url];
    if (account) {
        NSLog(@"App linked successfully!");
        return YES;
    }
    return NO;
}

The user only has to link once. Once they've linked, the Sync API will automatically store the user's account info on the device. When your app restarts, you can check whether it is already linked by calling linkedAccount.

Working with files

Once you've linked to a user's account, you can get the associated DBFilesystem which you'll use to access the user's Dropbox.

DBAccount *account = [[DBAccountManager sharedManager] linkedAccount];

if (account) {
    DBFilesystem *filesystem = [[DBFilesystem alloc] initWithAccount:account];
    [DBFilesystem setSharedFilesystem:filesystem];
}

With a file system in hand, you can start reading and writing files (represented by a DBFile). If you're using the App folder permission, your App Folder won't contain any files when a user first links with your app, but it's easy to create one.

DBPath *newPath = [[DBPath root] childPath:@"hello.txt"];
DBFile *file = [[DBFilesystem sharedFilesystem] createFile:newPath error:nil];
[file writeString:@"Hello World!" error:nil];

Writing to the file will succeed even if you are offline, and automatically sync to the server once your app comes back online. There are other ways to write to a file depending on your needs, such as using an NSData object or a path to an existing file. Reading a file is just as easy.

DBPath *existingPath = [[DBPath root] childPath:@"hello.txt"];
DBFile *file = [[DBFilesystem sharedFilesystem] openFile:existingPath error:nil];
NSString *contents = [file readString:nil];
NSLog(@"%@", contents);

If the file isn't cached yet, -readString: will wait while the file downloads. If you'd like your app to instead be notified when the file is cached and ready to be read, you can add an observer.

Observing changes

A DBFile is associated with a specific version of that file. You can check whether it's cached and can be read immediately by using the status property. If it's not cached, the -readString: call will wait while it downloads. If you don't want to wait, you can use an observer to track its download progress.

DBFileStatus *status = file.status;
if (!status.cached) {
    [self.file addObserver:self block:^() {
        // Check file.status and read if it's ready
    }];
    // Check if the status.cached is now YES to ensure nothing
    // was missed while adding the observer
}

You can also check if the version you have is the most recent version of the file with its newerStatus property. If the file is the latest version, this will be nil. If not, it will return the sync status for the newest version of the file. When a file is open, the Sync API will automatically download newer versions of the file as they're available and newerStatus will include the download progress. Once a newer version is downloaded, newerStatus.cached will be set. Then you can call -[DBFile update:] to update the open file to the newest version.

In addition to a single file, you can also listen to changes to all files in a folder by using the -[DBFilesystem addObserver:forPathAndChildren:] method.