Blog Post

Download Failures with Swift Package Manager Binary Targets

Illustration: Download Failures with Swift Package Manager Binary Targets

Our iOS PDF SDK has supported Swift Package Manager since PSPDFKit 10 was released. This occurred alongside the introduction of support for binary (precompiled) frameworks in packages in Xcode 12.0. Swift Package Manager is a fabulously convenient way to add PSPDFKit’s advanced PDF functionality to any app. However, since around the release of Xcode 13.0 (and tested up until Xcode 14.0 beta 1 at the time of writing), we observed that when first cloning or downloading our Catalog and Minimal sample projects, the following error would show up in Xcode:

failed downloading ‘https://my.pspdfkit.com/pspdfkit/xcframework/11.3.1.zip’ which is required by binary target ‘PSPDFKit’: ~/Library/Developer/Xcode/DerivedData/Minimal-enhpcflwoobkdifztstuqbqotegx/SourcePackages/artifacts/pspdfkit-sp/11.3.1.zip already exists in file system

At first, I basically read this error message as “failed downloading PSPDFKit, some long path, blah blah”.

To fix this issue, we found you just need to select File > Packages > Reset Package Caches at any point after opening the Xcode project, and then the download would work. Adding the packages from scratch also worked reliably. Since downloading the package sometimes worked and sometimes didn’t, we were fairly certain this was a bug in Swift Package Manager, and we thought we couldn’t do anything about it.

And so this problem remained for months — and it was a really awful first experience with PSPDFKit for our customers. We documented the requirement to reset package caches, but of course, iOS developers commonly expect that you can just open and run an Xcode project without additional steps.

We considered other options, such as if our sample projects didn’t have the Swift package dependencies already configured, and we documented how to add these. This workaround would be more time-consuming for people trying out PSPDFKit, but at least the process would work reliably.

New Information

Recently, I was in the process of documenting this limitation more thoroughly when I noticed a slightly different error in Xcode:

failed downloading ‘https://my.pspdfkit.com/pspdfkitui/xcframework/11.3.1.zip’ which is required by binary target ‘PSPDFKitUI’: ~/Library/Developer/Xcode/DerivedData/Minimal-enhpcflwoobkdifztstuqbqotegx/SourcePackages/artifacts/pspdfkit-sp/11.3.1.zip already exists in file system

What caught my eye was that this said PSPDFKitUI. Note the UI part at the end.

For some background information, we separate our core PSPDFKit for iOS product into two frameworks: PSPDFKit, for model operations like document parsing and rendering; and PSPDFKitUI, which provides ready-to-use UI components for SwiftUI and UIKit. This means customers who only need model-level processing operations don’t need to add our UI framework to their app at all, and even when using both, files only working with the data don’t need to import the UI module.

Therefore, our PSPDFKit-SP package has two binary targets. This was our Package.swift file:

let package = Package(
    name: "PSPDFKit",
    products: [
        .library(
            name: "PSPDFKit",
            targets: ["PSPDFKit", "PSPDFKitUI"]),
    ],
    targets: [
        .binaryTarget(
            name: "PSPDFKit",
            url: "https://my.pspdfkit.com/pspdfkit/xcframework/11.3.1.zip",
            checksum: "8b72c61db0497111cb5e94af2269c8e8a5a7b5935f5600d87264e1df266f0144"),
        .binaryTarget(
            name: "PSPDFKitUI",
            url: "https://my.pspdfkit.com/pspdfkitui/xcframework/11.3.1.zip",
            checksum: "d2ba1b1a01ac5a4cb36610200f8e13e671d8608608a6dcde46721e9b0ab04ab1"),
    ]
)

Looking back at the two error messages, we can see that despite these messages being for PSPDFKit and PSPDFKitUI respectively, the file system path is the same in both cases. Inside the derived data directory, the path is:

SourcePackages/artifacts/pspdfkit-sp/11.3.1.zip

And that looks like the bug. When first opening a project with Swift package dependencies already configured, Swift Package Manager tries to download all the binary targets of each package into a path determined only by the package name and the last path component of the URL of the binary. Since both our URLs ended with 11.3.1.zip, the second download to complete would find a file already existed at the target file system location. This issue has been reported to Apple as FB10471859.

Note that we suggest unique file names in the HTTP headers, but Swift Package Manager seems to ignore these.

A Simple Solution

With this knowledge, an obvious workaround would be to serve the binary files with distinct last path components in the URLs. So we set up an additional route on the server side, tested it, and boom: Downloading PSPDFKit after opening the Xcode project just worked. We’re back to the smooth first experience we had with Xcode 12.

We’ve now updated our PSPDFKit Swift Package repository to fix this issue when using PSPDFKit for iOS version 11.3.2 or later. (We could fix this for older versions too if we rewrote the Git history of our Swift Package repository and re-pushed all its tags, but this seems like a drastic step to take.)

Takeaways

The specific point to remember is that when setting up a Swift package with binary targets, ensure the URLs have distinct last path components. Of course, the more general lesson is to read error messages very carefully for clues! Now that our PDF SDK is working correctly with Swift Package Manager, the tight integration between Xcode and Swift Package Manager is so, so nice. You can see it working right now in our Catalog sample app.

Related Products
Share Post
Free 60-Day Trial Try PSPDFKit in your app today.
Free Trial

Related Articles

Explore more
PRODUCTS  |  iOS • Releases

PSPDFKit 13.4 for iOS Introduces Revamped API Documentation and Improves Multiple Annotation Selection

DEVELOPMENT  |  visionOS • iOS

Apple’s Vision of Our Digital Future

PRODUCTS  |  iOS • visionOS • Mac Catalyst • Releases

PSPDFKit 13.3 for iOS Adds Long-Term Validation for Digital Signatures