Citolex just went live on the App Store. It's a speed-reading app, flash-based word-by-word reading with synced text-to-speech, everything on-device.
The part I actually want to write about is how it got built and shipped. I don't own a Mac. Xcode needs one to sign and archive an iOS build, so instead of buying hardware I built a GitHub Actions pipeline that does it for me.
Capacitor wraps the web app (HTML/JS/CSS) in a native iOS shell, so most of the UI didn't need native code. But Citolex needed a few things Capacitor can't reach on its own: text-to-speech, a Share Extension so you can send text into the app from Safari or Notes, an App Group so the extension and the main app can share data, and background audio so narration keeps playing when the app isn't in the foreground. Those are native Swift plugins layered on top of the Capacitor shell.
The workflow runs on GitHub's free macOS build minutes (available on public repos), checks out the code, pulls signing certs and provisioning profiles from GitHub secrets, archives with xcodebuild, exports a signed ipa, and uploads to App Store Connect on a normal git push.
What actually took the time wasn't the workflow file. It was the signing debug loop: certificate and profile mismatches, needing the exact same name between the Apple Developer portal and the CI config, and TestFlight silently rejecting a reupload with an unchanged build number while the CI log stayed green the whole time with no useful error. Eventually I added a validate step that runs before the real build and checks the Team ID and bundle ID actually match what's in the provisioning profile, so a mismatch fails fast with a specific message instead of a cryptic xcodebuild error twenty minutes in.
It shipped. Citolex is live, built and signed entirely through that pipeline, no Mac at any point: apps.apple.com/us/app/citolex/id6800933053
If you're in the same position, no Mac, need to ship a real iOS app, that pipeline is now packaged up as Macless (macless.dev).
Top comments (0)