Skip to content

iOS

For: getting the game onto an iPhone or iPad, and from there onto the App Store.

What the iOS app is

The iOS app is an Expo application that wraps the web game in a native shell. It loads the deployed site in a web view. It adds the native pieces a browser cannot give: deep links, haptics, push notifications, a wake lock, offline and update-required screens, and back navigation.

That shape has a consequence worth holding onto. Shipping a change to the game itself is a web deploy, not an App Store submission. A new binary is needed only when the native shell changes.

The project lives under platforms/mobile, and its configuration is platforms/mobile/app.config.ts.

Identity

These values are committed and are the same on both platforms. Changing the bundle identifier after a store release starts a new app rather than updating the existing one.

ItemValue
Display nameGrafted Wars
Bundle identifiercom.graftedwars.game
Expo sluggrafted-wars
Expo accountevgeniiarts
URL schemegraftedwars
Version1.0.0, with build numbers held remotely by Expo
Orientationportrait
Tablet supporton

Encryption is declared as non-exempt in the configuration, which is what lets a submission skip the export-compliance questionnaire.

Once per machine

Install the mobile project's own dependencies, which are separate from the repository root's:

bash
npm ci --prefix platforms/mobile

Building locally for a device also needs Xcode and a CocoaPods install, both on macOS. Building through Expo's hosted builders needs neither, which is the route the committed build script uses.

Which server the app talks to

The shell points at the production site by default. Override it to aim at staging or at a local loop:

bash
GRAFTED_WARS_GAME_URL=https://<staging address> npm run build:ios --prefix platforms/mobile

The value is validated rather than trusted. A URL carrying embedded credentials is discarded, and a plain-HTTP URL is discarded unless it is localhost and GRAFTED_WARS_ALLOW_HTTP_LOCALHOST is set to true.

Run it on a device or simulator

Start the development server and open the project:

bash
npm run start --prefix platforms/mobile

To build and run a native debug build on a connected device, on macOS:

bash
npm run ios --prefix platforms/mobile

Build for distribution

The committed script builds an internal-distribution build through Expo's hosted builders:

bash
npm run build:ios --prefix platforms/mobile

That uses the preview profile, which distributes internally and does not target the simulator. Three profiles exist in platforms/mobile/eas.json.

ProfileDistributionFor
developmentinternal, with the development clientday-to-day work against a dev server
previewinternalhanding a build to a tester or to yourself
productionstorean App Store submission, with the build number incremented automatically

For a store build, name the production profile explicitly:

bash
npx eas build --platform ios --profile production

Credentials

Expo generates and holds the signing material, and prompts for what it needs on the first build. An Apple Developer Program membership is the prerequisite.

ItemWhere it comes from
Apple Developer Program membershipdeveloper.apple.com
Distribution certificate and provisioning profilegenerated and stored by Expo, backed by your Apple account
App Store Connect API keyappstoreconnect.apple.com → Users and Access → Integrations
Expo access tokenexpo.dev → Account Settings → Access Tokens, for non-interactive builds

None of these belong in this repository. Credentials and access is the index.

App Store submission

Once a production build finishes, submit it:

bash
npx eas submit --platform ios --profile production

The submission profile is present in the configuration and carries no options of its own, so the interactive prompts decide the target. Expect the App Store Connect listing, screenshots and review notes to be filled in through the web console rather than from here.

Prove it before you ship

Type-check the mobile project from the repository root:

bash
npm run mobile:typecheck

The project also carries its own suite, run from its own directory:

bash
npm test --prefix platforms/mobile

Sharp edges

A web deploy changes what every installed app shows, because the shell loads the live site. A bad production deploy therefore reaches phones without any store involvement.

The app images are generated rather than hand-drawn, and a check verifies they match. Run npm run images:check --prefix platforms/mobile when an icon or splash asset changes.

Build numbers are held remotely by Expo rather than in the repository, so two machines cannot disagree about the next one.