Revision control
Copy as Markdown
# 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](../adr/0003-swift-packaging.md).
---
## At a glance
**Goal:** Build a local Firefox iOS against a local Application Services.
**Current workflow (recommended):**
1. Build an **XCFramework** from your local `application-services`.
2. Point **Firefox iOS’s local Swift package** (`MozillaRustComponents/Package.swift`) at that artifact (either an HTTPS URL + checksum, **or** a local `path:`).
3. Update UniFFI generated swift source files.
3. 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
1. A local checkout of **Firefox iOS** that builds: <https://github.com/mozilla-mobile/firefox-ios#building-the-code>
2. A local checkout of **Application Services** prepared for iOS builds: see [Building for Firefox iOS](../building.md#building-for-firefox-ios)
---
## Step 1 — Build all artifacts needed from Application Services.
This step builds an XCFramework and also generates swift sources for the components with UniFFI.
From the root of your `application-services` checkout, execute:
```bash
./automation/build_ios_artifacts.sh
```
This produces:
- `megazords/ios-rust/MozillaRustComponents.xcframework`, containing:
- The compiled Rust code as a static library (for all iOS targets)
- C headers and Swift module maps for the components
- `megazords/ios-rust/MozillaRustComponents.xcframework.zip`, which is a zip
of the above directory. By default, firefox-ios consumes the .zip file, although
as we discuss below, we will change firefox-ios to use the directory itself.
- `megazords/ios-rust/Sources/MozillaRustComponentsWrapper/Generated/*.swift`, which are
the source files generated by UniFFI.
## 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 as described below:
1. Switch the binaryTarget to a local path - note however that the path can't be absolute but must be relative to `Package.swift`.
For example, if you have `application-services` checked out next to the `firefox-ios` repo, a suitable relative path might be
`../../application-services/megazords/ios-rust/MozillaRustComponents.xcframework`
2. Comment out or remove the `url` and `checksum` elements - they aren't needed when pointing to a local path:
```swift
// In firefox-ios/MozillaRustComponents/Package.swift
.binaryTarget(
name: "MozillaRustComponents",
// ** Comment out the existing `url` and `checksum` entries
// url: url,
// checksum: checksum
// ** Add a new `path` entry.
path: "../../application-services/megazords/ios-rust/MozillaRustComponents.xcframework"
)
```
3. Update UniFFI generated files: manually copy `./megazords/ios-rust/Sources/MozillaRustComponentsWrapper/Generated/*.swift` from
your `application-services` directory to the existing `./MozillaRustComponents/Sources/MozillaRustComponentsWrapper/Generated/.`
directory in your `firefox-ios` checkout.
for example, from the root of your application-services directory:
```bash
cp ./megazords/ios-rust/Sources/MozillaRustComponentsWrapper/Generated/*.swift ../firefox-ios/MozillaRustComponents/Sources/MozillaRustComponentsWrapper/Generated/.
```
## 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 (rare), delete:
```swift
~/Library/Caches/org.swift.swiftpm
~/Library/Developer/Xcode/DerivedData/*
```
…and build again.
---
## Using an external XCFramework artifact.
The instructions above all assume you have an XCFramework you built locally. However, it might be
the case where you want to use a `MozillaRustComponents.xcframework.zip` from an HTTPS-accessible URL
(e.g., a Taskcluster or GitHub artifact URL).
In this scenario, you also need the checksum of the zip file - this can be obtained by executing
```bash
swift package compute-checksum megazords/ios-rust/MozillaRustComponents.xcframework.zip
```
However, that means you need to have the .zip file locally - in which case you might as well
unzip it and use the instructions above for consuming it from a local path!
But for completeness, once you have a https URL and the checksum you should
edit `MozillaRustComponents/Package.swift` and set the binaryTarget to the zip URL and checksum:
```swift
// In firefox-ios/MozillaRustComponents/Package.swift
.binaryTarget(
name: "MozillaRustComponents",
checksum: "<sha256 from `swift package compute-checksum`>"
)
```
> Note: Every time you produce a new zip, you must update the checksum.
> Note: The above instructions do not handle copying updated files generated by UniFFI.
If you have changed the public API of any components, this process as written will not work.
## Disabling local development
To revert quickly:
1. Restore your changes to MozillaRustComponents/Package.swift (e.g., git checkout -- MozillaRustComponents/Package.swift).
2. Reset Package Caches in Xcode.
3. 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:
1. Build the XCFramework from application-services.
2. In a local checkout of rust-components-swift, point its Package.swift to the local path of the unzipped XCFramework:
```swift
.binaryTarget(
name: "MozillaRustComponents",
path: "./MozillaRustComponents.xcframework"
)
```
3. Commit the changes in rust-components-swift (Xcode only reads committed package content).
4. 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).