feat: a release script for the APK and the snap
All checks were successful
CI / check (push) Successful in 9m8s
CI / deploy (push) Successful in 1m5s

tool/release.sh builds a release on the maintainer's laptop: one APK for
every phone, from a checkout of the signed tag and signed with the app's
own key, and the snap, both connecting to learn.halkyon.eu, the project's
instance; their checksums signed with GPG; the release on code.halkyon.app
through Forgejo's API, and the snap in the Store's edge channel.

Before building it checks that main is clean and pushed, that the tag is
signed by a key deploys accept, the version and a raised build number,
the pinned Flutter, and that the keystore holds the key whose certificate
tool/release/android-certificate.sha256 names. After building it checks
the APK's signer, package, version, that it isn't debuggable and that it
names the server, and the snap's version. The key's password and the
Forgejo token are asked for at each run and never stored.

Release builds take the app's key from the environment and otherwise fall
back to the debug key, so `flutter run --release` works anywhere. The
native libraries go into the APK compressed: an APK for three
architectures was 110 MB with them stored as they are, 48 MB now. The
list of dependencies Gradle adds for Google Play is left out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-05 12:55:39 +02:00
commit 88b82cda4b
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -28,13 +28,48 @@ android {
versionName = flutter.versionName
}
// The app's own key signs release builds when tool/release.sh hands it over
// through the environment: the keystore's path and the key's alias, and the
// password asked for at each release, never written down. Other release builds
// are signed with the debug key, so `flutter run --release` works anywhere; the
// release script refuses to build without the app's key.
val releaseKeystore = System.getenv("HALKYON_ANDROID_KEYSTORE")
signingConfigs {
if (releaseKeystore != null) {
create("release") {
storeFile = file(releaseKeystore)
keyAlias = System.getenv("HALKYON_ANDROID_KEY_ALIAS")
// A PKCS #12 keystore has one password, for the store and its key.
storePassword = System.getenv("HALKYON_ANDROID_KEYSTORE_PASSWORD")
keyPassword = System.getenv("HALKYON_ANDROID_KEYSTORE_PASSWORD")
}
}
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
signingConfig =
signingConfigs.findByName("release") ?: signingConfigs.getByName("debug")
}
}
// The native libraries go into the APK compressed. One APK serves every phone, so
// it holds them for three architectures; stored uncompressed (the default, made
// for stores that send each phone its own) they made it 110 MB to download and to
// keep. Compressed it's about half that, and Android unpacks the phone's own
// libraries as it installs the app.
packaging {
jniLibs {
useLegacyPackaging = true
}
}
// Leaves out the list of dependencies Gradle would otherwise add to the APK,
// encrypted for Google Play alone; F-Droid's and others' scanners flag it.
dependenciesInfo {
includeInApk = false
includeInBundle = false
}
}
kotlin {