WWDC Quick Look 💓 By SwiftGGTeam
Distribute binary frameworks as Swift packages

Distribute binary frameworks as Swift packages

Watch original video

Highlight

Xcode 12 makes Swift Package Manager available via.binaryTargetDistribute precompiled.xcframework, the user declares dependencies just like adding a source code package, and the publisher uses HTTPS URL and checksum to verify the downloaded binary file.

Core Content

Before Xcode 11, Swift Package Manager mainly solved source code library distribution. Open source libraries can put the source code into packages, and users add dependencies in Xcode, and version updates and builds are handled by the tool chain. The experience of closed-source SDK is different: the author usually only delivers the compiled framework, and the user has to manually download it, drag it into the project, process the platform slices, and confirm whether the version matches.

The XCFramework introduced in Xcode 11 solves the binary format problem. An XCFramework can combine frameworks or libraries from different platforms and target environments, and each subdirectory corresponds to a target triple. It is suitable for distributing closed source libraries, but has not yet entered the dependency resolution process of Swift packages.

Xcode 12 connect these two lines. Swift tools version 5.3 NewbinaryTarget, the package author can find thePackage.swiftDeclare a precompiled XCFramework here. The user still adds the warehouse and version through File > Swift Packages > Add Package Dependency. Xcode will download the binary product, verify the checksum, and then expose the module to the App code.

This session focuses on incorporating closed source frameworks into the Swift package distribution model. What the author gets is a release agreement consisting of warehouse, version constraints, HTTPS artifacts and checksums; what the user gets is an integration entry that is basically the same as the source code package.

Detailed Content

Use binary package dependencies

(01:01) The speech starts from the user side. Developers select File > Swift Packages > Add Package Dependency in Xcode, select version 1.0 of the BinaryEmoji package, and then link the binary dependency to the App. The Referenced Binaries group will appear in the project navigation, which contains an XCFramework.

(02:37) The same dependency can also be written in the package manifest. The official code snippet shows how to write a normal package dependency:

// swift-tools-version:5.3

import PackageDescription

let package = Package(
    name: "package",
    products: [
        .library(
            name: "package",
            targets: ["package"]),
    ],
    dependencies: [
        .package(url: "https://github.com/JohnnyAppleseed2020/BinaryEmoji", from: "1.0.0"),
    ],
    targets: [
        .target(
            name: "package",
            dependencies: ["Emoji"]),
    ]
)

Key points:

  • // swift-tools-version:5.3Indicates that this manifest uses the SwiftPM capabilities corresponding to Xcode 12. -.package(url:from:)Point to the package repository that distributes this binary framework and set the minimum version. -.target(... dependencies: ["Emoji"])Make the current target importableEmojimodule.
  • The user cannot see the source code of the binary framework, but the entry points for importing modules, jump definitions, and refreshing SwiftUI preview are the same as for source code packages.

Distribute XCFramework with binaryTarget

(03:04) The key API on the author side is the new target typebinaryTarget. Its name corresponds to the module name of XCFramework, and HTTPS URL and checksum are required for remote distribution.

// swift-tools-version:5.3

import PackageDescription

let package = Package(
    name: "Emoji",
    products: [
        .library(name: "Emoji", targets: ["Emoji"])
    ],
    dependencies: [
    ],
    targets: [
        .binaryTarget(
            name: "Emoji",
            url: "https://example.com/Emoji/Emoji-1.0.0.xcframework.zip",
            checksum: "6d988a1a27418674b4d7c31732f6d60e60734ceb11a0ce9b54d1871918d9c194"
        )
    ]
)

Key points:

  • .library(name:targets:)BundleEmojiThe target is exposed to clients as a package product. -.binaryTarget(name:url:checksum:)Declare this target to come from a minified XCFramework. -urlIt must be HTTPS, and the download action will be independent of Git checkout to avoid writing large binary files into the warehouse history. -checksumIt is the integrity constraint of the manifest. Xcode will recalculate and compare it after downloading the artifact.
  • The verbatim also mentions path-based binary target, which is used during the development phase and can point to XCFramework files within the package.

checksum is part of the publishing agreement

(05:43) The checksum is calculated by the SwiftPM command. The author first zipped XCFramework and then ran the command on this zip:

swift package compute-checksum Emoji-1.0.0.xcframework.zip

Key points:

  • The value output by the command is copied toPackage.swiftofchecksumfield.
  • When the client uses package, Xcode will recalculate the checksum of the downloaded file.
  • When the checksum does not match, Xcode will reject the download result to prevent the client from getting a binary file that is inconsistent with the manifest.
  • The version number in the artifact file name should match the package release rhythm. The verbatim draft recommends that the binary target also comply with semantic versioning.

XCFramework is still the underlying format

06:16binaryTargetDistributed is XCFramework. The verbatim draft emphasizes that XCFramework can contain multiple platform variants, supports framework, dynamic library and static library, and each XCFramework only contains one module.

The process of creating XCFramework is only summarized here: open Build Libraries for Distribution on the framework or library target, archive each variant separately, and then usexcodebuild -create-xcframeworkmerge. The speaker pointed to WWDC 2019’s “Binary Frameworks in Swift” for more complete creation and version evolution details.

(07:00) The final choice is also very practical. Binary dependencies make debugging more difficult. Users cannot directly modify the source code, and can only use platforms already supported by the author. After putting the closed-source SDK into the Swift package, dependency management is smoother, but the responsibility for evaluating third-party components does not disappear.

Core Takeaways

  • What: Transform the closed source SDK into a Swift package for distribution. Why it’s worth doing: Xcode 12 support.binaryTarget, users can obtain precompiled XCFramework through package dependency. How ​​to start: First prepare a package warehouse that is only responsible for distribution.Package.swiftStatement in.libraryproducts and.binaryTarget(name:url:checksum:)

  • What: Release private binary components for internal teams. Why it’s worth doing: HTTPS artifacts will be downloaded outside of Git checkout, and large files will not pollute the package repository history. How ​​to start: Put the zipped XCFramework into an HTTPS address accessible to the company, calculate the checksum, and match the package tag with the artifact version.

  • What to do: Establish upgrade rules for the binary SDK. Why it’s worth doing: The verbatim draft explicitly recommends that binary targets follow semantic versioning just like source targets, and that destructive API changes have to raise their major version. How ​​to get started: Put public API changes, XCFramework bundle version and package tag into the same release checklist.

  • What: Add integration acceptance to binary dependencies. Why it’s worth doing: Users cannot modify the binary source code, and problems are more suitable to be discovered in advance at the access boundary. How ​​to start: Create a new sample App or test package, add package dependency according to the client path, and verifyimport, main API calls and whether the target platform is available.

Comments

GitHub Issues · utterances