PublishingPublish to app stores

Native project

The full phone project, for ads, purchases and a developer who looks after it.

Native gives you the whole app as a phone project, in one ZIP or pushed to a GitHub repository. Give it the app's name and an app ID like com.yourcompany.yourapp first: the ID is how the stores know your app, and it cannot change once it is published.

The window then shows the exact commands to build it, for Android and for the iPhone:

text
npm install && npm run build
npx cap add android
npm run icons
npx cap sync && npx cap open android

On the iPhone, ios takes the place of android, and the last command opens Xcode.

From there it is the stores' own path: sign the app in Android Studio or Xcode, upload it, test it, fill the store page and release. Keep the Android signing key and its passwords safe. Every update must be signed with the same key. Without Android Studio or a Mac, GitHub can build it for you: Build in the cloud.

Getting the project: download or GitHub

In step 1, Download the project has two fields, App name and App ID. The ID starts as com.setherion. and the app's name, and it has to be written in the reverse-domain form. Download project (.zip) builds a ZIP called after the app. It holds the web project, the phone files, a schema.sql if the app has tables, any game art, and the icon and launch screen pictures. It needs a paid plan.

Instead, or push to GitHub: connect with Connect with GitHub, or paste a token, choose a Repo name and press Export to GitHub. The repository is created private, and Open repo takes you to it. This also needs a paid plan.

Native on Android, step by step
  1. Download the project, as above.
  2. Build it. Needs Node 22 and Android Studio. Run the commands the window shows. If the app uses ads or purchases, npm run native:setup is added after npx cap add android.
  3. Sign it. In Android Studio choose Build, then Generate Signed App Bundle. Create a key and keep it and its passwords: every update needs the same key.
  4. Upload it and test it. Create the app in Play Console, upload the .aab to Internal testing, then fill the store page, the content rating and Data safety. With ads you also declare the advertising ID.
  5. Release. Review takes a few hours to two days. A personal Google Play account opened after November 2023 needs the closed test first.
Native on iPhone, step by step
  1. Download the project: the same ZIP as for Android.
  2. Build it. Needs a Mac with Xcode and the $99 a year Apple developer account. Run the same commands with ios in place of android.
  3. Sign it and upload it. In Xcode open Signing & Capabilities and pick your team. With ads or purchases add In-App Purchase. Then Product, Archive, Distribute, to App Store Connect.
  4. Try it on your iPhone with TestFlight.
  5. Fill the store page and send it for review. With ads, Apple counts them as tracking.

Build in the cloud

No Android Studio and no Mac: GitHub can build the app on its own computers. Push the project to GitHub in step 1 and the repository gets two build workflows, one for Android and one for the iPhone. The Build it step then shows Build it in the cloud, with a button to the workflow's page on GitHub.

On GitHub open Actions, pick Android build or iPhone build, press Run workflow and choose what to build:

WorkflowChoiceWhat you get
Android buildTest APKAn app to install on your own phone, under the run's Artifacts. Nothing to set up.
Android buildMake a new keyThe signing key, made once before your first Google Play upload. Only in a private repository.
Android buildGoogle Play bundle (.aab)The signed file for Play Console, with a higher version number on every run.
iPhone buildCheck that it buildsProof that the app compiles for the iPhone. No Apple account needed.
iPhone buildTestFlightThe app signed and sent to App Store Connect, to install with TestFlight.

A private repository has 2,000 free minutes of GitHub's computers a month. An Android build takes a few of them, and GitHub counts a Mac minute as ten. The repository's README says each step.

Before the first Google Play bundle
  1. Run Make a new key and download upload-key from the run.
  2. Keep upload.jks and its password safe, outside the repository. Every update must be signed with the same key.
  3. In the repository open Settings, Secrets and variables, Actions, and add three secrets, each with the text of its file: ANDROID_KEYSTORE_BASE64, ANDROID_KEYSTORE_PASSWORD and ANDROID_KEY_ALIAS.
  4. Run Google Play bundle (.aab) and upload the file to Internal testing in Play Console.
Before the first TestFlight build
  1. In App Store Connect create the app, with the same app ID as in step 1.
  2. In Users and Access, Integrations, App Store Connect API, generate a key with the Admin role and download its .p8 file. Apple lets you download it only once.
  3. In the repository add four secrets: APPLE_TEAM_ID (Membership details on developer.apple.com), ASC_KEY_ID, ASC_ISSUER_ID and ASC_KEY_P8, the text of the .p8 file.
  4. Run TestFlight. A few minutes later the build is in App Store Connect, under TestFlight. The workflow tells Apple the app uses only standard encryption, so TestFlight does not ask about it.

A GitHub connection made before the cloud build cannot add the workflows: the step says so, and Reconnect in step 1 fixes it.

Accounts in the phone app

In the phone app people sign in with email and password. The Google button and the emailed sign-in link hide themselves there. That is why the Delete account button check matters: Apple refuses an app people can sign up to without one.

Ads and purchases

A game that shows ads or sells something works for real only in the Native project: ads from Google AdMob, purchases from the stores through RevenueCat. In the editor's preview they are pretend ("Test ad", "Test purchase", no money taken), so you can try them, and on the published website they are hidden. In the Easy way the game runs without them.

The project starts on Google's test ads, which pay nothing. Put your own ad ids and store keys in src/monetize.keys.json, and run npm run native:setup: the project's README says where each one comes from.

What goes in the keys file

The file holds the AdMob app id and the rewarded and interstitial ad unit ids for Android and the iPhone, and the RevenueCat keys for each store (starting goog_ for Android and appl_ for the iPhone). Without RevenueCat keys, or without products, nothing is sold.

For real ads, create the AdMob account, apps and ad units, put the ids in the file, run npm run native:setup on fresh native folders, and publish an app-ads.txt file on the website. For purchases, create products in Play Console and App Store Connect with the same ids as in src/monetize.json, and connect both stores in a RevenueCat project. On the iPhone, add the In-App Purchase capability.

Both stores want a privacy policy link, and a Restore purchases button is required: the project provides one. Between ads, the app skips an interstitial in the first 30 seconds, within 60 seconds of the last, and for a player who has bought the remove-ads product.

Was this page helpful?

Join the community

Questions, ideas and what others are building.