Keep local Gradle signing alongside Oore
How Oore hands the pipeline keystore to Gradle, and what a local key.properties setup needs to keep working.
Oore signs Android builds in Gradle itself, so most apps need no Gradle change. This page explains how, and what to check when the repository also signs release builds on developer machines.
What you need
- Android signing configured for the pipeline.
- A Flutter Android project in the repository’s
androidfolder.
How Oore signs the build
For each flutter build apk or flutter build appbundle command, the runner:
- Writes the pipeline’s keystore to a private folder outside the checkout.
- Adds the Android Gradle plugin’s injected signing properties,
android.injected.signing.store.file,store.password,key.aliasandkey.password, to the workspace’sandroid/gradle.properties. - Runs the command. The Android Gradle plugin signs every variant it builds
with those values, in place of the app’s own
signingConfig. - Restores
android/gradle.propertiesand deletes the keystore copy as soon as the command ends.
These are the properties Android Studio uses for Generate Signed Bundle /
APK, and the ones fastlane’s gradle action passes. After the build, the
android-sign step checks every APK or App Bundle under build/app/outputs.
An artifact Gradle signed with the pipeline key is left as it is. Anything
else is signed again with the pipeline key, so the result is the same either
way.
The build command can read the keystore and its passwords while Gradle runs. Oore does not put them in the step’s environment, its arguments, or the build log.
1. Keep local signing from failing in CI
A local setup that loads key.properties keeps working on developer machines.
In CI the file usually does not exist, so Gradle must still configure without
it. Guard the file read, and do not call file() on a missing path:
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
signingConfigs {
release {
keyAlias keystoreProperties["keyAlias"]
keyPassword keystoreProperties["keyPassword"]
storeFile keystoreProperties["storeFile"] ? file(keystoreProperties["storeFile"]) : null
storePassword keystoreProperties["storePassword"]
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}With this setup the repository does not need to commit key.properties or
the keystore. Adapt the syntax to a Kotlin build.gradle.kts file as needed.
2. Keep secrets out of repository configuration
Do not add keystore content or passwords to .oore.yaml, UI environment
variables, or Gradle source. Do not read OORE_ANDROID_* variables from
Gradle: the runner removes them from build commands.
3. Run one Android variant
Use a supported Flutter APK or App Bundle build command for one variant in the pipeline, then trigger a build.
Verify the result
The build log shows
[oore-signing] Gradle signs this build with the managed keystore before the
build command, and
[oore-signing] Gradle signed 1 Android artifact(s) with the managed key; verified
in the android-sign step. The downloaded artifact passes
apksigner verify --print-certs or keytool -printcert -jarfile, with your
key’s certificate.
Troubleshooting
Gradle fails because key.properties is missing
The Gradle file reads the file or calls file() on its storeFile without
checking that it exists. Guard both as in step 1.
The log says Gradle did not sign with the managed key
The build still succeeds, because the android-sign step signed the output
with the pipeline key. The build does not apply the injected properties, for
example because the repository has no android/gradle.properties project at
its root, the file is a symbolic link, or the Gradle build sets signing in a
way that ignores them.
No Android artifact is found for signing
Confirm the Flutter build command produces an APK under
build/app/outputs or an App Bundle under the corresponding bundle output,
and that the pipeline artifact patterns include it.
The runner reports both debug and release
Separate those commands into different pipeline runs. Managed signing selects one Android signing profile per run.
Next step
Trigger the release build and verify its downloaded artifact.