A Capacitor-based Android app (package: games.supergoose.path). This README covers the
sync/build workflow and a debugging section for the issues encountered so far.
- Node.js + npm
- Android SDK / Android Studio (for
adb,gradlew, emulator/device testing) bundletool(optional, for inspecting.aabfiles locally)
Whenever you change capacitor.config.ts, web assets, or native config files
(AndroidManifest.xml, build.gradle), re-sync before building:
npx cap sync androidNote: editing native files (manifest, Info.plist, build.gradle) does not take
effect just by saving them — you must run cap sync and then rebuild, or the build
cache will serve stale native config.
Build the Next application
npm run buildDebug build (for local testing):
cd android
./gradlew assembleDebugRelease build (for Play Console upload):
cd android
./gradlew clean
./gradlew bundleReleaseOutput AAB:
android/app/build/outputs/bundle/release/app-release.aab
- Bump
versionCodeinandroid/app/build.gradle(must strictly increase every upload — integers only, no uniqueness requirement onversionName) - Bump
versionName(human-readable string, e.g."1.0.1") — optional but recommended - Confirm the build is signed with your release/upload key, not the debug keystore (see Debugging → Release Signing below)
-
applicationIdinbuild.gradlematches the App ID registered in Play Console
android {
namespace "games.supergoose.path"
defaultConfig {
applicationId "games.supergoose.path"
versionCode 2 // increment every upload
versionName "1.0.1" // user-facing string
...
}
}versionCode/versionName live in native android/app/build.gradle — npx cap sync
does not touch them, so bump manually or automate via a Gradle version-bump
script/CI step.
Android — in android/app/src/main/AndroidManifest.xml:
<activity
android:name=".MainActivity"
android:screenOrientation="portrait"
...>Use "portrait" for upright-only, or "userPortrait" to also allow upside-down.
iOS — in Xcode (npx cap open ios) → app target → General → Deployment Info,
uncheck Landscape Left/Right under Device Orientation. This edits Info.plist
(UISupportedInterfaceOrientations); update the ~ipad variant too if you support iPad.
Runtime control (allow rotation on some screens only):
npm install @capacitor/screen-orientation
npx cap syncimport { ScreenOrientation } from "@capacitor/screen-orientation";
await ScreenOrientation.lock({ orientation: "portrait" });
await ScreenOrientation.unlock();The plugin can only unlock into orientations still allowed by the native manifest/plist config — for full runtime flexibility, keep native config permissive and control locking via the plugin instead.
Symptom: Play Console rejects upload because the app's package doesn't match the
registered App ID (e.g. project was cap init'd with com.yourname.mygame but Play
Console has games.supergoose.path registered).
Fix — update the package name in every location:
-
capacitor.config.tsconst config: CapacitorConfig = { appId: "games.supergoose.path", // ... };
-
android/app/build.gradle—namespaceandapplicationIdmust both match:android { namespace "games.supergoose.path" defaultConfig { applicationId "games.supergoose.path" ... } }
-
Move the Java source folder to match the new package path:
cd android/app/src/main/java mkdir -p games/supergoose/path git mv com/yourname/mygame/MainActivity.java games/supergoose/path/MainActivity.java rm -rf com(drop
gitfromgit mvif not a git repo) -
Update the package declaration inside the moved
MainActivity.java:package games.supergoose.path;
-
Check
AndroidManifest.xmlfor a leftoverpackage="..."attribute pointing to the old name (modern AGP usually only sets this vianamespaceinbuild.gradle, but worth checking). -
Clean, sync, rebuild:
npx cap sync android cd android ./gradlew clean ./gradlew bundleReleaseRe-upload the new
.aab.
Symptom: Google Play rejects the upload because versionCode 1 (or whatever was
last uploaded) has already been used — even to internal testing, even if that release
was later deleted. Every uploaded AAB needs a unique, incrementing versionCode.
Fix:
android {
defaultConfig {
applicationId "com.yourapp.id"
versionCode 2 // increment this
versionName "1.0.1" // usually bump this too
...
}
}cd android
./gradlew clean bundleReleaseNew AAB lands at android/app/build/outputs/bundle/release/app-release.aab.
Notes:
versionCodemust always increase — integers only, no requirement to matchversionName.versionNameis just the human-readable display string, no uniqueness requirement.cap syncwill not touch either value — bump manually each release, or automate it.- To check the version code baked into an existing
.aab, usebundletoolor just readbuild.gradledirectly.
Symptom: App installs fine (pm list packages confirms it), but crashes on launch,
or logcat shows a missing-class error tied to MainActivity.
Step 1 — reproduce and capture logs:
adb logcat -c && adb shell am start -n games.supergoose.path/.MainActivity && adb logcat "*:E"adb logcat -cclears old log buffer so you only see fresh output.am start -n <package>/.MainActivitylaunches the activity directly.logcat "*:E"filters to error-level logs only.
If MainActivity resolves cleanly here, the original missing-class bug is likely
gone — which points back to ProGuard/minification as the root cause (classes
getting stripped or renamed by minify rules without corresponding keep rules).
Step 2 — check ProGuard/minify config if the class-not-found error persists:
- Look at
android/app/proguard-rules.proand confirmminifyEnabledbehavior inbuild.gradle'sreleasebuild type. - Add
-keeprules for any classes referenced via reflection or by the Capacitor bridge that minification might be stripping.
Step 3 — Release signing (separate but related issue):
If bundletool output includes something like:
The APKs will be signed with the debug keystore found at '/Users/<you>/.android/debug.keystore'
this means bundletool couldn't find your real release/upload signing config and
fell back to the debug key. This is fine for local crash-testing, but it means your
bundleRelease build likely does not have proper release signing configured in
android/app/build.gradle. Play Console expects a properly signed release bundle —
fix your signing config (signingConfigs { release { ... } } block, keystore path,
alias, passwords) before your next real upload, even though it isn't the cause of the
launch crash itself.
-
npx cap sync androidrun after any native config change -
./gradlew cleanbefore a fresh release build if behavior seems stale -
applicationId/namespacematch Play Console's registered App ID -
versionCodeincremented since the last upload (any track) - Release build uses your actual signing config, not the debug keystore fallback
- If a class/activity fails to resolve only in release builds, suspect ProGuard/minify rules first