Skip to content

Building

DashPilot is a plain Xcode project with no package manager, no code generation step and no bootstrap script. Cloning it and opening it is the whole setup.

Requirements

Requirement Version
Xcode A version including the iOS 26.5 SDK or newer
iOS deployment target 26.5
Swift Swift 5 language mode, with SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor
Dependencies None
Targets DashPilot, plus the DashPilotWidgets extension it embeds

The deployment target is iOS 26.5. Check xcodebuild -showsdks and select a compatible installed simulator. The Interval 4B verification host uses Xcode 27.1; that is a tested host, not a new minimum deployment target.

Schemes

Both schemes are shared and committed, under DashPilot.xcodeproj/xcshareddata/xcschemes, so -scheme DashPilot means the same thing in a fresh clone, in CI and on a machine that has had the project open for months. Per-user Xcode state (xcuserdata) stays out of the repository, and one of the things it holds is a flag that switches off Xcode's automatic creation of a scheme for a target. A project whose schemes are not tracked therefore builds or does not build from the command line depending on files nobody can see.

In Xcode

Open DashPilot.xcodeproj, choose the DashPilot scheme and an iOS simulator, then build and run. The scheme covers the app, the DashPilotWidgets extension it embeds, the DashPilotTests domain suite and the DashPilotUITests journeys. There is a DashPilotWidgets scheme too, and it is only useful for previews: the extension cannot run on its own, and the Live Activity it draws is requested by the app.

From the command line

xcodebuild build \
  -project DashPilot.xcodeproj \
  -scheme DashPilot \
  -destination 'platform=iOS Simulator,name=iPhone 17'
xcodebuild test \
  -project DashPilot.xcodeproj \
  -scheme DashPilot \
  -destination 'platform=iOS Simulator,name=iPhone 17'

Substitute any installed iPhone simulator for iPhone 17. To see what is installed:

xcrun simctl list devices available

For the clean verification build, include the app, embedded widget and both test targets together:

xcodebuild clean build-for-testing -project DashPilot.xcodeproj -scheme DashPilot \
  -destination 'platform=iOS Simulator,name=iPhone 17' \
  -derivedDataPath DerivedData CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO

Then run each complete suite using test-without-building with the same destination and derived data path. Keep UI tests serial with -parallel-testing-enabled NO. See Testing.

The typeface

DashPilot is set in SF Pro, the system typeface, and bundles no font: there is no font file, no UIAppFonts entry and no font license in the app or the widget extension. The reasons are in the design system. DashPilot's own source code is MIT (LICENSE).

FontBundleInvariantTests pins what a font change must not disturb: no UIAppFonts entry and no font file or font license in the app bundle, the widget extension still embedded and carrying no font, and NSSupportsLiveActivities, the location background mode and the When In Use usage description all still declared. ProjectFileInvariantTests reads the project file for two things the bundle cannot show: no file reference is an absolute path on one machine, and no font folder is a member of the widget target.

Signing

The app target carries a development team for local device runs. Simulator builds do not need it, and CI passes CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO so that no Apple Developer account is required to build or test the project. Nothing in the repository signs or archives for distribution.

Building the documentation site

The documentation is MkDocs Material. It is entirely separate from the app: Python is never required to build or run DashPilot itself.

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements-docs.txt
mkdocs serve

mkdocs serve publishes a live-reloading copy on http://127.0.0.1:8000/.

To reproduce exactly what CI checks:

mkdocs build --strict

strict is on in mkdocs.yml as well, so a broken internal link, a missing anchor or a page left out of the navigation fails the build rather than shipping. The generated site/ directory is ignored by Git and must never be committed.

Continuous integration

One workflow covers the app and two the documentation:

Workflow Trigger What it does
ci.yml Pull requests, pushes to main, a weekly schedule, v* tags, manual dispatch Builds the app and both test bundles for an iOS simulator on a GitHub-hosted macOS runner, then runs the whole domain suite and every UI journey as separate steps
docs-check.yml Pull requests touching docs/, mkdocs.yml, requirements-docs.txt, the README or itself Runs mkdocs build --strict on Ubuntu. It validates only and never deploys
docs.yml Pushes to main touching documentation, and manual dispatch Builds the site and deploys it to GitHub Pages through the Actions artifact

The runner details, including how the Xcode version and the simulator destination are chosen, are under Testing.