SwiftyDropbox

repository·master·Indexed 20 days ago

https://github.com/dropbox/swiftydropbox

The Official Dropbox Swift SDK for integrating Dropbox API v2 functionality into iOS (12.0+) and macOS (10.13+) applications. It supports OAuth 2.0 authorization with PKCE, Swift concurrency (async/await) as of version 10.0.0, and background networking for iOS. The SDK provides tools for handling RPC, upload, and download requests, as well as support for Dropbox-specific union types and datatypes with subtypes.

Tokens
7.4K
Snippets
16
Records
22
Agent score
22%

What's inside SwiftyDropbox

  1. Manage single vs multiple Dropbox users with DropboxClientsManager

    master

    The DropboxClientsManager handles the lifecycle of Dropbox accounts within your app.

    Single User Flow

    1. Call setupWithAppKey (or setupWithAppKeyDesktop) in your App Delegate.
    2. The manager checks for stored tokens. If none exist, call authorizeFromControllerV2 to start OAuth.
    3. Handle the redirect in the App Delegate using handleRedirectURL.
    4. Use DropboxClientsManager.authorizedClient to make calls.
    5. To logout, call unlinkClients.

    Multiple User Flow

    1. Use setupWithAppKeyMultiUser (or setupWithAppKeyMultiUserDesktop).
    2. When an OAuth flow completes via handleRedirectURL, the app must persistently save the tokenUid from the DropboxOAuthResult.
    3. To switch users or authorize a new one, use reauthorizeClient(tokenUid:).
    4. To logout a specific user, use clearStoredAccessToken in DropboxOAuthManager.
  2. Handle Dropbox union types and datatypes with subtypes

    master

    Dropbox API v2 uses two specific data models that require careful handling in Swift:

    Union Types

    Union types represent a single value that can take on multiple different types depending on its state (the "tag"). To handle them, use a switch statement on the error or result to check the tag state. Once the tag is identified, you can access its associated value. Example: Files.DeleteError can be .pathLookup or .pathWrite.

    Datatypes with Subtypes

    These are hybrid objects (structs with a tag) that represent a common supertype containing shared fields, but can exist as different specific subtypes at runtime. To access subtype-specific fields, cast the object using a switch statement. Example: Metadata can be cast to Files.FileMetadata, Files.FolderMetadata, or Files.DeletedMetadata.

    Error Handling Strategy

    When an error occurs, cast it to CallError. You can then switch between .routeError (for API-specific errors like Files.DeleteError) and generic errors like .internalServerError, .authError, or .rateLimitError.

    // Handling a Union Type Error
    client.files.deleteV2(path: "/path").response { response, error in
        if let error = error {
            switch error as CallError {
            case .routeError(let boxed, _, _, _):
                switch boxed.unboxed as Files.DeleteError {
                case .pathLookup(let lookupError):
                    // handle lookup error
                case .pathWrite(let writeError):
                    // handle write error
                default: break
                }
            default: break
            }
        }
    }
    
    // Handling a Datatype with Subtypes
    if let response = response {
        switch response {
        case let fileMetadata as Files.FileMetadata:
            print(fileMetadata)
        case let folderMetadata as Files.FolderMetadata:
            print(folderMetadata)
        default: break
        }
    }
  3. Handle Dropbox API responses and errors

    master

    Dropbox API v2 requests fall into three categories: RPC, Upload, and Download. All endpoints require a response handler.

    Response Handler Arguments

    Response handler blocks receive:

    1. route result type: The data returned by the endpoint (or Void if the route has no return type).
    2. network error: Either a route-specific error or a generic network error.
    3. output content: A URL or Data reference (only for Download-style endpoints).

    Swift Concurrency (async/await)

    As of version 10.0.0, you can use the .response() function with async/await instead of completion handlers.

    Request Types

    • RPC-style: Standard calls like createFolder.
    • Upload-style: Calls like upload that accept Data and support .progress handlers and .cancel().
    • Download-style: Calls like download that can download to a local URL or directly into Data.
    // Swift Concurrency example
    let response = try await client.files.createFolder(path: "/test/path/in/Dropbox/account").response()
    
    // Upload-style with progress and cancellation
    let request = client.files.upload(path: "/path", input: fileData)
        .response { response, error in /* handle */ }
        .progress { progressData in /* handle */ }
    
    if someCondition { request.cancel() }
  4. How to modify the SwiftyDropbox SDK

    master

    If you intend to contribute to or modify the SDK, follow these steps to set up your local development environment:

    1. Clone the repository.
    2. Initialize and update submodules:
      git submodule init
      git submodule update
    3. Navigate to the platform directory: TestSwifty_[iOS|macOS].
    4. Ensure your CocoaPods version matches the version locked in TestSwifty_[iOS|macOS]/Podfile.lock.
    5. Run pod install.
    6. Open the .xcworkspace in Xcode.

    Running Integration Tests: To verify changes using the integration test app:

    1. Create a 'Full Dropbox' app on the Dropbox Developer Console and note the App key.
    2. In the test app's Info.plist, configure the URL Scheme: URL types > Item 0 (Editor) > URL Schemes > Item 0 to db-[YOUR_APP_KEY].
    3. In AppDelegate.swift, replace FULL_DROPBOX_APP_KEY with your actual App key.
    4. Run the test app on a device and follow the on-screen instructions.
  5. Configure the Dropbox network client

    master

    You can customize the underlying networking behavior by providing a custom DropboxTransportClientImpl. This allows you to specify a custom userAgent, sessionConfiguration, or authChallengeHandler.

    iOS Setup

    Use DropboxClientsManager.setupWithAppKey with your transport client.

    macOS Setup

    Use DropboxClientsManager.setupWithAppKeyDesktop with your transport client.

    import SwiftyDropbox
    
    let transportClient = DropboxTransportClientImpl(
        accessToken: "<MY_ACCESS_TOKEN>",
        userAgent: "CustomUserAgent",
        sessionConfiguration: mySessionConfiguration
    )
    
    // For iOS
    DropboxClientsManager.setupWithAppKey("<APP_KEY>", transportClient: transportClient)
    
    // For macOS
    DropboxClientsManager.setupWithAppKeyDesktop("<APP_KEY>", transportClient: transportClient)
  6. Configure the Application .plist file

    master

    To support the Dropbox Swift SDK, you must modify your application's .plist file to allow URL scheme queries and to register a custom redirect URL scheme for OAuth 2.0 completion.

    1. Allow URL Queries: Add LSApplicationQueriesSchemes to allow the SDK to check if the official Dropbox iOS app is installed. This enables 'Direct auth' on iOS.
    2. Register Redirect Scheme: Add a CFBundleURLTypes entry with a scheme formatted as db-<APP_KEY>, where <APP_KEY> is your Dropbox app key from the App Console.
    <!-- LSApplicationQueriesSchemes configuration -->
    <key>LSApplicationQueriesSchemes</key>
    <array>
        <string>dbapi-8-emm</string>
        <string>dbapi-2</string>
    </array>
    
    <!-- CFBundleURLTypes configuration -->
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>db-<APP_KEY></string>
            </array>
            <key>CFBundleURLName</key>
            <string></string>
        </dict>
    </array>
  7. Use the Objective-C compatibility layer

    master

    If you need to interact with the Dropbox SDK in Objective-C code, use the SwiftyDropboxObjC compatibility layer. This layer is designed to mimic the Swift interface closely while following Objective-C patterns (e.g., using verbose names instead of Swift-style namespacing).

    Distribution

    Swift Package Manager

    Add the same package used for the Swift SDK. After adding it, include the SwiftyDropboxObjC target in your project.

    CocoaPods

    In your Podfile, specify SwiftyDropboxObjC instead of (or in addition to) SwiftyDropbox.

    use_frameworks!
    
    target '<YOUR_PROJECT_NAME>' do
        pod 'SwiftyDropboxObjC', '~> 10.2.4'
    end
  8. Register your application and obtain an OAuth 2.0 token

    master

    Before using the SDK, you must complete these two steps:

    1. Register your application: Create an app in the Dropbox App Console. This associates your API calls with your specific application.
    2. Obtain an OAuth 2.0 token: All requests require an access token.
      • Manual: You can manually generate a token in the App Console for testing your own account.
      • Programmatic: You can obtain tokens programmatically using the SDK's built-in authorization flow (see 'Handling the authorization flow' in the documentation).
  9. Install the Dropbox Swift SDK via Swift Package Manager

    master

    You can integrate the SDK into your project using Swift Package Manager by adding the following repository URL as a dependency:

    https://github.com/dropbox/SwiftyDropbox.git

    https://github.com/dropbox/SwiftyDropbox.git
  10. Implement background networking

    master

    Versions 10.0+ support iOS background networking. This allows transfers to continue even if the app is suspended.

    Initialization

    When calling setupWithAppKey, provide a backgroundSessionIdentifier. For app extensions, also provide a sharedContainerIdentifier and ensure App Groups/Keychain sharing are configured in Xcode.

    Reconnecting Requests

    Because background requests can span app sessions, you must handle reconnection in your AppDelegate using DropboxClientsManager.handleEventsForBackgroundURLSession.

    In the requestsToReconnect block, you receive a collection of results. You must iterate through these and re-attach your completion handlers. To help reconstruct context (like which UI element to update), use .persistingString(string:) on your requests to store metadata that persists across sessions.

    // Initialization
    DropboxClientsManager.setupWithAppKey(
        "<APP_KEY>",
        backgroundSessionIdentifier: "<BACKGROUND_SESSION_IDENTIFIER>",
        requestsToReconnect: { requestResults in
           // Handle reconnection logic
       }
    )
    
    // Reconnecting in AppDelegate
    func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
        DropboxClientsManager.handleEventsForBackgroundURLSession(
            with: identifier,
            creationInfos: [],
            completionHandler: completionHandler,
            requestsToReconnect: { requestResults in
                processReconnect(requestResults: requestResults)
            }
        )
    }
  11. Install the Dropbox Swift SDK via CocoaPods

    master

    To use CocoaPods, first ensure CocoaPods is installed, then add SwiftyDropbox to your Podfile.

    If your project includes Objective-C code that needs access to the SDK, you must also add the SwiftyDropboxObjC pod to provide the Objective-C compatibility layer.

    After updating your Podfile, run pod install to install the dependencies.

    use_frameworks!
    
    target '<YOUR_PROJECT_NAME>' do
        pod 'SwiftyDropbox'
        # Add this if you need Objective-C compatibility:
        # pod 'SwiftyDropboxObjC'
    end
    # Install CocoaPods if not already installed
    $ gem install cocoapods
    
    # Install the SDK dependencies
    $ pod install
    
    # Update the SDK dependencies
    $ pod update