# 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: 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", url: "https://example.com/path/MozillaRustComponents.xcframework.zip", 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).