Makes the iOS build a first-class citizen: ROM/mod/save import through
the system document picker (the README's missing "UIDocumentPicker
handoff"), Files-app drop-in support, and an opt-in Apple Health
step-sync seam consumed by a new gallery mod (Pokewalker).
Native layer (mobile/ios/native/, wired by mobile/ios/patch_love_src.py
on every build, so the fetched love-src tree stays pristine + re-patchable):
- GRPickerBridge.swift: love.system.pickFile("rom"|"mod"|"sav") and
love.system.createFile on iOS with the same contract as love-android's
SAF picker (picked_rom.gb / picked_mod.zip / picked_save.sav /
export_done.flag in the save dir). Reached from wrap_System.cpp via the
ObjC runtime, so liblove needs no Swift interop.
- GRBootstrap.m: sweeps .gb/.gbc/.zip/.sav dropped in Documents (Files
app / Finder sharing) into the save dir on every activation;
UIFileSharingEnabled + LSSupportsOpeningDocumentsInPlace in the plist
overlay. Drop a ROM, open the app, it imports with zero taps.
- GRHealthBridge.swift: love.system.syncHealthSteps() -> read-only
HealthKit step query anchored to the last sync, delivered as
steps_pending.json (merge-not-overwrite). HealthKit entitlement +
usage description included.
Lua:
- RomImporter: iOS rides the Android mobile flows; a 0.5s poll consumes
picker deliveries (iOS pickers are in-process modals, so the Android
refocus rescan never fires); failed pick copies surface as an
on-screen notice via pick_error.txt.
- main.lua: on iOS, stop forwarding touchpressed to the Importer - LOVE
already synthesizes a mousepressed for the primary touch, and the
resulting same-frame double-present made the document picker
auto-dismiss with zero documents (silent import failure).
- mods/pokewalker: opt-in Pokewalker mod (manifest v2, MECHANIC,
permissions declared, mod.card, CHANGELOG, headless test suite 9/9,
modkit validate --base imported + lint clean). Fused into iOS
game.love only; loads dormant anywhere without the bridge.
Build (scripts/build_ios.sh):
- Fix Xcode 26: the global PRODUCT_NAME override also renamed liblove.a
and broke the app link; the app bundle is renamed after the build
instead.
- Fix nondeterministic pack failures: grep -q + pipefail races SIGPIPE
on the game.love content checks.
- Simulator builds sign ad-hoc so entitlements embed (HealthKit works in
the simulator).
- Device builds: signing team auto-detected from the keychain,
CODE_SIGN_STYLE=Automatic + -allowProvisioningUpdates for CLI-only
provisioning, per-team derived bundle ID (explicit App IDs are
globally unique, so third parties can't sign the project default),
gitignored mobile/ios/bundle_id.local pin, and --install to push to a
connected iPhone.
- docs/ios-install.md: a zero-knowledge walkthrough from bare Mac to
playing on an iPhone.
Backward compatibility: no behavior change on desktop or Android. The
new love.system functions exist only under LOVE_IOS; RomImporter's
mobile flag simply includes iOS alongside Android; the main.lua change
is iOS-gated; the Pokewalker mod is packed only by the iOS build script
and its option defaults off.
Verified on an iPhone 17 Pro simulator and an iPhone 16 Pro device:
scripted ROM import to title screen, Files-drop zero-tap import,
picker-driven mod install and save import/export, HealthKit permission
sheet + step credit (4000 steps -> +200 EXP at the default rate through
the engine growth curve).
4.7 KiB
Build & install on your iPhone — step by step
This guide assumes zero programming experience. Follow it top to bottom and you'll have the game running on your own iPhone in roughly an hour (most of it is waiting for downloads).
What you need
- A Mac (any Apple-silicon or recent Intel Mac on macOS 14 or newer)
- An iPhone and its charging cable
- A free Apple ID (the same account you use for the App Store)
- Your own, legally obtained Pokémon Red or Blue ROM file (a 1 MB
.gbfile). This project ships no game data — the app rebuilds everything from your cartridge dump and verifies it before use. - About 15 GB free disk space (Xcode is enormous; the game itself is tiny)
Free vs. paid Apple account: a free Apple ID works. The only catch: apps signed with a free account stop launching after 7 days — just re-run the install command (step 5) to re-sign; your save data is kept. A paid Apple Developer account ($99/yr) extends that to a year.
Step 1 — Install Xcode (once)
- On the Mac, open the App Store, search Xcode, click Get. It's a ~10 GB download — go make tea.
- Open Xcode once. Accept the license. If it offers to install extra components or the iOS platform, say yes and let it finish.
Step 2 — Sign Xcode into your Apple ID (once)
- In Xcode's menu bar: Xcode → Settings → Accounts.
- Click the + in the bottom-left → Apple Account → sign in.
- Close the window. (This quietly creates the "signing certificate" the build uses — you never have to touch it again.)
Step 3 — Get this project onto the Mac
If you received it as a folder, put it somewhere easy like your home folder. If it's on GitHub, click the green Code button → Download ZIP, then double-click the zip to unpack it.
Step 4 — Build it (one command)
-
Open the Terminal app (press ⌘-space, type
terminal, press return). -
Type
cd(c, d, space — don't press return yet), then drag the project folder from Finder onto the Terminal window — it fills in the path — and press return. -
Paste this and press return:
scripts/build_ios.sh --fetchThe first run downloads the LÖVE engine and compiles everything (5–15 minutes). Lines of build output scrolling by is normal. You're done when you see
==> done.
Step 5 — Put it on your iPhone
-
Plug the iPhone into the Mac with the cable. Unlock it and keep it unlocked. If it asks "Trust This Computer?" → Trust.
-
Paste this and press return:
scripts/build_ios.sh --device --installThe script finds your signing identity and your phone by itself. If it complains, it tells you exactly what to fix (usually: the phone was locked — unlock and re-run).
-
First time only, the iPhone will want two approvals:
- Developer Mode: Settings → Privacy & Security → scroll to Developer Mode → turn on → restart the phone → confirm.
- Trust the developer: Settings → General → VPN & Device Management → tap the entry under Developer App → Trust.
Then re-run the command in step 5.2 if the install had failed.
Step 6 — Give it your ROM and play
- Get your
.gbfile onto the phone — AirDrop it to yourself, or save it in iCloud Drive / Files. - Open the app. On the RED tab, tap Import ROM and pick your
.gbfile in the file browser that appears. (Alternative: in the Files app, drop the.gbinto On My iPhone → the game's folder and just reopen the app — it imports automatically.) - Import takes ~10 seconds, the button turns into Play Red — tap it.
Optional goodies
- Pokéwalker mode (real steps → EXP): in-game mod manager → POKEWALKER → SYNC STEPS on, allow step access when iOS asks, and go for a walk.
- Mods: launcher → MODS tab → Import mod .zip.
- Save import/export: buttons on each game's tab, using the normal iOS file picker.
When things go wrong
| Symptom | Fix |
|---|---|
xcodebuild not found |
Xcode isn't installed or wasn't opened once — do Step 1 |
no Apple signing identity found |
Do Step 2, then re-run |
no iPhone/iPad found |
Cable in? Phone unlocked? Tapped "Trust"? |
| Install fails with "locked" | Unlock the phone, keep it unlocked, re-run |
| App icon appears then won't open | Do the two approvals in Step 5.3 |
| App stops launching after a week | Free-account 7-day limit — re-run Step 5.2 |
| "That ROM could not be imported" | The file isn't a canonical 1 MB US Red/Blue dump — the importer checks its fingerprint |
Every build/install command is safe to re-run; your saves live on the phone and survive reinstalls.