Skip to content

Android

For: getting the game onto an Android phone, and from there onto Google Play.

What the Android app is

The Android app is the same Expo application as the iOS one. It wraps the web game in a native shell that loads the deployed site in a web view. On top of that it adds deep links, haptics, push notifications, a wake lock, offline and update-required screens, and hardware back-button handling.

Shipping a change to the game itself is therefore a web deploy rather than a Play 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. The application id is the same string as the iOS bundle identifier, and changing it after a Play release starts a new listing rather than updating the existing one.

ItemValue
Display nameGrafted Wars
Application idcom.graftedwars.game
Expo sluggrafted-wars
Expo accountevgeniiarts
URL schemegraftedwars
Version1.0.0, with version codes held remotely by Expo
Orientationportrait
Adaptive icona foreground image over the palette's background colour

Three permissions are blocked outright in the configuration, so no dependency can quietly add them: the overlay permission, and both external-storage permissions. That keeps the Play listing's permission set small and the review short to answer for.

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 also needs a Java toolchain and the Android SDK, with adb on your path for device work. Building through Expo's hosted builders needs none of that.

Which server the app talks to

The shell points at the production site by default. Override it to aim elsewhere:

bash
GRAFTED_WARS_GAME_URL=https://<staging address> npx eas build --platform android --profile preview

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

Start the development server:

bash
npm run start --prefix platforms/mobile

To build and install a native debug build on a connected device:

bash
npm run android --prefix platforms/mobile

Regenerating the native project from the configuration, when a plugin or an identity value changes:

bash
npm run prebuild:android --prefix platforms/mobile

Prove it on real hardware

The project carries a script that drives a connected device and reports what it found. Three forms exist:

bash
npm run prove:android --prefix platforms/mobile
npm run prove:android:debug --prefix platforms/mobile
npm run prove:android:release --prefix platforms/mobile

Use the release form before a store build, because a release build differs from a debug one in ways that only show on a device.

Build for distribution

Three profiles exist in platforms/mobile/eas.json, and the artifact differs by profile.

ProfileArtifactFor
developmentdevelopment client buildday-to-day work against a dev server
previewan APKsideloading onto a device, or handing to a tester
productionan app bundlea Play submission, with the version code incremented automatically

An APK you can install directly:

bash
npx eas build --platform android --profile preview

A Play-ready app bundle:

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

Play accepts app bundles rather than APKs for new releases, which is why the production profile differs from preview here and does not on iOS.

Credentials

Expo generates and holds the upload keystore, and prompts for what it needs on the first build.

ItemWhere it comes from
Upload keystoregenerated and stored by Expo on the first build, or supplied by you
Google Play developer accountplay.google.com/console
Play service account keya Google Cloud service account, granted access in the Play Console
Expo access tokenexpo.dev → Account Settings → Access Tokens, for non-interactive builds

Losing the upload keystore without Play App Signing enrolled means no further update can be published to that listing. Enrol in Play App Signing and let Google hold the app signing key, so a lost upload key can be reset rather than being fatal.

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

Google Play submission

Once a production build finishes, submit it:

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

The submission profile carries no options of its own, so the interactive prompts decide the target track. The listing, screenshots, content rating and data-safety declarations are filled in through the Play 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 reaches phones with no store involvement.

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

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