How to Build iPhone Apps Without a Mac — EAS + GitHub Codespaces
00要約Overview
Tools
- Apple Developer ProgramApp Store submission$99/yr
- EAS buildBuilds on cloud macOSFree
- GitHub CodespacesOne-time certificate stepFree
- PC (any)Browser, one time onlyalready owned
01物語Story
Situation
With the dev loop from 1.1.1, the check-and-fix cycle through Expo Go spins nicely. During development, no build is ever needed.
Complication
Shipping to the App Store is another story. Submitting to Apple means building the app, and building an iPhone app requires a Mac — an unavoidable fact of Apple's ecosystem.
Question
A build needs a Mac. Without owning one, how do you reach the App Store?
02解決Solution
Criteria
- Works without owning a Mac (don't buy one, don't borrow one, don't host one)
Answer
# First time only (creating certificates) PC browser → GitHub → GitHub Codespaces → EAS (build) # From then on (everything from the iPhone) iPhone → GitHub → GitHub Actions → EAS (build) iPhone → GitHub → GitHub Actions → EAS (submit) → App Store Connect → TestFlight → iPhone
A Mac is required. It just has to live in the cloud.
EAS (Expo Application Services) builds your iPhone app on macOS machines on their side. All you need at hand is a device that can fire the command — and an iPhone is enough.
Reason
The one-time PC browser session exists because of interactivity. The first build creates the signing credentials for the App Store, and that process asks Y/N questions interactively. The answers are basically all Y, but automating them in GitHub Actions means writing tedious timing-sensitive response code. For an operation that happens a few times a year at most, automation isn't worth it — so the first time is manual.
Even that manual step needs no Mac. Open GitHub Codespaces — the VS Code environment GitHub gives you in a browser — and run the commands from there. The personal free tier (120 core-hours/month) is plenty. In theory a phone browser would work, but a terminal on a phone screen really is too small, so this one step used a PC browser. Again: a PC, not a Mac.
From the second time on, no interaction is needed: run the GitHub Actions workflow from the iPhone and the build rolls. When it succeeds, submit from Actions the same way, and the app lands in App Store Connect and comes down to your device through TestFlight. Right up to the moment of submission, everything completes on the iPhone.
Options
- Xcode Cloud — Apple's own CI/CD. But the initial setup needs Xcode, i.e., a Mac, which contradicts the "own no Mac" criterion. And since the app is built on EXPO, EAS's affinity settled it.
- GitHub Actions macOS runners — you can build directly on a macOS runner. But macOS minutes bill at 10× the Linux rate, and the 2,000 free minutes/month evaporate. Never dared.
03結果Result
Good
Build and submit both live in EAS now, so management is unified. Development in EXPO (1.1.1) continues seamlessly right up to the doorstep of submission — all from a phone. The real find: "you need a Mac," the tallest barrier in iPhone development, turned out not to mean "you need to own a Mac."
Bad
The free tiers come with constraints. As of writing:
| Service | Free tier | Notes |
|---|---|---|
| EAS build | 15 iOS builds/mo (+15 Android) | Failed builds still count |
| GitHub Actions | 2,000 min/mo | Free plan, private repos |
Normal development never hits these ceilings. But debugging native issues with repeated builds eats them fast — and the painful part is that failed builds still consume the count. Three consecutive errors from a config mistake, and a fifth of your month is gone.
Follow-up
Free-tier EAS builds sit at low priority, and the queue can get absurdly long. Waiting is fine — but here's the trap: if Actions sits waiting for the build to finish, that waiting time also drains your 2,000 Actions minutes. Waiting changes nothing about the result, so the right move is to run eas build with --no-wait and end the workflow the moment the trigger fires.
The trade-off is that build and submit no longer chain in one workflow. So it's a two-step routine: confirm the build succeeded on the EAS dashboard, then run submit from Actions. --no-wait works on submit too.
With this, the vertical line of "build it and deliver it" is connected — enough to release. Once released, add the safety layer that separates dev and production delivery — 1.1.3 Safe EAS Update operation — to prevent accidental releases during maintenance. Then the story widens sideways: 1.2 Localization.