{"id":28550662,"url":"https://github.com/dropbox/swiftydropbox","last_synced_at":"2025-10-08T13:41:46.977Z","repository":{"id":32128470,"uuid":"35701074","full_name":"dropbox/SwiftyDropbox","owner":"dropbox","description":"Swift SDK for the Dropbox API v2.","archived":false,"fork":false,"pushed_at":"2025-05-14T16:13:04.000Z","size":536724,"stargazers_count":699,"open_issues_count":16,"forks_count":205,"subscribers_count":58,"default_branch":"master","last_synced_at":"2025-06-30T08:47:14.928Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dropbox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-05-15T23:04:04.000Z","updated_at":"2025-06-30T01:13:21.000Z","dependencies_parsed_at":"2023-02-16T12:45:16.932Z","dependency_job_id":"6bff9e0b-b190-4cfe-9428-dd84b9635fb1","html_url":"https://github.com/dropbox/SwiftyDropbox","commit_stats":{"total_commits":342,"total_committers":46,"mean_commits":7.434782608695652,"dds":0.7222222222222222,"last_synced_commit":"aee63b4717fda3255c532d52a4b05f0328ac00bc"},"previous_names":[],"tags_count":73,"template":false,"template_full_name":null,"purl":"pkg:github/dropbox/SwiftyDropbox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dropbox%2FSwiftyDropbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dropbox%2FSwiftyDropbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dropbox%2FSwiftyDropbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dropbox%2FSwiftyDropbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dropbox","download_url":"https://codeload.github.com/dropbox/SwiftyDropbox/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dropbox%2FSwiftyDropbox/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263226321,"owners_count":23433680,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-10T03:09:57.831Z","updated_at":"2025-10-08T13:41:46.970Z","avatar_url":"https://github.com/dropbox.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dropbox for Swift\n\n## Version 10.0.0 differs greatly from previous versions of the SDK. See [Changes in version 10.0.0](#changes-in-version-1000) and, if needed, [Migrating from dropbox-sdk-obj-c](#migrating-from-dropbox-sdk-obj-c).\n\nThe Official Dropbox Swift SDK for integrating with Dropbox [API v2](https://www.dropbox.com/developers/documentation/http/documentation) on iOS or macOS.\n\nFull documentation [here](https://dropbox.github.io/SwiftyDropbox/api-docs/latest/).\n\n---\n\n## Table of Contents\n\n* [System requirements](#system-requirements)\n* [Get started](#get-started)\n  * [Register your application](#register-your-application)\n  * [Obtain an OAuth 2.0 token](#obtain-an-oauth-20-token)\n* [SDK distribution](#sdk-distribution)\n  * [Swift Package Manager](#swift-package-manager)\n  * [CocoaPods](#cocoapods)\n* [Configure your project](#configure-your-project)\n  * [Application `.plist` file](#application-plist-file)\n  * [Handling the authorization flow](#handling-the-authorization-flow)\n    * [Initialize a `DropboxClient` instance](#initialize-a-dropboxclient-instance)\n    * [Begin the authorization flow](#begin-the-authorization-flow)\n    * [Handle redirect back into SDK](#handle-redirect-back-into-sdk)\n* [Try some API requests](#try-some-api-requests)\n  * [Dropbox client instance](#dropbox-client-instance)\n  * [Handle the API response](#handle-the-api-response)\n  * [Request types](#request-types)\n    * [RPC-style request](#rpc-style-request)\n    * [Upload-style request](#upload-style-request)\n    * [Download-style request](#download-style-request)\n  * [Handling responses and errors](#handling-responses-and-errors)\n    * [Route-specific errors](#route-specific-errors)\n    * [Generic network request errors](#generic-network-request-errors)\n    * [Response handling edge cases](#response-handling-edge-cases)\n  * [Customizing network calls](#customizing-network-calls)\n    * [Configure network client](#configure-network-client)\n    * [Specify API call response queue](#specify-api-call-response-queue)\n  * [`DropboxClientsManager` class](#dropboxclientsmanager-class)\n    * [Single Dropbox user case](#single-dropbox-user-case)\n    * [Multiple Dropbox user case](#multiple-dropbox-user-case)\n* [Objective-C](#objective-c)\n  * [Objective-C Compatibility Layer Distribution](#objective-c-compatibility-layer-distribution)\n  * [Using the Objective-C Compatbility Layer](#using-the-objective-c-compatbility-layer)\n  * [Migrating from dropbox-sdk-obj-c](#migrating-from-dropbox-sdk-obj-c)\n* [Changes in version 10.0.0](#changes-in-version-1000)\n* [Examples](#examples)\n* [Documentation](#documentation)\n* [Stone](#stone)\n* [Modifications](#modifications)\n* [App Store Connect Privacy Labels](#app-store-connect-privacy-labels)\n* [Bugs](#bugs)\n\n---\n\n## System requirements\n\n- iOS 12.0+\n- macOS 10.13+\n- Xcode 13.3+\n- Swift 5.6+\n\n## Get Started\n\n### Register your application\n\nBefore using this SDK, you should register your application in the [Dropbox App Console](https://dropbox.com/developers/apps). This creates a record of your app with Dropbox that will be associated with the API calls you make.\n\n### Obtain an OAuth 2.0 token\n\nAll requests need to be made with an OAuth 2.0 access token. An OAuth token represents an authenticated link between a Dropbox app and\na Dropbox user account or team.\n\nOnce you've created an app, you can go to the App Console and manually generate an access token to authorize your app to access your own Dropbox account.\nOtherwise, you can obtain an OAuth token programmatically using the SDK's pre-defined auth flow. For more information, [see below](https://github.com/dropbox/SwiftyDropbox#handling-the-authorization-flow).\n\n---\n\n## SDK distribution\n\nYou can integrate the Dropbox Swift SDK into your project using one of several methods.\n\n### Swift Package Manager\n\nThe Dropbox Swift SDK can be installed in your project using [Swift Package Manager](https://swift.org/package-manager/) by specifying the Dropbox Swift SDK repository URL:\n\n```\nhttps://github.com/dropbox/SwiftyDropbox.git\n```\n\nRefer to [Apple's \"Adding Package Dependencies to Your App\" documentation](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app) for more information.\n\n\n### CocoaPods\n\nTo use [CocoaPods](http://cocoapods.org), a dependency manager for Cocoa projects, you should first install it using the following command:\n\n```bash\n$ gem install cocoapods\n```\n\nThen navigate to the directory that contains your project and create a new file called `Podfile`. You can do this either with `pod init`, or open an existing Podfile, and then add `pod 'SwiftyDropbox'` to the main loop. Your Podfile should look something like this:\n\n```ruby\nuse_frameworks!\n\ntarget '\u003cYOUR_PROJECT_NAME\u003e' do\n    pod 'SwiftyDropbox'\nend\n```\nIf your project contains Objective-C code that will need to have access to Dropbox SDK there is a separate pod called `SwiftyDropboxObjC` that contains an Objective-C compatibility layer for the SDK. Add this pod to your `Podfile` (in addition to `SwiftyDropbox` or on its own). For more information refer to the [Objective-C](#objective-c) section of this README.\n\nThen, run the following command to install the dependency:\n\n```bash\n$ pod install\n```\n\nOnce your project is integrated with the Dropbox Swift SDK, you can pull SDK updates using the following command:\n\n```bash\n$ pod update\n```\n\n---\n\n## Configure your project\n\nOnce you have integrated the Dropbox Swift SDK into your project, there are a few additional steps to take before you can begin making API calls.\n\n### Application `.plist` file\n\nIf you are compiling on iOS SDK 9.0, you will need to modify your application's `.plist` to handle Apple's [new security changes](https://developer.apple.com/videos/wwdc/2015/?id=703) to the `canOpenURL` function. You should\nadd the following code to your application's `.plist` file:\n\n```\n\u003ckey\u003eLSApplicationQueriesSchemes\u003c/key\u003e\n    \u003carray\u003e\n        \u003cstring\u003edbapi-8-emm\u003c/string\u003e\n        \u003cstring\u003edbapi-2\u003c/string\u003e\n    \u003c/array\u003e\n```\nThis allows the Swift SDK to determine if the official Dropbox iOS app is installed on the current device. If it is installed, then the official Dropbox iOS app can be used to programmatically obtain an OAuth 2.0 access token.\n\nAdditionally, your application needs to register to handle a unique Dropbox URL scheme for redirect following completion of the OAuth 2.0 authorization flow. This URL scheme should have the format `db-\u003cAPP_KEY\u003e`, where `\u003cAPP_KEY\u003e` is your\nDropbox app's app key, which can be found in the [App Console](https://dropbox.com/developers/apps).\n\nYou should add the following code to your `.plist` file (but be sure to replace `\u003cAPP_KEY\u003e` with your app's app key):\n\n```\n\u003ckey\u003eCFBundleURLTypes\u003c/key\u003e\n    \u003carray\u003e\n        \u003cdict\u003e\n            \u003ckey\u003eCFBundleURLSchemes\u003c/key\u003e\n            \u003carray\u003e\n                \u003cstring\u003edb-\u003cAPP_KEY\u003e\u003c/string\u003e\n            \u003c/array\u003e\n            \u003ckey\u003eCFBundleURLName\u003c/key\u003e\n            \u003cstring\u003e\u003c/string\u003e\n        \u003c/dict\u003e\n    \u003c/array\u003e\n```\n\nAfter you've made the above changes, your application's `.plist` file should look something like this:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/dropbox/SwiftyDropbox/blob/master/Images/InfoPlistExample.png?raw=true\" alt=\"Info .plist Example\"/\u003e\n\u003c/p\u003e\n\n---\n\n### Handling the authorization flow\n\nThere are three methods to programmatically retrieve an OAuth 2.0 access token:\n\n* **Direct auth** (iOS only): This launches the official Dropbox iOS app (if installed), authenticates via the official app, then redirects back into the SDK\n* **Safari view controller auth** (iOS only): This launches a `SFSafariViewController` to facillitate the auth flow. This is desirable because it is safer for the end-user, and pre-existing session data can be used to avoid requiring the user to re-enter their Dropbox credentials.\n* **Redirect to external browser** (macOS only): This launches the user's default browser to facillitate the auth flow. This is also desirable because it is safer for the end-user, and pre-existing session data can be used to avoid requiring the user to re-enter their Dropbox credentials.\n\nTo facilitate the above authorization flows, you should take the following steps:\n\n---\n\n#### Initialize a `DropboxClient` instance\n\nFrom your application delegate:\n\n_SwiftUI note: You may need to create an Application Delegate if your application doesn't have one._\n\n##### iOS\n\n```Swift\nimport SwiftyDropbox\n\nfunc application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -\u003e Bool {\n    DropboxClientsManager.setupWithAppKey(\"\u003cAPP_KEY\u003e\")\n    return true\n}\n```\n\n##### macOS\n\n```Swift\nimport SwiftyDropbox\n\nfunc applicationDidFinishLaunching(_ aNotification: Notification) {\n    DropboxClientsManager.setupWithAppKeyDesktop(\"\u003cAPP_KEY\u003e\")\n}\n```\n\n---\n\n#### Begin the authorization flow\n\nYou can commence the auth flow by calling `authorizeFromControllerV2:controller:openURL` method in your application's\nview controller. Note that the controller reference will be weakly held. For SwiftUI applications nil can be passed in for the controller argument and the app's root view controller will be used to present the flow.\n\nFrom your view controller:\n\n##### iOS\n\n```Swift\nimport SwiftyDropbox\n\nfunc myButtonInControllerPressed() {\n    // OAuth 2 code flow with PKCE that grants a short-lived token with scopes, and performs refreshes of the token automatically.\n    let scopeRequest = ScopeRequest(scopeType: .user, scopes: [\"account_info.read\"], includeGrantedScopes: false)\n    DropboxClientsManager.authorizeFromControllerV2(\n        UIApplication.shared,\n        controller: self,\n        loadingStatusDelegate: nil,\n        openURL: { (url: URL) -\u003e Void in UIApplication.shared.open(url, options: [:], completionHandler: nil) },\n        scopeRequest: scopeRequest\n    )\n}\n\n```\n\n##### macOS\n\n```Swift\nimport SwiftyDropbox\n\nfunc myButtonInControllerPressed() {\n    // OAuth 2 code flow with PKCE that grants a short-lived token with scopes, and performs refreshes of the token automatically.\n    let scopeRequest = ScopeRequest(scopeType: .user, scopes: [\"account_info.read\"], includeGrantedScopes: false)\n    DropboxClientsManager.authorizeFromControllerV2(\n        sharedApplication: NSApplication.shared,\n        controller: self,\n        loadingStatusDelegate: nil,\n        openURL: {(url: URL) -\u003e Void in NSWorkspace.shared.open(url)},\n        scopeRequest: scopeRequest\n    )\n}\n```\n\nBeginning the authentication flow via in-app webview will launch a window like this:\n\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/dropbox/SwiftyDropbox/blob/master/Images/OAuthFlowInit.png?raw=true\" alt=\"Auth Flow Init Example\"/\u003e\n\u003c/p\u003e\n\n---\n\n#### Handle redirect back into SDK\n\nTo handle the redirection back into the Swift SDK once the authentication flow is complete, you should add the following code in your application's delegate:\n\n_SwiftUI note: You may need to create an Application Delegate if your application doesn't have one._\n\n##### iOS\n\n```Swift\nimport SwiftyDropbox\n\nfunc application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -\u003e Bool {\n    let oauthCompletion: DropboxOAuthCompletion = {\n      if let authResult = $0 {\n          switch authResult {\n          case .success:\n              print(\"Success! User is logged into DropboxClientsManager.\")\n          case .cancel:\n              print(\"Authorization flow was manually canceled by user!\")\n          case .error(_, let description):\n              print(\"Error: \\(String(describing: description))\")\n          }\n      }\n    }\n    let canHandleUrl = DropboxClientsManager.handleRedirectURL(url, includeBackgroundClient: false, completion: oauthCompletion)\n    return canHandleUrl\n}\n\n```\nOr if your app is iOS13+, or your app also supports Scenes, add the following code into your application's main scene delegate:\n\nNote: You may need to create a Scene Delegate if your application doesn't have one._\n```Swift\nimport SwiftyDropbox\n\nfunc scene(_ scene: UIScene, openURLContexts URLContexts: Set\u003cUIOpenURLContext\u003e) {\n     let oauthCompletion: DropboxOAuthCompletion = {\n      if let authResult = $0 {\n          switch authResult {\n          case .success:\n              print(\"Success! User is logged into DropboxClientsManager.\")\n          case .cancel:\n              print(\"Authorization flow was manually canceled by user!\")\n          case .error(_, let description):\n              print(\"Error: \\(String(describing: description))\")\n          }\n      }\n    }\n\n    for context in URLContexts {\n        // stop iterating after the first handle-able url\n        if DropboxClientsManager.handleRedirectURL(context.url, includeBackgroundClient: false, completion: oauthCompletion) { break }\n    }\n}\n```\n\n##### macOS\n\n```Swift\nimport SwiftyDropbox\n\nfunc applicationDidFinishLaunching(_ aNotification: Notification) {\n    ...... // code outlined above goes here\n\n    NSAppleEventManager.shared().setEventHandler(self,\n                                                 andSelector: #selector(handleGetURLEvent),\n                                                 forEventClass: AEEventClass(kInternetEventClass),\n                                                 andEventID: AEEventID(kAEGetURL))\n}\n\nfunc handleGetURLEvent(_ event: NSAppleEventDescriptor?, replyEvent: NSAppleEventDescriptor?) {\n    if let aeEventDescriptor = event?.paramDescriptor(forKeyword: AEKeyword(keyDirectObject)) {\n        if let urlStr = aeEventDescriptor.stringValue {\n            let url = URL(string: urlStr)!\n            let oauthCompletion: DropboxOAuthCompletion = {\n                if let authResult = $0 {\n                    switch authResult {\n                    case .success:\n                        print(\"Success! User is logged into Dropbox.\")\n                    case .cancel:\n                        print(\"Authorization flow was manually canceled by user!\")\n                    case .error(_, let description):\n                        print(\"Error: \\(String(describing: description))\")\n                    }\n                }\n            }\n            DropboxClientsManager.handleRedirectURL(url, includeBackgroundClient: false, completion: oauthCompletion)\n            // this brings your application back the foreground on redirect\n            NSApp.activate(ignoringOtherApps: true)\n        }\n    }\n}\n```\n\nAfter the end user signs in with their Dropbox login credentials via the in-app webview, they will see a window like this:\n\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/dropbox/SwiftyDropbox/blob/master/Images/OAuthFlowApproval.png?raw=true\" alt=\"Auth Flow Approval Example\"/\u003e\n\u003c/p\u003e\n\nIf they press **Allow** or **Cancel**, the `db-\u003cAPP_KEY\u003e` redirect URL will be launched from the webview, and will be handled in your application\ndelegate's `application:handleOpenURL` method, from which the result of the authorization can be parsed.\n\nNow you're ready to begin making API requests!\n\n---\n\n## Try some API requests\n\nOnce you have obtained an OAuth 2.0 token, you can try some API v2 calls using the Swift SDK.\n\n### Dropbox client instance\n\nStart by creating a reference to the `DropboxClient` or `DropboxTeamClient` instance that you will use to make your API calls.\n\n```Swift\nimport SwiftyDropbox\n\n// Reference after programmatic auth flow\nlet client = DropboxClientsManager.authorizedClient\n```\n\nor\n\n```Swift\nimport SwiftyDropbox\n\n// Initialize with manually retrieved auth token\nlet client = DropboxClient(accessToken: \"\u003cMY_ACCESS_TOKEN\u003e\")\n```\n\n---\n\n### Handle the API response\n\nThe Dropbox [User API](https://www.dropbox.com/developers/documentation/http/documentation) and [Business API](https://www.dropbox.com/developers/documentation/http/teams) have three types of requests: RPC, Upload and Download.\n\nThe response handlers for each request type are similar to one another. The arguments for the handler blocks are as follows:\n* **route result type** (`Void` if the route does not have a return type)\n* **network error** (either a route-specific error or generic network error)\n* **output content** (`URL` / `Data` reference to downloaded output for Download-style endpoints only)\n\nNote: Response handlers are required for all endpoints. Progress handlers, on the other hand, are optional for all endpoints.\n\n#### Swift Concurrency\n\nAs of the 10.0.0 release, all of the request types also support Swift Concurrency (`async`/`await`) via the async `response()` function.\n\n```swift\nlet response = try await client.files.createFolder(path: \"/test/path/in/Dropbox/account\").response()\n```\n\n---\n\n### Request types\n\n#### RPC-style request\n```Swift\nclient.files.createFolder(path: \"/test/path/in/Dropbox/account\").response { response, error in\n    if let response = response {\n        print(response)\n    } else if let error = error {\n        print(error)\n    }\n}\n```\n\n---\n\n#### Upload-style request\n```Swift\nlet fileData = \"testing data example\".data(using: String.Encoding.utf8, allowLossyConversion: false)!\n\nlet request = client.files.upload(path: \"/test/path/in/Dropbox/account\", input: fileData)\n    .response { response, error in\n        if let response = response {\n            print(response)\n        } else if let error = error {\n            print(error)\n        }\n    }\n    .progress { progressData in\n        print(progressData)\n    }\n\n// in case you want to cancel the request\nif someConditionIsSatisfied {\n    request.cancel()\n}\n```\n\n---\n\n#### Download-style request\n```Swift\n// Download to URL\nlet fileManager = FileManager.default\nlet directoryURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]\nlet destination = directoryURL.appendingPathComponent(\"myTestFile\")\n\nclient.files.download(path: \"/test/path/in/Dropbox/account\", overwrite: true, destination: destination)\n    .response { response, error in\n        if let response = response {\n            print(response)\n        } else if let error = error {\n            print(error)\n        }\n    }\n    .progress { progressData in\n        print(progressData)\n    }\n\n\n// Download to Data\nclient.files.download(path: \"/test/path/in/Dropbox/account\")\n    .response { response, error in\n        if let response = response {\n            let responseMetadata = response.0\n            print(responseMetadata)\n            let fileContents = response.1\n            print(fileContents)\n        } else if let error = error {\n            print(error)\n        }\n    }\n    .progress { progressData in\n        print(progressData)\n    }\n```\n\n---\n\n### Handling responses and errors\n\nDropbox API v2 deals largely with two data types: **structs** and **unions**. Broadly speaking, most route **arguments** are struct types and most route **errors** are union types.\n\n**NOTE:** In this context, \"structs\" and \"unions\" are terms specific to the Dropbox API, and not to any of the languages that are used to query the API, so you should avoid thinking of them in terms of their Swift definitions.\n\n**Struct types** are \"traditional\" object types, that is, composite types made up of a collection of one or more instance fields. All public instance fields are accessible at runtime, regardless of runtime state.\n\n**Union types**, on the other hand, represent a single value that can take on multiple value types, depending on state. We capture all of these different type scenarios under one \"union object\", but that object will exist only as one type at runtime. Each union state type, or **tag**, may have an associated value (if it doesn't, the union state type is said to be **void**). Associated value types can either be primitives, structs or unions. Although the Swift SDK represents union types as objects with multiple instance fields, at most one instance field is accessible at runtime, depending on the tag state of the union.\n\nFor example, the [/delete](https://www.dropbox.com/developers/documentation/http/documentation#files-delete) endpoint returns an error, `Files.DeleteError`, which is a union type. The `Files.DeleteError` union can take on two different tag states: `path_lookup`\n(if there is a problem looking up the path) or `path_write` (if there is a problem writing -- or in this case deleting -- to the path). Here, both tag states have non-void associated values (of types `Files.LookupError` and `Files.WriteError`, respectively).\n\nIn this way, one union object is able to capture a multitude of scenarios, each of which has their own value type.\n\nTo properly handle union types, you should pass each union through a switch statement, and check each possible tag state associated with the union. Once you have determined the current tag state of the union, you can then access the value associated with that tag state (provided there exists an associated value type, i.e., it's not **void**).\n\n---\n\n#### Route-specific errors\n```Swift\nclient.files.deleteV2(path: \"/test/path/in/Dropbox/account\").response { response, error in\n    if let response = response {\n        print(response)\n    } else if let error = error {\n        switch error as CallError {\n        case .routeError(let boxed, let userMessage, let errorSummary, let requestId):\n            print(\"RouteError[\\(requestId)]:\")\n\n            switch boxed.unboxed as Files.DeleteError {\n            case .pathLookup(let lookupError):\n                switch lookupError {\n                case .notFound:\n                    print(\"There is nothing at the given path.\")\n                case .notFile:\n                    print(\"We were expecting a file, but the given path refers to something that isn't a file.\")\n                case .notFolder:\n                    print(\"We were expecting a folder, but the given path refers to something that isn't a folder.\")\n                case .restrictedContent:\n                    print(\"The file cannot be transferred because the content is restricted...\")\n                case .malformedPath(let malformedPath):\n                    print(\"Malformed path: \\(malformedPath)\")\n                case .other:\n                    print(\"Unknown\")\n                }\n            case .pathWrite(let writeError):\n                print(\"WriteError: \\(writeError)\")\n                // you can handle each `WriteError` case like the `DeleteError` cases above\n            case .tooManyWriteOperations:\n                print(\"Another write operation occurring at the same time prevented this from succeeding.\")\n            case .tooManyFiles:\n                print(\"There are too many files to delete.\")\n            case .other:\n                print(\"Unknown\")\n            }\n        case .internalServerError(let code, let message, let requestId):\n            ....\n            ....\n            // a not route-specific error occurred\n        ....\n        ....\n        ....\n        }\n    }\n}\n```\n\n---\n\n#### Generic network request errors\n\nIn the case of a network error, errors are either specific to the endpoint (as shown above) or more generic errors.\n\nTo determine if an error is route-specific or not, the error object should be cast as a `CallError`, and depending on the type of error, handled in the appropriate switch statement.\n\n```Swift\nclient.files.deleteV2(path: \"/test/path/in/Dropbox/account\").response { response, error in\n    if let response = response {\n        print(response)\n    } else if let error = error {\n        switch error as CallError {\n        case .routeError(let boxed, let userMessage, let errorSummary, let requestId):\n            // a route-specific error occurred\n            // see handling above\n            ....\n            ....\n            ....\n        case .internalServerError(let code, let message, let requestId):\n            print(\"InternalServerError[\\(requestId)]: \\(code): \\(message)\")\n        case .badInputError(let message, let requestId):\n            print(\"BadInputError[\\(requestId)]: \\(message)\")\n        case .authError(let authError, let userMessage, let errorSummary, let requestId):\n            print(\"AuthError[\\(requestId)]: \\(userMessage) \\(errorSummary) \\(authError)\")\n        case .accessError(let accessError, let userMessage, let errorSummary, let requestId):\n            print(\"AccessError[\\(requestId)]: \\(userMessage) \\(errorSummary) \\(accessError)\")\n        case .rateLimitError(let rateLimitError, let userMessage, let errorSummary, let requestId):\n            print(\"RateLimitError[\\(requestId)]: \\(userMessage) \\(errorSummary) \\(rateLimitError)\")\n        case .httpError(let code, let message, let requestId):\n            print(\"HTTPError[\\(requestId)]: \\(code): \\(message)\")\n        case .clientError(let error):\n            print(\"ClientError: \\(error)\")\n        }\n    }\n}\n```\n\n---\n\n#### Response handling edge cases\n\nSome routes return union types as result types, so you should be prepared to handle these results in the same way that you handle union route errors. Please consult the [documentation](https://www.dropbox.com/developers/documentation/http/documentation)\nfor each endpoint that you use to ensure you are properly handling the route's response type.\n\nA few routes return result types that are **datatypes with subtypes**, that is, structs that can take on multiple state types like unions.\n\nFor example, the [/delete](https://www.dropbox.com/developers/documentation/http/documentation#files-delete) endpoint returns a generic `Metadata` type, which can exist either as a `FileMetadata` struct, a `FolderMetadata` struct, or a `DeletedMetadata` struct.\nTo determine at runtime which subtype the `Metadata` type exists as, pass the object through a switch statement, and check for each possible class, with the result casted accordingly. See below:\n\n```Swift\nclient.files.deleteV2(path: \"/test/path/in/Dropbox/account\").response { response, error in\n    if let response = response {\n        switch response {\n        case let fileMetadata as Files.FileMetadata:\n            print(\"File metadata: \\(fileMetadata)\")\n        case let folderMetadata as Files.FolderMetadata:\n            print(\"Folder metadata: \\(folderMetadata)\")\n        case let deletedMetadata as Files.DeletedMetadata:\n            print(\"Deleted entity's metadata: \\(deletedMetadata)\")\n        }\n    } else if let error = error {\n        switch error as CallError {\n        case .routeError(let boxed, let userMessage, let errorSummary, let requestId):\n            // a route-specific error occurred\n            // see handling above\n        case .internalServerError(let code, let message, let requestId):\n            ....\n            ....\n            // a not route-specific error occurred\n            // see handling above\n        ....\n        ....\n        ....\n        }\n    }\n}\n```\n\nThis `Metadata` object is known as a **datatype with subtypes** in our API v2 documentation.\n\nDatatypes with subtypes are a way combining structs and unions. Datatypes with subtypes are struct objects that contain a tag, which specifies which subtype the object exists as at runtime. The reason we have this construct, as with unions, is so we can capture a multitude of scenarios with one object.\n\nIn the above example, the `Metadata` type can exists as `FileMetadata`, `FolderMetadata` or `DeleteMetadata`. Each of these types have common instances fields like \"name\" (the name for the file, folder or deleted type), but also instance fields that are specific to the particular subtype. In order to leverage inheritance, we set a common supertype called `Metadata` which captures all of the common instance fields, but also has a tag instance field, which specifies which subtype the object currently exists as.\n\nIn this way, datatypes with subtypes are a hybrid of structs and unions. Only a few routes return result types like this.\n\n---\n\n### Customizing network calls\n\n#### Configure network client\n\nIt is possible to configure the networking client used by the SDK to make API requests. You can supply custom fields like a custom user agent or custom session configurations, or a custom auth challenge handler. See below:\n\n##### iOS\n```Swift\nimport SwiftyDropbox\n\nlet transportClient = DropboxTransportClientImpl(accessToken: \"\u003cMY_ACCESS_TOKEN\u003e\",\n                                             baseHosts: nil,\n                                             userAgent: \"CustomUserAgent\",\n                                             selectUser: nil,\n                                             sessionConfiguration: mySessionConfiguration,\n                                             longpollSessionConfiguration: myLongpollSessionConfiguration,\n                                             authChallengeHandler: nil)\n\nDropboxClientsManager.setupWithAppKey(\"\u003cAPP_KEY\u003e\", transportClient: transportClient)\n```\n\n##### macOS\n```Swift\nimport SwiftyDropbox\n\nlet transportClient = DropboxTransportClientImpl(accessToken: \"\u003cMY_ACCESS_TOKEN\u003e\",\n                                             baseHosts: nil,\n                                             userAgent: \"CustomUserAgent\",\n                                             selectUser: nil,\n                                             sessionConfiguration: mySessionConfiguration,\n                                             longpollSessionConfiguration: myLongpollSessionConfiguration,\n                                             authChallengeHandler: nil)\n\nDropboxClientsManager.setupWithAppKeyDesktop(\"\u003cAPP_KEY\u003e\", transportClient: transportClient)\n```\n\n#### Specify API call response queue\n\nBy default, response/progress handler code runs on the main thread. You can set a custom response queue for each API call that you make via the `response` method, in the event want your response/progress handler code to run on a different thread:\n\n```Swift\nlet client = DropboxClientsManager.authorizedClient!\n\nclient.files.listFolder(path: \"\").response(queue: DispatchQueue(label: \"MyCustomSerialQueue\")) { response, error in\n    if let result = response {\n        print(Thread.current)  // Output: \u003cNSThread: 0x61000007bec0\u003e{number = 4, name = (null)}\n        print(Thread.main)     // Output: \u003cNSThread: 0x608000070100\u003e{number = 1, name = (null)}\n        print(result)\n    }\n}\n```\n\n#### Mock API responses in tests\n\nWhen testing code that depends upon the SDK, it can be useful to mock arbitrary API responses from JSON fixtures. We recommend using dependency injection rather than accessing the client via the convenience singletons. Note that the mocks are not public, they are only available in tests when SwiftyDropbox is imported using the `@testable` attribute.\n\n```Swift\n@testable import SwiftyDropbox\n\nlet transportClient = MockDropboxTransportClient()\nlet dropboxClient = DropboxClient(transportClient: transportClient)\n\n// your feature under test\nlet commentClient = CommentClient(apiClient: dropboxClient)\n\nlet expectation = expectation(description: \"added comment\")\n\n// function of your feature that relies upon Dropbox api response\ncommentClient.addComment(\n    forIdentifier: identifier,\n    commentId: \"pendingCommentId\",\n    threadId: nil,\n    message: \"hello world\",\n    mentions: [],\n    annotation: nil\n) { result in\n    XCTAssertEqual(result.commentId, \"thread-1\")\n    XCTAssertNil(result.error)\n    addCommentExpectation.fulfill()\n}\n\nlet mockInput: MockInput = .success(\n    json: [\"id\": \"thread-1\", \"status\": 1]\n)\n\nlet request = try XCTUnwrap(transportClient.getLastRequest())\ntry request.handleMockInput(mockInput)\n\nwait(for: [expectation], timeout: 1.0)\n```\n\n---\n\n### Supporting background networking\n\nVersions 10.0 and higher support iOS background networking from applications and their extensions.\n\n#### Initialization\n\nTo create a background client, provide a background session identifier. To use a shared container, specify that as well.\n\n```Swift\nimport SwiftyDropbox\n\nDropboxClientsManager.setupWithAppKey(\n    \"\u003cAPP_KEY\u003e\",\n    backgroundSessionIdentifier: \"\u003cBACKGROUND_SESSION_IDENTIFIER\u003e\",\n    requestsToReconnect: { requestResults in\n       // app code to handle results of completed requests\n   }\n)\n```\n\nIf you're setting up a background client from an app extension, you'll need to specify a shared container identifier and configure and app group or keychain sharing appropriately.\n```Swift\nDropboxClientsManager.setupWithAppKey(\n    \"\u003cAPP_KEY\u003e\",\n    backgroundSessionIdentifier: \"\u003cBACKGROUND_SESSION_IDENTIFIER\u003e\"\n    sharedContainerIdentifier: \"\u003cSHARED_CONTAINER_IDENTIFIER\u003e\",\n    requestsToReconnect: { requestResults in\n       // app code to handle results of completed requests\n   }\n)\n```\n Apps in an app group automatically have keychain sharing. App groups are required for using a shared container, which is necessary if your applications will be downloading files using background sessions in extensions. See:\n- https://developer.apple.com/documentation/xcode/configuring-app-groups\n- https://developer.apple.com/documentation/xcode/configuring-keychain-sharing\n\n#### Making requests\nMake requests like you would with a foreground client.\n\n```Swift\nlet client = DropboxClientsManager.authorizedBackgroundClient!\n\nclient.files.download(path: path, overwrite: true, destination: destinationUrl) {\n    if let result = response {\n        print(result)\n    }\n}\n```\n\n#### Customizing requests\nSet background session related properties on requests for fine-grained control.\n\n```Swift\nclient.files.download(path: path, overwrite: true, destination: destinationUrl)\n    .persistingString(string: \"\u003cDATA_AVAILABLE_ACROSS_APP_SESSIONS\u003e\")\n    .settingEarliestBeginDate(date: .addingTimeInterval(fiveSeconds))\n    .response { response, error in\n{\n    if let result = response {\n        print(result)\n    }\n})\n```\n\n#### Reconnecting to requests across app sessions\nAs background requests potentially span app sessions, the app will recieve `AppDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` when woken to handle events. SwiftyDropbox can reconnect completion handlers to requests. The application must set up the `authorizedBackgroundClient` prior to attempting reconnection.\n\nIn the reconnection block you're recieving a heterogenous collection of the routes requested on the background session. Handling the response will likely require context that must be persisted across sessions. You can use `.persistingString(string:)` and `.clientPersistedString` on request to store this context. Depending on your use case you may need to persist additional context in your application.\n\n```Swift\n    func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -\u003e Void) {\n        DropboxClientsManager.handleEventsForBackgroundURLSession(\n            with: identifier,\n            creationInfos: [],\n            completionHandler: completionHandler,\n            requestsToReconnect: { requestResults in\n                processReconnect(requestResults: requestResults) // provide your own code here to process the completed requests. \n            }\n        )\n    }\n\n    func processReconnect(requestResults: ([Result\u003cDropboxBaseRequestBox, ReconnectionError\u003e])) {\n        let successfulReturnedRequests = requestResults.compactMap { result -\u003e DropboxBaseRequestBox? in\n            switch result {\n            case .success(let requestBox):\n                return requestBox\n            case .failure(let error):\n                // handle error\n                return nil\n            }\n        }\n\n        for request in successfulReturnedRequests {\n            switch request {\n            case .download(let downloadRequest):\n                downloadRequest.response { response, error in\n                    // handle response\n                }\n            case .upload(let uploadRequest):\n                uploadRequest.response { response, error in\n                    // handle response\n                }\n            // or .downloadZip, .paperCreate, .getSharedLinkFile etc.\n            default:\n                // handle every case you expect to see, this should never be reached.\n            }\n        }\n    }\n```\n\nIn the event that the requests originated from an App Extension, SwiftyDropbox must recreate the extension background client in order to reconnect the requests.\n\n```Swift\n    func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -\u003e Void) {\n        let extensionCreationInfo: BackgroundExtensionSessionCreationInfo = .init(defaultInfo: .init(\n            backgroundSessionIdentifier: \"\u003cEXTENSION_BACKGROUND_SESSION_IDENTIFIER\u003e\",\n            sharedContainerIdentifier: \"\u003cEXTENSION_SHARED_CONTAINER_IDENTIFIER\u003e\"\n        ))\n\n        DropboxClientsManager.handleEventsForBackgroundURLSession(\n            with: identifier,\n            creationInfos: [extensionCreationInfo],\n            completionHandler: completionHandler,\n            requestsToReconnect: { requestResults in\n                processReconnect(requestResults: requestResults) // provide your own code here to process the completed requests.\n            }\n        )\n    }\n```\n\n#### Debugging\nBackground sessions are difficult to debug. Both simulators and the Xcode debugger will cause the application to behave in meaningfully different ways–verification of correct reconnection behavior should always take place on a physical device without the debugger connected. Logs to console can be viewed via Xcode -\u003e Window -\u003e Devices and Simulators and are a good bet for gaining insights here. Force quitting the application will disqualify it from continuing to do work in the background.\n\nFor a good discussion of this, see https://developer.apple.com/forums/thread/14855.\n\n#### Persistence\nSwiftyDropbox tracks state and orchestrates reconnection by writing a JSON string to `URLSessionTask.taskDescription` a property that `URLSession` itself persists across app sessions.\n\nAbove, in Customizing Requests, is an example of the ability of a client of SwiftyDropbox to persist its own arbitrary strings alongside SwiftyDropbox's private use of this field. This could be useful for storing the information needed to reconstruct a completion handler for a task after reconnection.\n\nDepending on the needs of the application, this lightweight solution may be insufficient persistent bookkeeping, and the application may build independate private persistence mapping state to an id stored on the request. This could be useful in the event that a failure occurs where URLSession itself has lost track of the transfer and it must be recreated.\n\nSee https://developer.apple.com/forums/thread/11554 for further discussion.\n\n---\n\n\n### `DropboxClientsManager` class\n\nThe Swift SDK includes a convenience class, `DropboxClientsManager`, for integrating the different functions of the SDK into one class.\n\n#### Single Dropbox user case\n\nFor most apps, it is reasonable to assume that only one Dropbox account (and access token) needs to be managed at a time. In this case, the `DropboxClientsManager` flow looks like this:\n\n* call `setupWithAppKey`/`setupWithAppKeyDesktop` (or `setupWithTeamAppKey`/`setupWithTeamAppKeyDesktop`) in integrating app's app delegate\n* client manager determines whether any access tokens are stored -- if any exist, one token is arbitrarily chosen to use\n* if no token is found, call `authorizeFromControllerV2` to initiate the OAuth flow\n* if auth flow is initiated, call `handleRedirectURL` (or `handleRedirectURLTeam`) in integrating app's app delegate to handle auth redirect back into the app and store the retrieved access token (using a `DropboxOAuthManager` instance)\n* client manager instantiates a `DropboxTransportClient` (if not supplied by the user)\n* client manager instantiates a `DropboxClient` (or `DropboxTeamClient`) with the transport client as a field\n\nThe `DropboxClient` (or `DropboxTeamClient`) is then used to make all of the desired API calls.\n\n* On `DropboxClientsManager`, call `unlinkClients` to logout Dropbox user and clear all access tokens\n\n#### Multiple Dropbox user case\n\nFor some apps, it is necessary to manage more than one Dropbox account (and access token) at a time. In this case, the `DropboxClientsManager` flow looks like this:\n\n* access token uids are managed by the app that is integrating with the SDK for later lookup\n* call `setupWithAppKeyMultiUser`/`setupWithAppKeyMultiUserDesktop` (or `setupWithTeamAppKeyMultiUser`/`setupWithTeamAppKeyMultiUserDesktop`) in integrating app's app delegate\n    * _SwiftUI note: You may need to create an Application Delegate if your application doesn't have one._\n* client manager determines whether an access token is stored with the`tokenUid` as a key -- if one exists, this token is chosen to use\n* if no token is found, call `authorizeFromControllerV2` to initiate the OAuth flow\n* if auth flow is initiated, call `handleRedirectURL` (or `handleRedirectURLTeam`) in integrating app's app delegate to handle auth redirect back into the app and store the retrieved access token (using a `DropboxOAuthManager` instance)\n    * _SwiftUI note: You may need to create an Application Delegate if your application doesn't have one._\n* at this point, the app that is integrating with the SDK should persistently save the `tokenUid` from the `DropboxAccessToken` field of the `DropboxOAuthResult` object returned from the `handleRedirectURL` (or `handleRedirectURLTeam`) method\n* `tokenUid` can be reused either to authorize a new user mid-way through an app's lifecycle via `reauthorizeClient` (or `reauthorizeTeamClient`) or when the app initially launches via `setupWithAppKeyMultiUser`/`setupWithAppKeyMultiUserDesktop` (or `setupWithTeamAppKeyMultiUser`/`setupWithTeamAppKeyMultiUserDesktop`)\n* client manager instantiates a `DropboxTransportClient` (if not supplied by the user)\n* client manager instantiates a `DropboxClient` (or `DropboxTeamClient`) with the transport client as a field\n\nThe `DropboxClient` (or `DropboxTeamClient`) is then used to make all of the desired API calls.\n\n* On `DropboxClientsManager` call `resetClients` to logout Dropbox user but not clear any access tokens\n* if specific access tokens need to be removed, use the `clearStoredAccessToken` method in `DropboxOAuthManager`\n\n---\n## Objective-C\n\nIf you need to interact with the Dropbox SDK in Objective-C code there is an Objective-C compatibility layer for the SDK that can be used.\n\n### Objective-C Compatibility Layer Distribution\n\n#### Swift Package Manager\n\nThe Objective-C compatibility layer is in the same package outlined in [SDK distribution](#sdk-distribution). After adding the package you will see a target named `SwiftyDropboxObjC` that can be added in the same way as the Swift SDK and used in its place.\n\n#### Cocoapods\n\nFor cocoapods, in your Podfile, simply specify `SwiftyDropboxObjC` instead of (or in addition to) `SwiftyDropbox`.\n\n```ruby\nuse_frameworks!\n\ntarget '\u003cYOUR_PROJECT_NAME\u003e' do\n    pod 'SwiftyDropboxObjC', '~\u003e 10.2.3'\nend\n```\n\n### Using the Objective-C Compatbility Layer\n\nThe Objective-C interface was built to mimic the Swift interface as closely as possible while still maintaining good Objective-C patterns and practices (for example full verbose names instead of the namespacing relied on in Swift). Other than the naming and some other small tweaks to accomodate Objective-C the usage of the SDK should be extremely similar in both languages, thus the instructions above should apply even when in Objective-C.\n\nAn example of the differences between Swift and Objective-C:\n\nSwift:\n```Swift\nimport SwiftyDropbox\n\nlet userSelectArg = Team.UserSelectorArg.email(\"some@email.com\")\nDropboxClientsManager.team.membersGetInfo(members: [userSelectArg]).response { response, error in\n    if let result = response {\n        // Handle result\n    } else {\n        // Handle error\n    }\n}\n```\n\nObjective-C:\n```objc\n@import SwiftyDropboxObjC;\n\nDBXTeamUserSelectorArgEmail *selector = [[DBXTeamUserSelectorArgEmail alloc] init:@\"some@email.com\"]\n[[DBXDropboxClientsManager.authorizedTeamClient.team membersGetInfoWithMembers:@[selector]] responseWithCompletionHandler:^(NSArray\u003cDBXTeamMembersGetInfoItem *\u003e * _Nullable result, DBXTeamMembersGetInfoError * _Nullable routeError, DBXCallError * _Nullable error) {\n    if (result) {\n        // Handle result\n    } else {\n        // Handle error\n    }\n}];\n```\n\n### Migrating from dropbox-sdk-obj-c\n\nIf you previously integrated with [dropbox-sdk-obj-c](https://github.com/dropbox/dropbox-sdk-obj-c) migrating to the Swift SDK + Objective-C layer will require code changes but they should be relatively straight forward in most cases.\n\nIn order to maintain as consistent of an interface between Swift and Objective-C as possible in this SDK the interface did have to differ slightly from [dropbox-sdk-obj-c](https://github.com/dropbox/dropbox-sdk-obj-c). The primary differences are as follows:\n\n1.) Type names are derived from SwiftyDropbox types prefixed with DBX. There are generally some differences in naming from dropbox-sdk-obj-c, and with Swift's more granular access control some previously accessbile types are now internal to the SDK only. See [Common type migration reference](#common-type-migration-reference).\n\n2.) Some function names have changed slightly to be more verbose about arguments and/or to better match the Swift interface. In the following example note `createFolderV2` vs `createFolderV2WithPath` and `responseWithCompletionHandler` vs `setResponseBlock`:\n\ndropbox-sdk-obj-c:\n```objc\n[[[DBClientsManager authorizedClient].filesRoutes createFolderV2:@\"/some/folder/path\"]\n  setResponseBlock:^(DBFILESCreateFolderResult * _Nullable result, DBFILESCreateFolderError * _Nullable routeError, DBRequestError * _Nullable networkError) {\n    // Handle response\n}];\n```\nSwiftyDropboxObjC:\n\n```objc\n[[DBXDropboxClientsManager.authorizedClient.files createFolderV2WithPath:@\"some/folder/path\"] responseWithCompletionHandler:^(DBXFilesCreateFolderResult * _Nullable result, DBXFilesCreateFolderError * _Nullable routeError, DBXCallError * _Nullable error) {\n    // Handle response\n}];\n```\n\n3.) Capitalization has changed on many classes.\n\ndropbox-sdk-obj-c:\n`DBUSERSBasicAccount`\n\nSwiftyDropboxObjC:\n`DBXUsersBasicAccount`\n\n4.) Representation of enums that are passed to or returned from the server are now explicitly typed in the class name:\n\ndropbox-sdk-obj-c:\n\n```objc\nDBTEAMUserSelectorArg *userSelectArg = [[DBTEAMUserSelectorArg alloc] initWithEmail:@\"some@email.com\"];\n```\nSwiftyDropboxObjC:\n\n```objc\nDBXTeamUserSelectorArgEmail *userSelectArg = [[DBXTeamUserSelectorArgEmail alloc] init:@\"some@email.com\"];\n```\n\n5.) When working with tasks you no longer need to manually `start` the tasks. They are automatically started on creation.\n\n6.) SwiftyDropbox relies on generics for typed completion handlers on Requests. This is not bridgeable to Objective-C. Instead, for each route there is an additional Request type with the correctly typed completion handler. E.g., `DownloadRequestFile\u003cFiles.FileMetadataSerializer, Files.DownloadErrorSerializer\u003e` is represented in Objective-C as `DBXFilesDownloadDownloadRequestFile`.\n\n### Common type migration reference\n| dropbox-sdk-objc-c                             | SwiftyDropbox                 | SwiftyDropboxObjC                                              |\n|------------------------------------------------|-------------------------------|------------------------------------------------------------|\n| DBAppClient                                    | DropboxAppClient              | DBXDropboxAppBase                                          |\n| DBClientsManager                               | DropboxClientsManager         | DBXDropboxClientsManager                                   |\n| DBTeamClient                                   | DropboxTeamClient             | DBXDropboxTeamClient                                       |\n| DBUserClient                                   | DropboxClient                 | DBXDropboxClient                                           |\n| DBRequestErrors                                | CallError                     | DBXCallError                                               |\n| DBRpcTask                                      | RpcRequest                    | DBX\u003croute-name\u003eRpcRequest                                  |\n| DBUploadTask                                   | UploadRequest                 | DBX\u003croute-name\u003eUploadRequest                               |\n| DBDownloadUrlTask                              | DownloadRequestFile           | DBX\u003croute-name\u003eDownloadRequestFile                         |\n| DBDownloadDataTask                             | DownloadRequestMemory         | DBX\u003croute-name\u003eDownloadRequestMemory                       |\n| DBTransportBaseClient/DBTransportDefaultClient | DropboxTransportClientImpl    | DBXDropboxTransportClient                                  |\n| DBTransportBaseHostnameConfig                  | BaseHosts                     | DBXBaseHosts                                               |\n| DBAccessTokenProvider                          | AccessTokenProvider           | DBXAccessTokenProvider                                     |\n| DBLongLivedAccessTokenProvider                 | LongLivedAccessTokenProvider  | DBXLongLivedAccessTokenProvider                            |\n| DBShortLivedAccessTokenProvider                | ShortLivedAccessTokenProvider | DBXShortLivedAccessTokenProvider                           |\n| DBLoadingStatusDelegate                        | LoadingStatusDelegate         | DBXLoadingStatusDelegate                                   |\n| DBOAuthManager                                 | DropboxOAuthManager           | DBXDropboxOAuthManager                                     |\n| DBAccessToken                                  | DropboxAccessToken            | DBXDropboxAccessToken                                      |\n| DBAccessTokenRefreshing                        | AccessTokenRefreshing         | DBXAccessTokenRefreshing                                   |\n| DBOAuthResult                                  | DropboxOAuthResult            | DBXDropboxOAuthResult                                      |\n| DBOAuthResultCompletion                        | DropboxOAuthCompletion        | (DBXDropboxOAuthResult?) -\u003e Void                           |\n| DBScopeRequest                                 | ScopeRequest                  | DBXScopeRequest                                            |\n| DBSDKKeychain                                  | SecureStorageAccess           | DBXSecureStorageAccess / DBXSecureStorageAccessDefaultImpl |\n| DBDelegate                                     | n/a                           | n/a                                                        |\n| DBGlobalErrorResponseHandler                   | n/a                           | n/a                                                        |\n| DBSDKReachability                              | n/a                           | n/a                                                        |\n| DBSessionData                                  | n/a                           | n/a                                                        |\n| DBTransportDefaultConfig                       | n/a                           | n/a                                                        |\n| DBURLSessionTaskResponseBlockWrapper           | n/a                           | n/a                                                        |\n| DBURLSessionTaskWithTokenRefresh               | n/a                           | n/a                                                        |\n| DBOAuthPKCESession                             | n/a                           | n/a                                                        |\n| DBOAuthTokenRequest                            | n/a                           | n/a                                                        |\n\n---\n\n## Changes in version 10.0.0\n\nVersion 10.0.0 of SwiftyDropbox differs significantly from version 9.2.0. It aims to support Objective-C, remove AlamoFire as a dependency, support background networking, replace fatal errors during serialization, add unit tests, and better support testing.\n\nThese additional features are the greatest differences, but even simple upgrades that don't utilize these new features should consider the other notable changes.\n\n- The destination to which a file is downloaded must now be specified at the time of the call. It's no longer possible to provide a closure that is evaluated after the request is complete.\n\n- The older API for SSL certificate pinning, provided through AlamoFire, is no longer available. This version exposes the URLSession authentication challenge API. Additionally, the optional SessionDelegate from the previous version of the SDK has been removed without a direct replacement.  If your workflows relied on these specific features in ways that are no longer implementable, please [inform us](https://github.com/dropbox/SwiftyDropbox/issues) so that we can better understand and address any potential issues.\n\n- Serialization inconsistencies that used to cause fatal errors now are represented as errors piped through to the requests' completion handlers. It is up to the calling app to decide how to handle them.\n\n- Carthage is no longer supported, please use Swift Package Manager or Cocoapods.\n\n- SDK classes can no longer be subclassed. If this disrupts your usage, please [let us know](https://github.com/dropbox/SwiftyDropbox/issues).\n\n- Due to the extensive nature of the rewrite and the introduction of new features in the new version of the SDK, when transitioning to the new version of the SDK it is important to perform thorough testing of your codebase. The significant changes and enhancements in the new version of the SDK may introduce subtle behavioral changes or edge cases that were not present in the previous version of the SDK.\n\n### New Features\n\nFor notes on Objective-C support see [Migrating from dropbox-sdk-obj-c](#migrating-from-dropbox-sdk-obj-c)\n\nThe SDK's background networking support simplifies the reconnection of completion handlers to URLSession tasks. See [`TestSwiftyDropbox/DebugBackgroundSessionViewModel`](https://github.com/dropbox/SwiftyDropbox/tree/master/TestSwiftyDropbox/TestSwiftyDropbox_SwiftUI/iOS) for code that exercises various background networking scenarios. See [`TestSwiftDropbox/ActionRequestHandler`](https://github.com/dropbox/SwiftyDropbox/blob/master/TestSwiftyDropbox/TestSwiftyDropbox_ActionExtension/ActionRequestHandler.swift) for usage from an app extension.\n\n### Testing Support\n\nInitialize a `DropboxClient` with a `MockDropboxTransportClient` to facillitate route response mocking in tests. Supply this client to your code under test, excercise the code, then pipe in responses as illustrated below and assert against your code's behavior.\n\n```\nlet transportClient = MockDropboxTransportClient()\n\nlet client = DropboxClient(\n    transportClient: transportClient\n)\n\nlet feature = SystemUnderTest(client: client)\n\nlet json: [String: Any] = [\"fileNames\": [\"first\"]]\n\nlet request = transportClient.getLastRequest()\n\nrequest.handleMockInput(.success(json: json))\n\nXCTAssert(\u003cstate of feature\u003e, \u003cexpected state\u003e)\n\n```\n\n---\n\n## Examples\n\n* [PhotoWatch](https://github.com/dropbox/PhotoWatch) - View photos from your Dropbox. Supports Apple Watch.\n\n---\n\n## Documentation\n\n* [Dropbox API v2 Swift SDK](http://dropbox.github.io/SwiftyDropbox/api-docs/latest/)\n* [Dropbox API v2](https://www.dropbox.com/developers/documentation/http/documentation)\n\n---\n\n## Stone\n\nAll of our routes and data types are auto-generated using a framework called [Stone](https://github.com/dropbox/stone).\n\nThe `stone` repo contains all of the Swift specific generation logic, and the `spec` repo contains the language-neutral API endpoint specifications which serve\nas input to the language-specific generators.\n\n---\n\n## Modifications\n\nIf you're interested in modifying the SDK codebase, you should take the following steps:\n\n* clone this GitHub repository to your local filesystem\n* run `git submodule init` and then `git submodule update`\n* navigate to `TestSwifty_[iOS|macOS]`\n* check the CocoaPods version installed (via `pod --version`) is same as \"locked\" in `TestSwifty_[iOS|macOS]/Podfile.lock`\n* run `pod install`\n* open `TestSwifty_[iOS|macOS]/TestSwifty_[iOS|macOS].xcworkspace` in Xcode\n* implement your changes to the SDK source code.\n\nTo ensure your changes have not broken any existing functionality, you can run a series of integration tests:\n* create a new app on https://www.dropbox.com/developers/apps/, with \"Full Dropbox\" access. Note the App key\n* open Info.plist and configure the \"URL types \u003e Item 0 (Editor) \u003e URL Schemes \u003e Item 0\" key to db-\"App key\"\n* open AppDelegate.swift and replace \"FULL_DROPBOX_APP_KEY\" with the App key as well\n* run the test app on your device and follow the on-screen instructions\n\nTo run and develop against the unit tests instead of the integration tests, open the root of the cloned repository in Xcode. Please run the integration tests after development.\n\n---\n\n## App Store Connect Privacy Labels\n\nTo assist developers using Dropbox SDKs in filling out Apple’s Privacy Practices Questionnaire, we’ve provided the below information on the data that may be collected and used by Dropbox.\n\nAs you complete the questionnaire you should note that the below information is general in nature. Dropbox SDKs are designed to be configured by the developer to incorporate Dropbox functionality as is best suited to their application. As a result of this customizable nature of the Dropbox SDKs, we are unable to provide information on the actual data collection and use for each application. We advise developers reference our Dropbox for HTTP Developers for specifics on how data is collected by each Dropbox API.\n\nIn addition, you should note that the information below only identifies Dropbox’s collection and use of data. You are responsible for identifying your own collection and use of data in your app, which may result in different questionnaire answers than identified below:\n\n| Data                    | Collected by Dropbox                                                      | Data Use                                                                 | Data Linked to the User | Tracking |\n| ----------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------ | ----------------------- | -------- |\n| **Contact Info**        |                                                                           |                                                                          |                         |          |\n| \u0026emsp;• Name            | Not collected                                                             | N/A                                                                      | N/A                     | N/A      |\n| \u0026emsp;• Email Address   | May be collected\u003cbr\u003e(if you enable authentication using an email address) | • Application functionality                                              | Y                       | N        |\n| **Health \u0026 Fitness**    | Not collected                                                             | N/A                                                                      | N/A                     | N/A      |\n| **Financial Info**      | Not collected                                                             | N/A                                                                      | N/A                     | N/A      |\n| **Location**            | Not collected                                                             | N/A                                                                      | N/A                     | N/A      |\n| **Sensitive Info**      | Not collected                                                             | N/A                                                                      | N/A                     | N/A      |\n| **Contacts**            | Not collected                                                             | N/A                                                                      | N/A                     | N/A      |\n| **User Content**        |                                                                           |                                                                          |                         |          |\n| \u0026emsp;• Audio Data      | May be collected                                                          | • Application functionality                                              | Y                       | N        |\n| \u0026emsp;• Photos or Videos | May be collected                                                          | • Application functionality                                              | Y                       | N        |\n| \u0026emsp;• Other User Content | May be collected                                                          | • Application functionality                                              | Y                       | N        |\n| **Browsing History**    | Not collected                                                             | N/A                                                                      | N/A                     | N/A      |\n| **Search History**      |                                                                           |                                                                          |                         |          |\n| \u0026emsp;• Search History  | May be collected\u003cbr\u003e(if using search functionality)                       | • Application functionality\u003cbr\u003e• Analytics                               | Y                       | N        |\n| **Identifiers**         |                                                                           |                                                                          |                         |          |\n| \u0026emsp;• User ID         | Collected                                                                 | • Application functionality\u003cbr\u003e• Analytics                               | Y                       | N        |\n| **Purchases**           | Not collected                                                             | N/A                                                                      | N/A                     | N/A      |\n| **Usage Data**          |                                                                           |                                                                          |                         |          |\n| \u0026emsp;• Product Interaction | Collected                                                                 | • Application functionality \u003cbr\u003e• Analytics\u003cbr\u003e• Product personalization | Y                       | N        |\n| **Diagnostics**         |                                                                           |                                                                          |                         |          |\n| \u0026emsp;• Other Diagnostic Data | Collected\u003cbr\u003e(API call logs)                                              | • Application functionality                                              | Y                       | N        |\n| **Other Data**          | N/A                                                                       | N/A                                                                      | N/A                     | N/A      |\n\n---\n\n## Bugs\n\nPlease post any bugs to the [issue tracker](https://github.com/dropbox/SwiftyDropbox/issues) found on the project's GitHub page.\n\nPlease include the following with your issue:\n - a description of what is not working right\n - sample code to help replicate the issue\n\nThank you!\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdropbox%2Fswiftydropbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdropbox%2Fswiftydropbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdropbox%2Fswiftydropbox/lists"}