How to locally test Swift Package Manager components on Firefox iOS
This guide explains how to build and test Firefox iOS against a local Application Services checkout.
For background on our Swift Package approach, see the ADR.
At a glance
Goal: Build a local Firefox iOS against a local Application Services.
Current workflow (recommended):
- Build an XCFramework from your local
application-services
. - Point Firefox iOS’s local Swift package (
MozillaRustComponents/Package.swift
) at that artifact (either an HTTPS URL + checksum, or a localpath:
). - Reset package caches in Xcode and build Firefox iOS.
A legacy flow that uses the rust-components-swift
package is documented at the end while we're in mid-transition to the new system.
Prerequisites
- A local checkout of Firefox iOS that builds: https://github.com/mozilla-mobile/firefox-ios#building-the-code
- A local checkout of Application Services prepared for iOS builds: see Building for Firefox iOS
Step 1 — Build the XCFramework from Application Services
From your application-services
checkout:
cd megazords/ios-rust
./build-xcframework.sh
This produces MozillaRustComponents.xcframework.zip (and you can also unzip it to get MozillaRustComponents.xcframework) containing:
- The compiled Rust code as a static library (for all iOS targets)
- C headers and Swift module maps for the components
Tip: If you plan to use the URL-based approach below, compute the checksum once you have the zip:
swift package compute-checksum MozillaRustComponents.xcframework.zip
Step 2 — Point Firefox iOS to your local artifact
Firefox iOS consumes Application Services via a local Swift package in-repo at:
{path-to-firefox-ios}/MozillaRustComponents/Package.swift
update it in one of two ways:
Option A: URL + checksum (zip artifact)
- Host your MozillaRustComponents.xcframework.zip at an HTTPS-accessible URL (e.g., a Taskcluster or GitHub artifact URL).
- Edit MozillaRustComponents/Package.swift and set the binaryTarget to the zip URL and checksum:
// In firefox-ios/MozillaRustComponents/Package.swift
.binaryTarget(
name: "MozillaRustComponents",
url: "https://example.com/path/MozillaRustComponents.xcframework.zip",
checksum: "<sha256 from `swift package compute-checksum`>"
)
Note: Every time you produce a new zip, you must update the checksum.
Option B: Local path (fastest for iteration)
- Unzip the XCFramework near the package (or anywhere on disk).
- Switch the binaryTarget to a local path:
// In firefox-ios/MozillaRustComponents/Package.swift
.binaryTarget(
name: "MozillaRustComponents",
path: "./MozillaRustComponents.xcframework"
)
UniFFI bindings: If your component requires UniFFI-generated Swift, ensure the package targets reference the directory where generated Swift files are emitted (same pattern used in the repo’s Package.swift today).
Step 3 — Reset caches and build
In Xcode:
- File → Packages → Reset Package Caches
- (If needed) File → Packages → Update to Latest Package Versions
- Product → Clean Build Folder, then build and run Firefox iOS.
If you still see stale artifacts, delete:
~/Library/Caches/org.swift.swiftpm
~/Library/Developer/Xcode/DerivedData/*
…and build again.
Disabling local development
To revert quickly:
- Restore your changes to MozillaRustComponents/Package.swift (e.g., git checkout -- MozillaRustComponents/Package.swift).
- Reset Package Caches in Xcode.
- Build Firefox iOS.
Troubleshooting
- Old binary still in use: Reset caches and clear DerivedData, then rebuild.
- Branch switches in application-services: Rebuild the XCFramework and update the package reference (URL/checksum or path:).
- Checksum mismatch (URL mode): Run swift package compute-checksum on the new zip and update Package.swift.
- Build script issues: Re-run ./build-xcframework.sh from megazords/ios-rust.
Legacy: using rust-components-swift (remote package)
[!WARNING] Status: rust-components-swift is deprecated for Firefox iOS. Prefer the local package at MozillaRustComponents/ unless you must validate against the legacy package for a specific task.
Some teams may still need the legacy flow temporarily. Historically, Firefox iOS consumed Application Services through the rust-components-swift package. To test locally with that setup:
- Build the XCFramework from application-services.
- In a local checkout of rust-components-swift, point its Package.swift to the local path of the unzipped XCFramework:
.binaryTarget( name: "MozillaRustComponents", path: "./MozillaRustComponents.xcframework" )
- Commit the changes in rust-components-swift (Xcode only reads committed package content).
- In Firefox iOS, replace the package dependency with a local reference to your rust-components-swift checkout (e.g., via Xcode’s “Add Local…” in Package Dependencies).