Publishing on the Play Store, step by step

The whole procedure to put a JumPHP game on Google Play and keep it there: what to build, what to keep, what to check on a phone, and the Play Console from start to end. It holds for both kinds of app:

The web app (On Google Play) The native app (Native Android app)
Command bin/jumphp twa my-game --url https://jumphp.net/my-game bin/jumphp android my-game
What it is the game's page in Chrome, full screen PHP, SDL and the game inside the app, offline
The game updates with the site, at once (no new app) with a new version of the app

Your Claude knows this guide (it is in your project's AGENTS.md, and docs/google-play.md): ask it "put my game on Google Play". It does the technical part; the choices and the submissions stay yours (see the end).

0. Before you start

  • A Google Play developer account: play.google.com/console, 25 $ once, with an identity check. It is your account: you accept Google's terms.
  • A new personal account must run a closed test with at least 12 testers for 14 days before it may publish in production. Start it early.
  • The package name (io.github.<your github account>.<my_game>): the app's id on Google Play. It never changes. The command asks it the first time.
  • The Android SDK license: you accept it, in your terminal, the first time (the SDK, ~1 GB, goes into ~/.jumphp). Your Claude asks you to run the command yourself (! bin/jumphp twa …).
  • A privacy policy at a public address: Google asks for it even when the game collects nothing. A short page is enough: the game collects, sends and shares no personal data; no account, no ads, no tracking; settings and saves stay on the device; a contact address. Put it in the game's site, games/my-game/site/privacy.html: it is served at https://play.jumphp.net/my-game/privacy.html (or the PRIVACY.md of your public repository). Open the address once before giving it to Google: a 404 blocks the review.

1. The keys: back them up first

The first build makes your upload key: ~/.jumphp/android/keys/<package>.keystore and its password in <package>.env.

  • Never in git, nor in a note or a message. Back up both files elsewhere (a password manager, an encrypted disk). Without them, a new build makes another key and Google Play refuses the update.
  • With Play App Signing (the default), Google keeps its own key, the one that signs the app on the phones. Yours only proves the uploads are yours; if lost, Google can replace it (Setup > App signing), but it takes days.
  • So there are two SHA-256 fingerprints: your key's (printed by the command) and Google's (Play Console > Setup

    App signing, after the first upload).

2. Build the app

bin/jumphp twa my-game --url https://jumphp.net/my-game     # the web app
bin/jumphp android my-game                                   # or the native app
  • Each build is version code + 1 (Google Play refuses a number it already has; a failed try uses a number, which is harmless).
  • Commit the version file at once: games/my-game/android/twa-manifest.json (web app) or games/my-game/android/app.json (native app). Never dist/.
  • The name under the icon: pwa: {short_name: …} in game.yaml (12 characters show whole). The icon: assets/icon.png.

3. Web app only: the site vouches for the app

Android opens the page full screen only if the site declares the app: the package name and both fingerprints (yours and Google's). With yours only, the app installed from your .apk works, but the one installed from Google Play opens with an address bar (or an "Open with" chooser).

In the Studio, the game's page, Android app part (or your Claude: update_project). The site publishes them in https://jumphp.net/.well-known/assetlinks.json. On your own server: https://your-domain/.well-known/assetlinks.json.

4. Try it on a real phone

With USB debugging on and adb:

adb install -r games/my-game/dist/android/my-game-<version>.apk
adb shell pm get-app-links <package>         # web app: "jumphp.net: verified"
adb exec-out screencap -p > shot.png         # look at it: the game must be there
  • The app must open on the game's title screen.
  • An .apk signed with your key does not install over the same app from Google Play (INSTALL_FAILED_UPDATE_INCOMPATIBLE): uninstall first (the app's saves are lost).
  • The web app opens then closes at once, with an "Open with" chooser: the phone has two Chrome, usually because of a clone space / second space / dual apps (Xiaomi, Samsung…). JumPHP's app asks for the Chrome of the main profile, which fixes it for players; on your test phone, removing the clone space erases every app in it.
  • The game opening in Chrome does not prove the app works: try the app.

5. The Play Console, the first time

The dashboard's "Set up your app" list (n of 11) shows what is left; "Send for review" stays greyed out while something is missing.

  1. Create app: name, default language, Game, Free, the declarations.
  2. App content (Policy > App content), every declaration:
    • Privacy policy: the public address of step 0;
    • Ads: no ads (JumPHP adds none);
    • App access: everything available without special access (no account);
    • Target audience: the ages the game is made for. Ages under 13 put the app in the Families programme (stricter rules, less visibility): only if the game is really made for children;
    • Content rating (IARC questionnaire): category Game; answer honestly for your game (cartoon or fantasy violence, blood, fear, gambling, player-made content, players talking to each other, location, purchases);
    • Data safety: a JumPHP game without accounts or analytics collects and shares no data (saves stay on the device; if your game calls a web service, declare it);
    • Advertising ID: not used;
    • Government apps, financial features, health: no.
  3. Store settings (Grow > Store presence > Store settings): the category (Arcade, Action, Puzzle…) and the contact e-mail. Both are required: without them, "Your app cannot be published yet". The e-mail is public.
  4. Main store listing: title (30 characters), short description (80), full description (4000), icon 512 × 512 PNG (bin/jumphp build makes it: dist/web/icon-512.png), feature graphic 1024 × 500, at least 2 phone screenshots (bin/jumphp shot my-game, scaled up by a whole factor, or taken on a phone). Keep the pictures in the game (games/my-game/store/) to redo them for the next versions.
  5. Testing: Test and release > Testing > Internal testing (or Closed testing for the 12 testers of a new account) > Create release > the .aab > release notes > Save > Review > Start rollout. Testers: a list of addresses; each opens the invitation link signed in with that Google account and taps Become a tester.
  6. Web app: after this first upload, add Google's key fingerprint (step 3), install from the test link and check it is full screen.
  7. Production: Production > Countries / regions > Add, select, Save (a release without countries is refused), then Create release > the .aab > notes > Next > Save.
  8. Publishing overview > Send for review, confirm. The review takes a few hours to 7 days; the console and the account's e-mail say when the app is live.

6. Release notes

One block per language, the tags on their own lines:

<en-US>
First release.
</en-US>
<fr-FR>
Première version.
</fr-FR>

7. The next versions

  • Web app: the game updates with the site (you push, it is published): no new app. A new app only when the name, the icon, the colours, the start address or the package change: bin/jumphp twa my-game.
  • Native app: each change of the game is a new app: bin/jumphp android my-game --version-name 1.1.

Then: commit the version file, try the .apk on a phone, then Play Console > the same track > Create release > the new .aab > notes > Send for review. The declarations stay valid unless the game changes what they describe (online play, purchases, data): update them first then.

8. Pitfalls met

Symptom Cause, fix
The app opens with an address bar a fingerprint (Google's) or the package is missing on the site: step 3
The web app opens and closes at once two Chrome on the phone (clone space): step 4
INSTALL_FAILED_UPDATE_INCOMPATIBLE the installed app comes from Google Play (another key): uninstall first
"Version code already used" build again (version + 1)
Google Play refuses the update's key the upload key was lost or remade: restore the backup, or ask Google to reset it
"Your app cannot be published yet" Store settings: category and contact e-mail
"Send for review" greyed out a step of "Set up your app" is missing; a release without countries
"Upload at least 1 asset" the picture is in the library but not attached to the listing: add it from the library panel
A tester is not added type the address then Enter (the chip), then Save and confirm
The privacy policy is refused its address answers 404 or is not public: open it in a private window

What your Claude does not do without you

  • accept the Android SDK license, Google's terms, or answer the content rating questionnaire without telling you its answers;
  • choose the target audience (saying the game is "for children" changes the rules and the visibility);
  • send to production without your yes for that submission;
  • remove a clone space or uninstall an app from your phone (data is lost);
  • put the keys, the passwords or dist/ in git.