Dropbox API
There are two options when creating that app record to the Dropbox platform. You can either select to allow access to the whole Dropbox folder, or to create a special folder that will be used by your application only. That folder will be the root for the app. In this tutorial we’ll choose the second option, but generally what you will select depends on what your app is supposed to do.Further than that, you’ll see that using the Dropbox API is simpler than you imagine. What we’ll do here is what you need to know in the most of cases, as we’ll cover many important stuff; from getting connected to the Dropbox account, to uploading and downloading files.
And with that, let’s move to the next part so we see what we’re about to do in this tutorial, and then to go straight into the details of the Dropbox API.
Demo App Overview
As always, in this part we’ll get to know the demo app that we will work with in this tutorial. So, let me start by saying that what we’ll do here is separated in two top-level steps:
In the first one, we’ll perform some web-side tasks by visiting the Dropbox’s online platform for developers. There we are going to create a new record for the app that we’ll make here (you’ll see more details about that later), and we’ll obtain some required keys so we can get connected to our Dropbox account through the app.
In the second step, we’re going to develop the demo app. Here’s a list with all the features that we will add:
- Link to the Dropbox account and unlinking from it (sign in and sign out)
- File upload
- Dropbox folder contents display
- File download
- Visual representation of the upload and download progress
The next screenshot illustrates a file upload process.
Creating a New App Record
When working with a third-party API, it’s almost always necessary to create a new app record (or app entry) to an online platform (often called web console) provided by the API creators. By doing that you obtain some keys that are unique for the app you’re making, and their purpose is to let you get connected to the provided services in a secure manner and then use those services.
As you guess, in this part we’re about to do exactly this; we will create a new app record to a special online platform of the Dropbox, we’ll specify some details about our demo app, and then we’ll get the keys we need so we get connected to our Dropbox account in the upcoming steps. The first thing we have to do, is to visit the Developer Home, a place dedicated to all kind of developers that want to deal with Dropbox. If this is the first time you arrive here, then feel free to navigate yourself around and get to know what Dropbox has to offer. Of course, don’t forget to sign in before you continue.
Let’s begin by clicking to the App Console link. Here is the place where you can find all of your existing Dropbox apps, and also the place where you can create a new one. Let’s do so by clicking to the Create app button.
After you’ve done your selection, you have to give a name to the app you’re creating. Let’s name this one TutApp (you may need to choose another name), so type it in the given textfield and click to the Create app button.
At this point, a new app record has been created for you by the Dropbox, and you’re guided to a new page where you can find all of its details. As you understand, it’s out of my scope to give you a tour guide here, so you’re free to explore what the app details are about. Regarding our purpose, we care only about the App key and App secret values right now, as we will need them in our iOS app in a while (if the App secret isn’t visible, just click to the Show link to display it).
The first step we had to do is now over. Don’t logout from this webpage yet, as we’ll need the app keys in a while (so you have easy access to them). Next, let’s prepare our project so we’re able finally to get connected and use the Dropbox API services.
Prerequisite Steps
Let’s turn page now, and let’s focus to the starter project that you’ve downloaded. Obviously, before we are able to perform any Dropbox-related tasks, we must get the respective SDK and add it to our project. So, visit this page, and click to the Download iOS SDK link. During the writing of this tutorial, the SDK was in the 1.3.13 version.
In this part, we have to do three specific steps:
1. To add the downloaded Dropbox framework and a couple of other necessary frameworks to the project.
2. To create a new URL scheme, so the user can return to our app once he/she has logged in to his/her Dropbox account.
3. To create a bridging file so we can import the Dropbox libraries to the code. This is necessary because the framework is written in Objective-C and we’re developing in Swift.
Let’s see each step in details.
Step 1 – Add frameworks
First of all, we have to add the downloaded framework to our project. The easiest way to do that is to locate the DropboxSDK.framework inside the downloaded folder using the Finder, and then drag and drop it to the Project Navigator of Xcode. Alternatively, in Xcode go to the File > Add files to ‘DBDemo’… menu, and search for the DropboxSDK.framework file. In any case, make sure to check the Copy items if needed option, so the framework to be really copied to our project.
Next, in the Project Navigator click to the project target, and then to the Build Phases tab. Click to the plus icon in the Link Binary With Libraries section and add the following two frameworks:
1. QuartzCore.framework
2. Security.framework
Step 2 – Create a URL Scheme
When we will first-run the app, one of the first things we have to do is to get connected to our Dropbox account by providing our credentials. Thankfully, the whole authorisation process is automated and we don’t need to do anything manually. If the original Dropbox app is installed to the device, it will be launched so we can login to the Dropbox account. If not, a view controller from the Dropbox SDK is presented inside the app so we can login. However, in the first case we must also “tell” the Dropbox app that our own app is the one that should be called after the authorisation is over, that’s why we have to create a new URL scheme, and as you’ll see, it’s really easy to do so.
In Xcode, click to the Info tab and then expand the URL Types section. Click to the plus icon to create a new one, and then in the URL Schemes textfield type: db-YOUR_APP_KEY (replace the “YOUR_APP_KEY” with the real key you created in the previous step).
Note that the “db-” prefix is necessary and that the Dropbox API expects to find it. If you change it you won’t be able to pass the authorisation stage.
Step 3 – Create a bridging file
As I said before, the Dropbox framework is written in Objective-C language, and there’s not a direct way to import the SDK in the Swift code. What we have to do, is to create a bridging header file where we’ll import the SDK, and then it will be available in a project-wide scope. We will create this bridging file by adding first an Objective-C file (an .m file) to the project, so we force Xcode to create it for us.
In Xcode go to the File > New > File… menu. In the iOS section, click to the Source category, and from the provided templates select the Objective-C file.
Proceed and name the file temp.
Continue and get finished with that file creation. Upon finishing, Xcode will display the following message asking if you want to create a bridging header file.
Click to the Yes button, and a file named DBDemo-Bridging-Header.h will be added to the Project Navigator. This is what we want. Now, you can go and delete the temp.m file, as we don’t need it.
Next, click to the DBDemo-Bridging-Header.h file and add the following line:
#import <DropboxSDK/DropboxSDK.h>
Now we are ready to write the needed code so we get logged in to the Dropbox account and start uploading and fetching files.
Connecting to Dropbox
Focusing on the code from now on, the first task we have to perform is to establish a session between the app and the Dropbox. Every time the app is launched, the session will check if the user has logged in to his account or not, and respectively it will provide the proper features. In this part, we’ll use the app key and app secret values we created earlier.
Begin by opening the AppDelegate.swift file. In the application(application:didFinishLaunchingWithOptions:) method we’ll initialise a session as shown next, so the Dropbox SDK to be able to handle all the tasks regarding it. Add the following code to that method:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
// Override point for customisation after application launch.
let appKey = "YOUR_KEY" // Set your own app key value here.
let appSecret = "YOUR_SECRET" // Set your own app secret value here.
let dropboxSession = DBSession(appKey: appKey, appSecret: appSecret, root: kDBRootAppFolder)
DBSession.setSharedSession(dropboxSession)
return true
}
From the Dropbox App Console, copy and paste your app key and app secret values to the appKey and appSecret respectively. As you see in the above snippet, the session is initialised with three arguments: The app key and secret, and a value indicating whether the app should access its own folder only, or the whole Dropbox folder. The value you’ll set here must match to the option you set to the App Console earlier. There are two possible constants you can use:
- kDBRootAppFolder: Use it to access the app’s own folder only.
- kDBRootDropbox: Use it to access the Dropbox folder.
Let’s keep going, and before we leave the AppDelegate.swift file let’s add one more useful part. The application delegate is the place where any custom URL schemes must be handled, and don’t forget that we’ve created such one previously. So, let’s do that by implementing the following method:
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) -> Bool
{
if DBSession.sharedSession().handleOpenURL(url) {
if DBSession.sharedSession().isLinked() {
return true
}
}
return false
}
The above will allow the authentication flow to be completed properly. No matter how the user will sign in, he is going to be able to return back to the app now without any problems at all. In a while we’ll come back to this method to add one more feature, but for now we’re good to go.
Now that we have created a session and made sure that the authentication flow will run smoothly, let’s perform the actual connection to a user Dropbox account. In the app interface there’s a bar button item to the toolbar at the top named Connect. By tapping it, we want the user to get connected (or linked as it’s called in the Dropbox API) by following the predefined authorisation process. Additionally, if the user is already connected we want to sign him out by “breaking” the link that has been established between our app and the Dropbox.
In the ViewController.swift file there’s an IBAction method named connectToDropbox(_:). Right now it doesn’t contain any code at all, so let’s add some:
@IBAction func connectToDropbox(sender: AnyObject)
{
if !DBSession.sharedSession().isLinked() {
DBSession.sharedSession().linkFromController(self)
}
else
{
DBSession.sharedSession().unlinkAll()
bbiConnect.title = "Connect"
}
}
The first important thing here is that the authorisation process begins by calling the linkFromController(_:) method of the sharedSession class. When that part of code is executed (in other words when the Connect button gets tapped and the user is not already logged in), either the original Dropbox app will be launched if it’s installed to the device, or a predefined view controller will be shown to allow user to provide his credentials.
The sign out process is achieved by calling the unlinkAll() method respectively.
The above is quite easy and straightforward, but as you see we change the button’s title only when the user logs out, and not when he logs in. It would be easy to add one more command and change the title from “Connect” to “Disconnect” in the first case, but the above method is not the proper place to do so and I’ll explain why.
Every time that a user logs in, or more precisely a link is set, the application(application:url:sourceApplication:annotation:) (the one that handles the URL scheme) is called. In there, we can post a custom notification that we’ll observe for in the ViewController class, and make that way known to our app that a new connection exists. In the handler method of that notification then, we can change the button’s title.
Let’s see things in the proper order. Initially, let’s update the application(application:url:sourceApplication:annotation:) method in the AppDelegate.swift file as shown next:
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) -> Bool
{
if DBSession.sharedSession().handleOpenURL(url) {
if DBSession.sharedSession().isLinked() {
NSNotificationCenter.defaultCenter().postNotificationName("didLinkToDropboxAccountNotification", object: nil)
return true
}
}
return false
}
Even though I provide you again the whole method, there’s actually only one new line there; the one we post the didLinkToDropboxAccountNotification notification. This notification will be posted every time a new connection is established by a Dropbox session.
Back to the ViewController.swift now, let’s observe for the above notification. In the viewDidLoad method add the next line:
override func viewDidLoad() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleDidLinkNotification:", name: "didLinkToDropboxAccountNotification", object: nil)
}
Let’s implement the handleDidLinkNotification(_:) custom method:
func handleDidLinkNotification(notification: NSNotification)
{
bbiConnect.title = "Disconnect"
}
With all the above additions, the button’s title will change from “Connect” to “Disconnect” once a new connection is made, and it won’t change if the authorisation fails for some reason. However, we’re still no good, because if the app is launched and an already established connection exists from a previous authorisation process, the button’s title will still show “Connect”. Let’s solve that too by modifying a bit more the viewDidLoad method:
override func viewDidLoad()
{
if DBSession.sharedSession().isLinked() {
bbiConnect.title = "Disconnect"
}
}
At this point, our app can successfully connect and disconnect to a Dropbox account. Note that later we’ll make it capable of fetching and displaying the contents of the designated folder once a link is made, but for now we’re just fine.
So, go ahead and give it a try either in the Simulator, or in a real device. Use the connect button and provide your Dropbox credentials. Once you successfully sign in, a new folder will be created in your Dropbox account having the name of the app you specified earlier (actually, two folders will be created: one named “Apps” that contains all applications’ subfolders, and one named “TutApp” for the current app).
Uploading Files
Having said all the above, let’s declare our first property. In the ViewController.swift file, go to the top of the class and add the next line:
var dbRestClient: DBRestClient
The dbRestClient property is the object of the DBRestClient class that we’ll use throughout the rest of the project for performing upload and fetch tasks. After the declaration of a property we usually move to its initialisation, and most of the times that happens in the viewDidLoad method in the tutorial demo applications. However, this time we won’t do that. We’ll create a custom method to initialise the above property. That’s because we need the dbRestClient object to be initialised in two cases: Either when a new connection is made, or when the app is launched and a link to the Dropbox already exists.
We’ll see all what I just said, but first, let’s create a new custom method where we’ll initialise the new property:
func initDropboxRestClient()
{
dbRestClient = DBRestClient(session: DBSession.sharedSession())
dbRestClient.delegate = self
}
As you see, the only thing required to be provided is the session that we establish once the app is launched. Note that we make the ViewController class the delegate of the dbRestClient object, even though we haven’t adopted the DBRestClientDelegate yet. Don’t worry and don’t mind about the error Xcode is showing; we’ll fix everything in just a while.
Let’s call the above method now. At first, this should be done once a new connection is made, so the place to do that is in the handleDidLinkNotification(_:) custom method:
func handleDidLinkNotification(notification: NSNotification)
{
initDropboxRestClient()
bbiConnect.title = "Disconnect"
}
In case an existing link is found when the app is launched, the above method must be called once again. In the viewDidLoad method we’ll do a small addition:
override func viewDidLoad()
{
if DBSession.sharedSession().isLinked() {
bbiConnect.title = "Disconnect"
initDropboxRestClient()
}
}
At this point and before we proceed, we should take care to make the dbRestClientproperty nil in case we get disconnected from Dropbox, as there’s no need to keep it initialised. So, in the connectToDropbox IBAction method, and in the else case specifically, let’s add the next command:
@IBAction func connectToDropbox(sender: AnyObject)
{
...
else {
...
dbRestClient = nil
}
}
As I said, we have two test files to upload, and a nice and easy approach, suitable for the purpose of the tutorial, would be to present an action sheet that will let us choose the file we want to upload to Dropbox. We’ll make the action sheet appear by tapping on the action bar button item existing to the right side of the top toolbar.
In the ViewController.swift file you’ll find a defined IBAction method named performAction(_:). This method has already been connected to the action bar button item, so it’s waiting for us to add some code. Initially, let’s write the standard code that will present the action sheet:
@IBAction func performAction(sender: AnyObject)
{
if !DBSession.sharedSession().isLinked() {
println("You're not connected to Dropbox")
return
}
let actionSheet = UIAlertController(title: "Upload file", message: "Select file to upload", preferredStyle: UIAlertControllerStyle.ActionSheet)
let uploadTextFileAction = UIAlertAction(title: "Upload text file", style: UIAlertActionStyle.Default) { (action) -> Void in
}
let uploadImageFileAction = UIAlertAction(title: "Upload image", style: UIAlertActionStyle.Default) { (action) -> Void in
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) { (action) -> Void in
}
actionSheet.addAction(uploadTextFileAction)
actionSheet.addAction(uploadImageFileAction)
actionSheet.addAction(cancelAction)
presentViewController(actionSheet, animated: true, completion: nil)
}
Notice that at the beginning of the method we check if there’s a link to the Dropbox. If there’s not, then we just display a relevant message to the console and we return from the method. The rest of the code is simple and easy, and there’s no reason to make any further discussion about it.
Now, let’s focus to the upload of the text file (the uploadTextFileAction action). Let me first show you the code, and then we’ll say a few more things about it:
let uploadTextFileAction = UIAlertAction(title: "Upload text file", style: UIAlertActionStyle.Default) { (action) -> Void in
let uploadFilename = "testtext.txt"
let sourcePath = NSBundle.mainBundle().pathForResource("testtext", ofType: "txt")
let destinationPath = "/"
self.dbRestClient.uploadFile(uploadFilename, toPath: destinationPath, withParentRev: nil, fromPath: sourcePath)
}
The uploadFile(…) method of the DBRestClient class is the one we use here for first time, and it expects the following arguments:
- The name of the file that will be uploaded.
- The destination path. In our case it’s the root of the app’s own folder (TutApp folder).
- The revision of the file. We won’t deal with that here, and for new files it’s not needed (just pass nil).
- The source path of the file that will be uploaded.
Let’s add the missing code now to the uploadImageFileAction action. Actually, we won’t do something different than what we did right before, so let’s see the code straight away:
let uploadImageFileAction = UIAlertAction(title: "Upload image", style:UIAlertActionStyle.Default) {
(action) -> Void in
let uploadFilename = "nature.jpg"
let sourcePath = NSBundle.mainBundle().pathForResource("nature", ofType: "jpg")
let destinationPath = "/"
self.dbRestClient.uploadFile(uploadFilename, toPath: destinationPath, withParentRev: nil, fromPath: sourcePath)
}
Time for the delegate methods now. First of all, we must adopt the DBRestClientDelegate protocol, so go to the header of the class do it:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, DBRestClientDelegate
We’re going to implement two delegate methods at this point: One that will let us know when the upload has finished, and one that will be called in case an error occurs during the upload process. Beginning with the first one, the only thing we’ll do for now is to display a message to the console and the path of the file to the Dropbox folder:
func restClient(client: DBRestClient!, uploadedFile destPath: String!, from srcPath: String!, metadata: DBMetadata!)
{
println("The file has been uploaded.")
println(metadata.path)
}
The error delegate method:
func restClient(client: DBRestClient!, uploadFileFailedWithError error: NSError!)
{
println("File upload failed.")
println(error.description)
}
Similarly as before, we just display a message and the error description to the console.
Go and test what we’ve done so far. This time, use the action bar button item to select the file you want to upload (you can do that repeatedly), and send it to the Dropbox folder. Then, open that folder either in a browser or in the Finder (if you’ve installed the Dropbox app to your Mac), and verify that the file is there.
Displaying The Uploading Progress
One of the many delegate methods that the DBRestClientDelegate protocol provides allows to keep track of the upload progress. This is useful in cases you want to notify the user about the percentage of the file upload that has been completed, or to show the progress graphically based on the value you get back from that delegate method.
In this demo application we’ll make use of that method, and we’ll display the progress of the uploading using a progress view. This progress view already exists in the interface, and by default it’s not visible.
The first thing we’ll do is to create a new custom method. In this one we’ll perform two simple tasks:
1. We’ll set the value of the progress view to 0, so it properly displays the progress.
2. We’ll make the progress view visible.
Here we go:
func showProgressBar()
{
progressBar.progress = 0.0
progressBar.hidden = false
}
Next, we must determine when this method should be called. Obviously, the progress view must become visible when a file upload begins, so let’s modify both the uploadTextFileAction and uploadImageFileAction actions of the action sheet (in the performAction() IBAction method) as shown below:
let uploadTextFileAction = UIAlertAction(title: "Upload text file", style: UIAlertActionStyle.Default) { (action) -> Void in
self.showProgressBar()
self.dbRestClient.uploadFile(uploadFilename, toPath: destinationPath, withParentRev: nil, fromPath: sourcePath)
}
let uploadImageFileAction = UIAlertAction(title: "Upload image", style: UIAlertActionStyle.Default) { (action) -> Void in
self.showProgressBar()
self.dbRestClient.uploadFile(uploadFilename, toPath: destinationPath, withParentRev: nil, fromPath: sourcePath)
}
Notice that the progress bar must become visible right before the upload starts.
Now, let’s implement the new delegate method, which as you’ll see right next, is really simple:
func restClient(client: DBRestClient!, uploadProgress progress: CGFloat, forFile destPath: String!, from srcPath: String!)
{
progressBar.progress = Float(progress)
}
Note that the progress view expects a Float value, therefore the above cast is necessary.
So far so good, as the progress bar will become visible and will display the progress while a file is being uploaded. Don’t forget however that when the uploading process is over, the progress bar must become hidden again. We’ll do that in the two other delegate methods that we have already implemented, as those are the places that indicate that the upload has finished.
func restClient(client: DBRestClient!, uploadedFile destPath: String!, from srcPath: String!, metadata: DBMetadata!)
{
progressBar.hidden = true
}
func restClient(client: DBRestClient!, uploadFileFailedWithError error: NSError!)
{
progressBar.hidden = true
}
Now you can go and test the app once again. This time you’ll see the upload progress in the progress view.
Fetching Content
As the title of this part says, here we are going to do the exact opposite thing from what we’ve already done; we’ll get the contents of the app’s folder in the Dropbox, and we’ll display them to the tableview existing to the app (and we haven’t used yet). Fetching the files from the Dropbox folder doesn’t mean that they will be downloaded. Actually, what we get is a list of files that we’ll display to the user.
Similarly to what we did before, here we are also going to use the dbRestClientobject for getting the files from Dropbox. Doing so it’s easy, as it takes just one line of code, the following:
dbRestClient.loadMetadata("/")
The parameter of the loadMetadata method is the path of the folder we want to get the file list from. In this case, we ask from Dropbox to return all the contents of the app’s folder (the “/” means the root folder where the app has access to). If there was a subfolder named “test” and we would want its contents only, then we would pass the “/test/” value as the parameter of the above method.
Back to our app again, initially we want to load the existing contents of the app’s folder in two cases: When we connect to Dropbox, and when the app gets launched and there’s a connection already. If you recall, in both of those cases we call the initDropboxRestClient() custom method, so obviously this is the best place to load the file list. Here it is:
func initDropboxRestClient()
{
dbRestClient.loadMetadata("/")
}
Also, we want to refresh the file list in the app after an upload process has successfully finished. So, let’s update the following delegate method too:
func restClient(client: DBRestClient!, uploadedFile destPath: String!, from srcPath: String!, metadata: DBMetadata!)
{
dbRestClient.loadMetadata("/")
}
Besides the above two cases, it would be also nice if we were able to get the Dropbox contents on demand. In the app’s interface there’s a refresh bar button item we haven’t used yet, but now it’s time to do so. By tapping it we’ll make our app ask for the Dropbox contents as we have already done in the above two cases.
In the ViewController.swift file there’s the reloadFiles IBAction method that is already connected to the refresh bar button item. In there we’ll make a call to the loadMetadata method of the DBRestClient class once again, so we fetch the Dropbox files whenever we wish so. Here’s that IBAction method:
@IBAction func reloadFiles(sender: AnyObject)
{
dbRestClient.loadMetadata("/")
}
The above is really convenient when new files have been added to the app’s folder in the Dropbox out of the app, and we want to get them here as well.
Now that we’ve covered all the possible cases for fetching the Dropbox contents, let’s see how we’ll handle the results that the DBRestClient returns back to the app. As you can imagine, we’ll implement another delegate method of the DBRestClientDelegate protocol to do that. This method is the next one:
func restClient(client: DBRestClient!, loadedMetadata metadata: DBMetadata!)
{
}
What we are interested in is the second parameter, the metadata object. This one contains various information about the contents of the directory we access (once again, in our case the app’s folder in the Dropbox), and also contains the list of the files we want to display to the tableview. I prompt you to the official Dropbox API documentation for more information about it; here we’ll be limited to what we need so we get the content list only.
So, our goal here is to hold this metadata object to a property and to have access to it even out of the scope of the above method, and then to display the contents to the tableview. Let’s see everything step by step.
First, let’s declare the following property to the top of the class:
var dropboxMetadata: DBMetadata!
Now, let’ go to the above delegate method to add the missing code:
func restClient(client: DBRestClient!, loadedMetadata metadata: DBMetadata!)
{
dropboxMetadata = metadata;
tblFiles.reloadData()
}
As you see, our work here couldn’t be any simpler than that. Our next task is to implement the tableview methods properly, but before we do that, let’s also cover the error case:
func restClient(client: DBRestClient!, loadMetadataFailedWithError error: NSError!)
{
println(error.description)
}
Now, let’s deal with the tableview. Initially, let’s see the easy stuff:
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if let metadata = dropboxMetadata {
return metadata.contents.count
}
return 0
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return 60.0
}
Notice how we handle the number of rows in the tableview. If the dropbox Metadata object isn’t nil, we get the number of the contents using the contents property. The same property we’ll use right next, where we’ll display the name of each content:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("idCellFile", forIndexPath: indexPath) as! UITableViewCell
let currentFile: DBMetadata = dropboxMetadata.contents[indexPath.row] as! DBMetadata
cell.textLabel?.text = currentFile.filename
return cell
}
The above method performs the actual display in the tableview. Initially we hold each file to the currentFile variable, and then using the filename property we get its name and we set it to the cell.
Now we’re ready to test the app once again. Once you launch it, give it a few seconds to get the contents from the Dropbox. Then try to upload a file to make it reload the contents, or add a file to the app’s folder manually in the Dropbox and then use the refresh bar button item.
Downloading Files
Getting the file list from Dropbox is awesome, but it makes no good if we’re unable to use any of them. So in this part we’re going to add one more feature to our demo app, and we’ll make it capable to download files.
More specifically, we’ll initiate a file download process right after we tap to the respective cell. Obviously, we’ll set the documents directory of the app as the destination directory for the downloaded file. Furthermore, and similarly to what we did in the file upload, we’ll keep track of the download progress by using once again the progress view we have in the bottom side of the view.
So, let’s get started by letting me give you a new tableview delegate method implementation, and then we’ll discuss about it:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
let selectedFile: DBMetadata = dropboxMetadata.contents[indexPath.row] as! DBMetadata
let documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! NSString
showProgressBar()
dbRestClient.loadFile(selectedFile.path, intoPath: documentsDirectoryPath as String)
}
Let’s take things from the beginning. At first, we keep the file that has been tapped to a local variable so it’s easier to handle it. Next, we specify the path to the documents directory of the app, and then we call the showProgressBar() custom method to make the progress view visible (and also to set its value to 0).
The new thing here is the last line, where we make use of the loadFile(…) method of the DBRestClient class. This one, will initiate the actual download process in the background, and as you expect, it will call the proper delegate methods either upon a successful download, or if an error occurs.
All the above is what we need to start the downloading. Now, we must implement three new delegate methods of the DBRestClientDelegate protocol, so we handle the newly downloaded file, any error that might occurs, and also to display the download progress to the progress view.
Let’s get started with the first one. As this is just a demo app, we won’t do much. Actually, we’ll display to the console just one message telling that the file has been downloaded, and showing the file name and the file type. Here we go:
func restClient(client: DBRestClient!, loadedFile destPath: String!, contentType: String!, metadata: DBMetadata!)
{
println("The file \(metadata.filename) was downloaded. Content type: \(contentType)")
progressBar.hidden = true
}
Apparently, in a real application you should manage each piece of information you receive in this delegate method in a more proper way, and according to your app’s requirements. As you see, once the download is finished we hide the progress view. It’s not necessary to stay visible any more.
Let’s see the error case now:
func restClient(client: DBRestClient!, loadFileFailedWithError error: NSError!)
{
println(error.description)
progressBar.hidden = true
}
As usually, we just display the error description, and again we make the progress view hidden.
Lastly, let’s update our progress view with the real progress of the download:
func restClient(client: DBRestClient!, loadProgress progress: CGFloat, forFile destPath: String!)
{
progressBar.progress = Float(progress)
}
That’s all. Go ahead and give the app one last try (or many tries). Tap to a file and watch the progress view indicating the download progress. Note that here we don’t handle the case of multiple file downloads, so don’t expect the progress view to behave “normally” if you tap to a file while another one is being downloaded. You can verify that the files have been downloaded if you simply open the documents directory either in the Simulator or in your device (by using Xcode).
Summary
So, as it seems working with the Dropbox API isn’t as hard as it may sounds eventually.
For reference, you can download the Xcode project here.
Comments
Post a Comment
Thank You.