Swift Package Manager distribution via prebuilt xcframework (iOS, macOS, Mac Catalyst, visionOS)#1486
Swift Package Manager distribution via prebuilt xcframework (iOS, macOS, Mac Catalyst, visionOS)#1486bmehta001 wants to merge 31 commits into
Conversation
First-pass scaffold to support Swift Package Manager on Apple platforms (the successor to CocoaPods, whose trunk goes read-only Dec 2 2026; there is no official in-repo podspec today). SPM cannot practically compile the C++ tree (CMake/Bond/sqlite/zlib/platform conditionals), so the compiled C++ core + Obj-C wrappers ship as a prebuilt MATTelemetry.xcframework (.binaryTarget) and the thin Swift layer (wrappers/swift/Sources/OneDSSwift) is compiled from source on top of the Obj-C module the xcframework vends. - Package.swift (root): binaryTarget (xcframework) + OneDSSwift source target; documents the path: -> url:+checksum: switch for releases. - tools/apple/build-xcframework.sh: per-slice static libmat.a via build-ios.sh (iOS device + simulator), lipo, then xcodebuild -create-xcframework; emits a zip + SPM checksum. - tools/apple/module.modulemap + MATTelemetry-umbrella.h: vend the `ObjCModule` Clang module the existing Swift sources already import. - tools/apple/README.md: approach, build/consume steps, release wiring, and the macOS-validation TODOs (macOS/Catalyst slices, conditional modules, header flattening, signing). NOT yet validated on macOS -- needs a mac with Xcode to run the build and adjust the static-lib path / header layout. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds .github/workflows/spm-release.yml: on a published 4-component release (vX.Y.Z.W), a macOS-runner job builds MATTelemetry.xcframework, uploads it to the Release, computes the SPM checksum, rewrites the Package.swift binaryTarget from path: to url:+checksum:, and pushes a 3-component SemVer tag (X.Y.Z) that Swift Package Manager can resolve (the SDK's own 4-component tags are not valid SemVer, so SPM ignores them). Also documents the parallel-tag consumption (`from: "3.10.161"`) and the release flow in tools/apple/README.md. Mirrors the vcpkg-release-bump pattern. NOT yet validated -- needs the prototype merged (so Package.swift exists at the release tag) and a macOS runner; the build script itself still needs a first run on a mac. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy objc_begin/end support headers into the flattened xcframework Headers directory and mirror the existing Swift wrapper optional-module source exclusions in the root package manifest. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Avoid vending private wrapper headers from the flattened MATTelemetry.xcframework Headers directory, which otherwise triggers incomplete umbrella warnings when ObjCModule is imported. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR prototypes distributing the 1DS C++ SDK to Apple developers via Swift Package Manager by shipping the C++ core + Obj-C wrappers as a prebuilt MATTelemetry.xcframework binary target, with the Swift wrapper layer (OneDSSwift) compiled from source on top.
Changes:
- Add a distributable root
Package.swiftusing an SPMbinaryTargetplus the existing Swift sources. - Add Apple tooling to build and package
MATTelemetry.xcframework(modulemap + umbrella header + build script). - Add a GitHub Actions workflow to build/upload the xcframework on release and publish an SPM-resolvable SemVer tag.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
Package.swift |
New root SPM manifest for distributing OneDSSwift backed by a binary xcframework. |
tools/apple/build-xcframework.sh |
Script to build per-slice libmat.a, assemble an xcframework, zip it, and compute SPM checksum. |
tools/apple/module.modulemap |
Declares the ObjCModule Clang module for Swift to import from the xcframework. |
tools/apple/MATTelemetry-umbrella.h |
Umbrella header listing Obj-C wrapper headers to export via the modulemap. |
tools/apple/README.md |
Documentation of the approach, local build steps, and release wiring/TODOs. |
.github/workflows/spm-release.yml |
Release automation: build xcframework, upload to Release, rewrite manifest to url+checksum, and tag for SPM. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Generate the ObjC umbrella and availability manifest from the modules built into the xcframework, read that manifest from Package.swift, and guard Swift type aliases for optional modules. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Drive Swift source exclusions and ObjC umbrella optional imports from the modules actually built into MATTelemetry.xcframework, remove unsupported macOS package advertising, and add Apple system linker settings for the static binary target. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove macOS package advertising until a macOS slice exists, add iOS linker settings for the static xcframework, and avoid repeating build tool setup for each slice. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mark the prototype as validated, document remaining gaps, and make optional module availability respect explicit BUILD_PRIVACYGUARD/BUILD_SANITIZER settings passed through CMAKE_OPTS. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Copilot round addressed (head
Re-requested |
Build a universal macOS libmat archive alongside the iOS device and simulator slices, advertise macOS in the root Swift package, and document the expanded validation story. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Teach the Apple build path to produce macabi archives, include a fat Catalyst variant in MATTelemetry.xcframework, advertise Mac Catalyst in the Swift package, and document the expanded validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Obj-C wrapper module vended by MATTelemetry.xcframework (and the local wrappers/swift package) was named `ObjCModule` -- a generic name that consumers `import`. Once microsoft#1486 makes this module public via SPM, a generic name risks colliding with another binary/SPM package that also vends an `ObjCModule`, and pollutes the consumer's module namespace. Rename it to the namespaced `MATTelemetryObjC` while the name is still internal (the wrappers/swift package was never distributed), so it is collision-safe before first release. Renamed consistently across both build paths so the same Swift sources compile against both modulemaps: - tools/apple/module.modulemap (xcframework) and wrappers/swift/Modules/module.modulemap (local): `module MATTelemetryObjC`. - All 13 `import ObjCModule` -> `import MATTelemetryObjC` in wrappers/swift/Sources/OneDSSwift/*.swift. - Bridging header file renamed ObjCModule-Bridging-Header.h -> MATTelemetryObjC-Bridging-Header.h and its modulemap reference updated. - Comments/docs (Package.swift, build-xcframework.sh, tools/apple/README.md, examples/swift/README.md) updated. Pure rename; no behavioral change. Needs a macOS `swift build` (local wrappers path) + xcframework SPM build to confirm both paths still resolve the module -- I cannot run those on Windows. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The SPM xcframework links the platform's libsqlite3/libz (Package.swift .linkedLibrary) rather than bundling them. Document why: bundling a private static sqlite3 would collide with any consumer that also uses SQLite (Core Data/GRDB/FMDB) -> duplicate symbols / two-instance state; system linking yields one shared copy. Notes the contrast with vcpkg (uses vcpkg packages) and Android (bundles, since the NDK has no system copy). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Every other PII-tagged public API in OneDSSwift (EventProperties, Logger, LogManager) already uses the `PIIKind` typealias; only SemanticContext.setUserID exposed the raw Obj-C `ODWPiiKind` in its signature/default. Switch it to `PIIKind` (same underlying type via the ObjCTypes.swift typealias) so consumers of the Swift API never need to reference the MATTelemetryObjC module name. Pure source-level alias swap; no behavioral change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
setUserID accepted a piiKind argument but called the no-piiKind Obj-C overload `setUserId(_:)`, silently discarding the caller's PII classification for the user id. ODWSemanticContext exposes a `setUserId:piiKind:` overload (wrappers/obj-c/ODWSemanticContext.h:47-48) for exactly this. Route the argument through so the requested PII tag is actually applied. Privacy-relevant behavioral fix. Needs a macOS `swift build` to confirm the bridged selector (`setUserId(_:piiKind:)`); cannot run Swift on the Windows session. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep CommonDataContext available without PrivacyGuard, tighten Swift docs, and scope xcframework slice cleanup to the output directory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ber published artifacts Two robustness fixes to the Apple/SPM distribution path: - build-ios.sh ran cmake, make, and make package without checking their exit codes. Under MATTELEMETRY_SKIP_PACKAGE=1 (used by the xcframework build) a failed `make` was masked -- the script printed "skipping package creation" and exited 0, so build-xcframework.sh would proceed with a broken/empty slice. Propagate failures explicitly for cd, cmake, make, and make package. - spm-release.yml uploaded the xcframework with `gh release upload --clobber` and updated Package.swift on every run, gated only on the tag being a valid 4-component version. A re-run for an already-published release replaced the release asset with a differently-hashed rebuild while the existing SPM tag kept the old checksum, breaking consumers pinned to it (SPM binary targets verify the checksum). Add an early "already published" check and gate the checksum/upload/manifest/commit steps on it, so a published SPM version's artifact and checksum are left untouched. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 24 out of 25 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
wrappers/swift/Package.swift:31
wrappers/swift/Package.swiftdetermineshasPrivacyGuard/hasSanitizerpurely fromlib/modules/...directory presence. However the build supports disabling these modules via-DBUILD_PRIVACYGUARD=OFF/-DBUILD_SANITIZER=OFF(see top-level CMake options). In that case this manifest will still includePrivacyGuard*.swift/Sanitizer*.swiftand defineMATSDK_PRIVACYGUARD_AVAILABLE, which can lead to Swift compile/link errors against alibmat.abuilt without those modules. Consider also honoring the effective CMake options (e.g., by parsingCMAKE_OPTSwhen present) so source exclusions match the binary actually built.
if hasPrivacyGuard {
swiftSettings.append(.define("MATSDK_PRIVACYGUARD_AVAILABLE"))
} else {
excludedSources.append(contentsOf: [
"PrivacyGuard.swift",
"PrivacyGuardInitConfig.swift",
])
}
…rminate The published-tag check used `git ls-remote --exit-code` and treated any non-zero exit as "not published", conflating "connected, no such tag" (exit 2) with a transport/auth error (exit 128+). A transient failure would set published=false and ungate the `gh release upload --clobber`, replacing an already-published asset with a differently-hashed rebuild while the existing SPM tag kept the old checksum -- the exact breakage this gate prevents. Branch on the exit status: existing tag -> skip, no match -> publish, any other error -> abort the job. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When the SPM xcframework includes visionOS slices, the mobile Apple sysinfo implementation should not report those runs as iOS or leave the device class empty. Teach the iOS/visionOS sysinfo path to return visionOS-specific OS and class values when compiled for visionOS, while preserving the existing iOS values for iOS and iOS Simulator. Also document the current SPM release-tag mapping: one SDK build can publish for each three-component SemVer tag because vX.Y.Z.W maps to X.Y.Z. Validation: - swift package dump-package - iOS/visionOS device and simulator Objective-C++ syntax checks - tools/apple/build-xcframework.sh release - swift build - xcodebuild iOS simulator, visionOS simulator, and Mac Catalyst package builds - git diff --check Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Swift Package Manager distribution via prebuilt xcframework
Adds Swift Package Manager (SPM) support so Apple app developers can consume the 1DS C++ SDK. SPM is the successor to CocoaPods (whose trunk goes read-only on 2 Dec 2026), and the repo has no official in-repo podspec today; the pre-existing
wrappers/swift/Package.swiftwas a local-build skeleton rather than a distributable package.Approach
SPM cannot practically compile this C++ tree from source (CMake build, Bond codegen, vendored sqlite3/zlib, heavy platform conditionals), so:
MATTelemetry.xcframework(.binaryTarget). The Obj-C wrappers compile intolibmat.aon Apple.wrappers/swift/Sources/OneDSSwift) is compiled from source on top of theObjCModuleClang module vended by the xcframework.Platforms
Package.swiftadvertises iOS 12, Mac Catalyst 14, macOS 10.15, and visionOS 1. The xcframework bundles six library slices:ios-arm64(device)ios-simulatormacos-universalmaccatalystvisionos-arm64(device)visionos-simulatorFramework links are gated per platform:
IOKitis macOS-only;UIKitis iOS / Mac Catalyst / visionOS;CFNetwork/CoreFoundation/Foundation/Network/SystemConfigurationspan all four.What's here
Package.swift— distributable SPM manifest:binaryTargetxcframework +OneDSSwiftsource target, with per-platform linker settings and source exclusions driven by the availability manifest.tools/apple/build-xcframework.sh— builds staticlibmat.aslices viabuild-ios.sh, fattens simulator / Catalyst / macOS archs withlipo, and assemblesMATTelemetry.xcframeworkwithxcodebuild -create-xcframework. Forces-DBUILD_SHARED_LIBS=OFF -DBUILD_OBJC_WRAPPER=YES, appended after callerCMAKE_OPTS.build-ios.sh— gained aMATTELEMETRY_SKIP_PACKAGE=1opt-out so per-slice xcframework builds skip the expensivemake packagestep, plus an explicit error for unsupported Apple platform names.tools/apple/module.modulemap+MATTelemetry-umbrella.h— vend theObjCModuleClang module; optional-module imports (e.g.ODWPrivacyGuard.h) are appended only when those modules are actually built into the binary.tools/apple/MATTelemetryAvailability.json— generated by the xcframework build from both module-directory presence and the effective-DBUILD_PRIVACYGUARD/-DBUILD_SANITIZER, then read byPackage.swiftso Swift source exclusions match the binary. Only copied back into the repo under CI or explicit opt-in (MATTELEMETRY_UPDATE_PACKAGE_AVAILABILITY=1), so local builds don't dirty the tree..github/workflows/spm-release.yml— on a publishedvX.Y.Z.Wrelease: build the xcframework on a macOS runner, upload it to the Release, pin thebinaryTargeturl:+checksum:, validate the declared Apple platforms viaswift package dump-package, and push a 3-component SemVer tag (X.Y.Z) that SPM can resolve. The tag step is idempotent — it skips if the SemVer tag already exists.tools/apple/README.md— approach, build / consume, release wiring, and remaining TODOs.Validation performed on macOS
tools/apple/build-xcframework.sh releasesucceeded and produced all six slices (ios-arm64,ios-arm64_x86_64-simulator,macos-arm64_x86_64, Mac Catalyst, visionOS device + simulator).swift buildsucceeded for macOS host consumption.xcodebuild -scheme OneDSSwift -destination 'generic/platform=iOS Simulator' buildsucceeded.swift package dump-packagereports all four platforms (iOS, Mac Catalyst, macOS, visionOS).Consume after a release
Remaining TODOs
Package.swiftlives long-term, since it makes the repository an SPM package.Companion to the official vcpkg port (for C++ consumers): SPM serves Apple app developers, and the two are complementary.