Skip to content

feat: build kit xcframeworks from SPM packages instead of Xcode projects#729

Open
thomson-t wants to merge 2 commits intomainfrom
feat/spm-kit-xcframework
Open

feat: build kit xcframeworks from SPM packages instead of Xcode projects#729
thomson-t wants to merge 2 commits intomainfrom
feat/spm-kit-xcframework

Conversation

@thomson-t
Copy link
Copy Markdown
Contributor

Summary

  • Remove all 29 kit-level .xcodeproj directories and 5 tvOS-specific header directories (mParticle-*-tvOS/), replacing the xcodeproj-based xcframework build with Scripts/build_kit_xcframework.sh that archives directly from each kit's Package.swift using xcodebuild -skipPackagePluginValidation
  • Simplify Kits/matrix.json from separate per-platform schemes to a single scheme + module + platforms[] per kit
  • Update release-publish.yml and build-kits.yml workflows to use the new SPM-based build approach

Motivation

Kit .xcodeproj files were only used to generate xcframeworks during release. Every kit already has a Package.swift that defines the same targets and dependencies. By building directly from SPM, we:

  • Eliminate ~16,000 lines of generated Xcode project files
  • Remove the need to maintain separate tvOS Xcode schemes (SPM handles multi-platform with a single scheme)
  • Align the xcframework build with how consumers actually integrate kits (via SPM)

Key changes

New: Scripts/build_kit_xcframework.sh

Reusable script that builds an xcframework from an SPM package for one or more platforms. Handles:

  • xcodebuild archive with -skipPackagePluginValidation (no .xcodeproj needed)
  • Post-processing to copy public headers and generate module.modulemap into framework bundles
  • Multi-platform builds (iOS + tvOS) from a single SPM scheme
  • Sets BUILD_XCFRAMEWORK=1 to signal Package.swift to use dynamic library type

Updated: Kits/matrix.json

Simplified from:

"schemes": [
  {"scheme": "mParticle-Braze", "module": "mParticle_Braze", "destination": "iOS"},
  {"scheme": "mParticle-Braze-tvOS", "module": "mParticle_Braze", "destination": "tvOS"}
]

To:

"scheme": "mParticle-Braze",
"module": "mParticle_Braze",
"platforms": ["iOS", "tvOS"]

Updated: 29 kit Package.swift files

  • Added BUILD_XCFRAMEWORK env var to conditionally set .dynamic library type (required for framework output from SPM)
  • Added explicit name: "mparticle-apple-sdk" on local path dependency for SPM identity resolution
  • No changes to remote dependency resolution or public API

Deleted

  • 29 kit .xcodeproj directories (project files + shared schemes)
  • 5 mParticle-*-tvOS/ directories from Braze (3) and Kochava (2) kits — only contained tvOS headers/plists used by the Xcode project's tvOS target

Test plan

  • Verify Scripts/build_kit_xcframework.sh produces valid xcframeworks for an iOS-only kit (e.g., Adjust) and a multi-platform kit (e.g., Braze)
  • Trigger Release – Publish workflow with dry_run: true to validate the full CI pipeline
  • Verify Build Kits CI workflow passes for all 29 kits
  • Confirm xcframework zip contents include headers, module maps, and dSYMs
  • Verify SPM consumers can still resolve kit packages (no public API change)

Remove kit-level .xcodeproj files and tvOS-specific directories, replacing
the xcodeproj-based xcframework build with a script that archives directly
from each kit's Package.swift using xcodebuild -skipPackagePluginValidation.

- Add Scripts/build_kit_xcframework.sh for SPM-based xcframework generation
- Simplify Kits/matrix.json to scheme + module + platforms[] per kit
- Update release-publish.yml and build-kits.yml to use the new format
- Update all 29 kit Package.swift files with BUILD_XCFRAMEWORK dynamic type
  and explicit package identity for local path dependencies
- Delete 29 kit .xcodeproj directories and 5 tvOS header directories
- Update KIT_XCFRAMEWORK_RELEASE_WORKFLOW.md to document the new approach
@thomson-t thomson-t requested a review from a team as a code owner April 8, 2026 20:14
@cursor
Copy link
Copy Markdown

cursor bot commented Apr 8, 2026

PR Summary

Medium Risk
Changes the kit release build pipeline and artifact generation (xcframework archiving, header/modulemap packaging), which could break kit publishing if schemes/platform metadata are wrong. No runtime SDK logic changes, but CI/release failures would block releases.

Overview
Kit XCFramework generation is switched from Xcode projects to SPM-based builds. GitHub Actions workflows now build/test kits by running xcodebuild directly against each kit’s Package.swift (with -skipPackagePluginValidation) and iterating over platforms per kit.

Release publishing now delegates xcframework creation to a new reusable script, Scripts/build_kit_xcframework.sh, which archives device+simulator slices per platform, injects public headers and a generated module.modulemap, then creates and zips the xcframework.

Kit metadata is simplified in Kits/matrix.json (single scheme/module plus platforms[], with optional per-kit xcode_version), and kit Package.swift files are updated to support xcframework output (BUILD_XCFRAMEWORK.dynamic) and to name the local core SDK dependency explicitly. Large generated kit .xcodeproj files (and some tvOS-only project header/plist folders) are removed, and a KIT_XCFRAMEWORK_RELEASE_WORKFLOW.md doc is added to describe the new flow.

Reviewed by Cursor Bugbot for commit a2f4b2a. Bugbot is set up for automated code reviews on this repo. Configure here.

# Conflicts:
#	Kits/google-analytics-firebase-ga4/firebase-ga4-11/mParticle-FirebaseGA4.xcodeproj/project.pbxproj
#	Kits/google-analytics-firebase-ga4/firebase-ga4-12/mParticle-FirebaseGA4.xcodeproj/project.pbxproj
#	Kits/google-analytics-firebase/firebase-11/mParticle-Firebase.xcodeproj/project.pbxproj
#	Kits/google-analytics-firebase/firebase-12/mParticle-Firebase.xcodeproj/project.pbxproj
#	Kits/urbanairship/urbanairship-19/mParticle-UrbanAirship.xcodeproj/project.pbxproj
#	Kits/urbanairship/urbanairship-20/mParticle-UrbanAirship.xcodeproj/project.pbxproj
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 8, 2026

📦 SDK Size Impact Report

Measures how much the SDK adds to an app's size (with-SDK minus without-SDK).

Metric Target Branch This PR Change
App Bundle Impact 1.75 MB 1.75 MB +N/A
Executable Impact 848 bytes 848 bytes +N/A
XCFramework Size 6.38 MB 6.38 MB +N/A

➡️ SDK size impact change is minimal.

Raw measurements

Target branch (main):

{"baseline_app_size_kb":84,"baseline_executable_size_bytes":75464,"with_sdk_app_size_kb":1880,"with_sdk_executable_size_bytes":76312,"sdk_impact_kb":1796,"sdk_executable_impact_bytes":848,"xcframework_size_kb":6532}

This PR:

{"baseline_app_size_kb":84,"baseline_executable_size_bytes":75464,"with_sdk_app_size_kb":1880,"with_sdk_executable_size_bytes":76312,"sdk_impact_kb":1796,"sdk_executable_impact_bytes":848,"xcframework_size_kb":6532}

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a2f4b2a. Configure here.

HEADERS_DIR="Sources/${SCHEME}/include"

XCFRAMEWORK_ARGS=""
FRAMEWORK_NAME="${SCHEME}.framework"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Wrong framework name: uses SCHEME instead of MODULE

High Severity

FRAMEWORK_NAME is set to "${SCHEME}.framework" (e.g., mParticle-Braze.framework) but xcodebuild archive from an SPM package produces framework bundles using the c99 extended identifier form with underscores (e.g., mParticle_Braze.framework). The existing Scripts/xcframework.sh and the deleted old workflow code both correctly use $MODULE.framework for the -framework argument. This mismatch causes the header/modulemap post-processing to silently skip (the -d check fails) and xcodebuild -create-xcframework to fail because it can't find the framework. Affects all 29 kits.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a2f4b2a. Configure here.

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.

1 participant