Phase 0

Before you start

Accounts, machines and tools

1–3 days (account approval)0/6 done

Store accounts take real time to approve and cost real money. Start these on day one so nothing blocks you at the end. Everything below is a one-time setup per developer, not per app.

01

Understand what you are actually building

Your web app stays exactly as it is. Capacitor wraps the built files in a thin native shell — an Android project and an iOS project — that opens your app in a full-screen system web view and hands it a bridge to native APIs (camera, push, files, biometrics). The stores receive a normal native app package; inside it, your web app runs.

  • One codebase. The same React app powers web, Android and iOS.
  • Two extra folders. android/ and ios/ are generated native projects that live in your repository.
  • Native build steps stay native. Android builds with Gradle/Android Studio, iOS builds with Xcode on a Mac. There is no way around that.
  • Store review is a human process. Plan for 1–7 days on Apple and hours-to-days on Google, plus the mandatory testing period for new Play accounts.
02

Open a Google Play Developer account

This is the primary target. Registration costs a one-time $25 USD and requires identity verification — government ID, address, and for organisations a D-U-N-S number. Verification is the slow part; it can take a few days.

  1. Go to the Play Console signup and choose Personal or Organisation. Choose carefully — switching later means a new account.
  2. Pay the $25 fee with a card matching your identity details.
  3. Complete identity verification and, for personal accounts, provide a phone number and address that match your ID.
  4. Set up a payments profile if you plan to sell anything or run ads.
03

Open an Apple Developer account

The Apple Developer Program costs $99 USD per year and must be renewed or your apps are removed from sale. Enrolment is done in the Apple Developer app or on the website, and usually completes within 48 hours; organisations need a D-U-N-S number, which can take longer.

  • Individual enrolment publishes under your legal name — visible on the store listing.
  • Organisation enrolment publishes under your company name and requires a legal entity plus D-U-N-S.
  • You need an Apple ID with two-factor authentication enabled.
04

Get a machine that can build iOS

Android builds on Windows, macOS or Linux. iOS builds require macOS and Xcode — this is an Apple restriction with no legitimate workaround. Your options:

OptionCostGood for
Own a Mac (M-series)One-time hardwareRegular releases, debugging on device
Mac cloud (MacStadium, Scaleway)Hourly/monthly rentalOccasional releases
CI service (Codemagic, Bitrise, Xcode Cloud, GitHub Actions macOS runners)Free tier then per-minuteAutomated builds, no local Mac
05

Install the local toolchain

ToolVersionWhy
Node.js20 LTS or 22 LTSBuilds your web app and runs the Capacitor CLI
Gitany recentYour code lives in GitHub
Android Studiolatest stableAndroid SDK, emulator, Gradle, signing UI
JDK17 (bundled with Android Studio)Gradle requires it; do not use 8 or 11
Xcodelatest stable (Mac only)iOS build, archive, upload
CocoaPodslatest (Mac only)iOS native dependencies

Verify everything in one go:

Verify your toolchain
node -v      # expect v20.x or v22.x
npm -v
git --version
java -version   # expect 17.x

# macOS only
xcodebuild -version
pod --version
Add the Android SDK to your shell (macOS/Linux)
# ~/.zshrc or ~/.bashrc
export ANDROID_HOME=$HOME/Library/Android/sdk   # Linux: $HOME/Android/Sdk
export PATH=$PATH:$ANDROID_HOME/platform-tools
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin
export PATH=$PATH:$ANDROID_HOME/emulator
06

Decide your app identity now

Your application ID (Android) / bundle identifier (iOS) is permanent. Once an app is published under com.example.myapp, that string can never change — a new ID means a new listing with zero installs and zero reviews. Choose it as if it were a domain name.

  • Reverse-domain form: com.yourcompany.yourapp.
  • Lowercase letters, digits and dots only. At least two segments. No hyphens, no leading digits in a segment, no reserved Java words (new, class, int).
  • Never ship com.example.* — Play rejects it.
  • Use the same string on both platforms so your analytics, deep links and push tokens line up.

Configuration generator

Saved in this browser and substituted into every command and snippet in the guide.

capacitor.config.ts
import type { CapacitorConfig } from "@capacitor/cli";

const config: CapacitorConfig = {
  appId: "com.example.myapp",
  appName: "My App",
  webDir: "dist",
  android: {
    allowMixedContent: false,
  },
  ios: {
    contentInset: "always",
  },
  plugins: {
    SplashScreen: {
      launchAutoHide: false,
      backgroundColor: "#ffffff",
      androidScaleType: "CENTER_CROP",
      showSpinner: false,
    },
    Keyboard: {
      resize: "body",
      resizeOnFullScreen: true,
    },
  },
};

export default config;