fix: raise the android versionCode with every release

`versionCode` was hard-coded to 1, so every release looked like the
same version to Android. It is now derived from `VERSION` as
`major * 10000000 + minor * 10000 + patch` (0.1.62 gives 10062), which
is above the 1 existing installs have and keeps growing, so Android
never mistakes an update for a downgrade.

The formula only increases while patch stays below 10000 and minor
below 1000. `build.gradle` refuses a `VERSION` outside that range or
outside Android's 2100000000 ceiling, and `scripts/bump-version.mjs`,
which only ever bumps patch, refuses to create such a version before
anything is committed or tagged.
This commit is contained in:
Linus Rath
2026-09-24 18:52:15 +02:00
parent 6f0abb4384
commit 746572c784
2 changed files with 35 additions and 1 deletions
+26 -1
View File
@@ -7,6 +7,31 @@ def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
def appVersionName = file("${projectRoot}/VERSION").text.trim()
/**
* versionCode has to grow with every release, or Android refuses the update as
* a downgrade. It is derived from VERSION as
*
* major * 10000000 + minor * 10000 + patch (0.1.62 -> 10062)
*
* which keeps increasing as long as patch stays below 10000 and minor below
* 1000 (scripts/bump-version.mjs, which only ever bumps patch, enforces both),
* and stays under Android's 2100000000 ceiling up to major 209.
*/
def versionParts = (appVersionName =~ /^(\d+)\.(\d+)\.(\d+)$/)
if (!versionParts.matches()) {
throw new GradleException("VERSION must be MAJOR.MINOR.PATCH, got '${appVersionName}'")
}
def (versionMajor, versionMinor, versionPatch) = (1..3).collect { versionParts.group(it) as long }
if (versionMinor > 999 || versionPatch > 9999) {
throw new GradleException("VERSION ${appVersionName}: minor must stay below 1000 and patch below 10000, " +
"or versionCode stops increasing. Move to the next minor or major version instead.")
}
def appVersionCode = versionMajor * 10000000L + versionMinor * 10000L + versionPatch
if (appVersionCode < 1 || appVersionCode > 2100000000L) {
throw new GradleException("VERSION ${appVersionName} gives versionCode ${appVersionCode}, " +
"outside the 1..2100000000 range Android accepts.")
}
/**
* Release signing. The key never lives in the repo: CI passes it as
* ORG_GRADLE_PROJECT_BULWARK_RELEASE_* environment variables, and a local
@@ -126,7 +151,7 @@ android {
applicationId 'com.anonymous.bulwarkmobile'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionCode appVersionCode.toInteger()
versionName appVersionName
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
+9
View File
@@ -42,6 +42,15 @@ if (parts.length !== 3 || parts.some(Number.isNaN)) {
parts[2] += 1;
const next = parts.join('.');
// android/app/build.gradle derives versionCode as
// major * 10000000 + minor * 10000 + patch. Past these limits it would stop
// increasing, and Android refuses an update with a lower versionCode.
if (parts[1] > 999 || parts[2] > 9999) {
console.error(`${next} would break the Android versionCode: minor must stay below 1000 and patch below 10000.`);
console.error('Raise the minor or major version in VERSION by hand and commit it, then bump again.');
process.exit(1);
}
const existingTags = new Set(git('tag', '--list').split(/\r?\n/).filter(Boolean));
if (existingTags.has(next)) {
console.error(`Tag ${next} already exists.`);