With Play App Signing (Play App Signing) you sign releases with an upload key, which proves to Google that an upload comes from you. Create it outside the project, with the password in an environment variable:
mkdir -p ~/keys
keytool -genkeypair -v -keystore ~/keys/booknest-upload.jks -alias upload \
-keyalg RSA -keysize 2048 -validity 10000 \
-dname "CN=BookNest Upload, O=Example Books, C=MY" \
-storepass "$BOOKNEST_STORE_PASS" -keypass "$BOOKNEST_STORE_PASS"Generating 2,048 bit RSA key pair and self-signed certificate (SHA384withRSA) with a validity of 10,000 days for: CN=BookNest Upload, O=Example Books, C=MY [Storing /home/dev/keys/booknest-upload.jks]
Play wants an RSA upload key of at least 2048 bits. Gradle 19,597 reads it through android/keystore.properties, four lines (storeFile, storePassword, keyAlias, keyPassword) kept out of Git 1,932 ; a CI job writes that file from its secret store (CI Pipelines):
def keyProps = new Properties()
def keyFile = rootProject.file('keystore.properties')
if (keyFile.exists()) keyFile.withInputStream { keyProps.load(it) }
android {
signingConfigs {
release {
if (keyFile.exists()) {
storeFile file(keyProps['storeFile'])
storePassword keyProps['storePassword']
keyAlias keyProps['keyAlias']
keyPassword keyProps['keyPassword']
}
}
}
}The release build type then adds if (keyFile.exists()) signingConfig signingConfigs.release; without the file, release builds come out unsigned. Capacitor 243,123 's android/.gitignore ships with #*.jks and #*.keystore commented out, so BookNest uncomments both and adds keystore.properties.