Skip to content

build: Add XCFramework binary distribution support#266

Open
cameroncooke wants to merge 1 commit into
mainfrom
cameroncooke/eme-1168-xcframework-binary-distribution
Open

build: Add XCFramework binary distribution support#266
cameroncooke wants to merge 1 commit into
mainfrom
cameroncooke/eme-1168-xcframework-binary-distribution

Conversation

@cameroncooke
Copy link
Copy Markdown
Contributor

Adds XCFramework binary distribution support for SnapshotPreviews while keeping the standard Swift Package integration source-first.

The release build now produces the full manually consumable framework set under XCFrameworks/, packages those artifacts for GitHub releases, and includes a separate example project that integrates the generated frameworks without Swift Package Manager.

Swift Package vs binary distribution

Package.swift remains the public source-package manifest. SwiftPM is allowed to choose linkage for regular products, while Snapshotting stays explicitly dynamic because it is the inserted/runtime dylib product.

XCFrameworkPackage.swift is a build-only manifest used by build.sh. It forces the currently built product to dynamic for binary packaging and wires already-built SnapshotPreviews dependencies back in as binary targets, so shared support modules are dynamically linked instead of being repeatedly embedded into parent frameworks.

Vended artifact layout

Generated binary artifacts are written to XCFrameworks/:

  • SnapshotSharedModels.xcframework
  • SnapshotPreviewsCore.xcframework
  • SnapshotPreferences.xcframework
  • PreviewGallery.xcframework
  • SnapshottingTests.xcframework
  • Snapshotting.xcframework
  • PreviewsSupport.xcframework

PreviewsSupport remains checked in at PreviewsSupport/PreviewsSupport.xcframework for SwiftPM usage. The distribution build copies it into XCFrameworks/ so binary consumers and release assets use one artifact folder.

Dynamic dependency model

Manual XCFramework integration does not get SwiftPM dependency resolution automatically, so consumers must link and embed the documented framework closure for each target.

The generated frameworks keep shared SnapshotPreviews dependencies as dynamic framework dependencies. This avoids duplicating shared support modules across frameworks when multiple SnapshotPreviews products are loaded in the same process.

Binary example project

Examples/DemoApp remains the normal local Swift Package example.

Examples/DemoApp-XCFrameworks is the manual binary integration example. It shares source files from ../DemoApp/..., links against ../../XCFrameworks/*.xcframework, and includes a small wrapper script:

cd Examples/DemoApp-XCFrameworks
./generate-xcframeworks.sh
open DemoApp-XCFrameworks.xcodeproj

Shared demo source that depends on optional external packages uses canImport, so the Swift Package example can keep accessibility snapshot rendering while the XCFramework example builds without that external package.

Manual integration matrix

For an app target using per-preview rendering preferences:

  • SnapshotPreferences.xcframework
  • SnapshotSharedModels.xcframework

For an app target using the gallery UI:

  • PreviewGallery.xcframework
  • SnapshotPreviewsCore.xcframework
  • SnapshotPreferences.xcframework
  • SnapshotSharedModels.xcframework
  • PreviewsSupport.xcframework

For an XCTest snapshot/layout target:

  • SnapshottingTests.xcframework
  • SnapshotPreviewsCore.xcframework
  • SnapshotSharedModels.xcframework
  • PreviewsSupport.xcframework

For the inserted-dylib/accessibility runtime flow, also include:

  • Snapshotting.xcframework

Refs EME-1168

Generate the vendored SnapshotPreviews frameworks with a Bash-based Xcode archive flow and a build-only package manifest that forces dynamic products for packaging.

Add a binary-framework DemoApp example, document the manual integration requirements, and update release packaging to publish the generated XCFramework artifacts from the XCFrameworks directory.

Co-Authored-By: Codex <noreply@openai.com>
@linear-code
Copy link
Copy Markdown

linear-code Bot commented Jun 4, 2026

EME-1168

Copy link
Copy Markdown
Contributor

@NicoHinderling NicoHinderling left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hopefully @noahsmartin can take a look as well

run: bash build.sh
- name: Zip xcframeworks
run: |
rm -f *.xcframework.zip
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why deleting?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix that. Bit pointless as the runner will be torn down.

Copy link
Copy Markdown
Member

@jamieQ jamieQ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable to me!

Comment thread build.sh
"iphonesimulator|generic/platform=iOS Simulator"
"macosx|generic/platform=macOS"
"watchos|generic/platform=watchOS"
"watchsimulator|generic/platform=watchOS Simulator"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How did we come up with this set of platforms? Should "visionos", "tvos", etc be in there?

Comment thread build.sh
sanitize_swift_interfaces "$modules_path" "$framework"
}

sanitize_swift_interfaces() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motiviation for this logic? Seems it's not new, but just curious

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants