gplay-signing-setup
Android app signing, keystores, and Play App Signing setup. Use when configuring signing for new apps or migrating to Play App Signing.
Works with
---
name: gplay-signing-setup
description: Android app signing, keystores, and Play App Signing setup. Use when configuring signing for new apps or migrating to Play App Signing.
license: MIT
---
# Android App Signing Setup
Use this skill when you need to set up or manage app signing for Google Play.
## Understanding Android App Signing
Android apps must be signed with a certificate before upload. Two signing approaches:
1. **App Signing by Google Play** (Recommended) - Google manages your signing key
2. **Manual Signing** (Legacy) - You manage your signing key
## Create a New Keystore
### Generate keystore
```bash
keytool -genkey -v \
-keystore release.keystore \
-alias my-app-key \
-keyalg RSA \
-keysize 2048 \
-validity 10000
```
**You'll be prompted for:**
- Keystore password (store securely!)
- Key password (can be same as keystore password)
- Your name/organization details
### Keystore file location
- **Development**: Keep locally, never commit to git
- **Production**: Store in secure location (password manager, secrets vault)
- **CI/CD**: Use encrypted secrets
## Configure Gradle Signing
### gradle.properties (gitignored)
```properties
KEYSTORE_FILE=/path/to/release.keystore
KEYSTORE_PASSWORD=your_keystore_password
KEY_ALIAS=my-app-key
KEY_PASSWORD=your_key_password
```
### app/build.gradle
```groovy
android {
signingConfigs {
release {
storeFile file(project.property('KEYSTORE_FILE'))
storePassword project.property('KEYSTORE_PASSWORD')
keyAlias project.property('KEY_ALIAS')
keyPassword project.property('KEY_PASSWORD')
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
```
### Using environment variables (CI/CD)
```groovy
android {
signingConfigs {
release {
storeFile file(System.getenv("KEYSTORE_FILE") ?: "release.keystore")
storePassword System.getenv("KEYSTORE_PASSWORD")
keyAlias System.getenv("KEY_ALIAS")
keyPassword System.getenv("KEY_PASSWORD")
}
}
}
```
## Play App Signing Setup
### Enable Play App Signing (New App)
1. **Build and sign AAB** with upload key:
```bash
./gradlew bundleRelease
```
2. **Upload AAB** to Play Console:
```bash
gplay release \
--package com.example.app \
--track internal \
--bundle app-release.aab
```
3. **Google Play generates app signing key** automatically
4. **Download upload certificate**:
- Go to Play Console → App → Setup → App signing
- Download "Upload certificate" (will be used for future uploads)
### Migrate Existing App to Play App Signing
If your app uses manual signing:
1. **Export upload key**:
```bash
keytool -export -rfc \
-keystore release.keystore \
-alias my-app-key \
-file upload_cert.pem
```
2. **Encrypt private key** (required by Google):
```bash
# Generate password for encryption
openssl rand -base64 32 > encryption_password.txt
# Export and encrypt private key
keytool -importkeystore \
-srckeystore release.keystore \
-destkeystore encrypted.p12 \
-deststoretype PKCS12 \
-srcalias my-app-key \
-deststorepass $(cat encryption_password.txt)
```
3. **Upload to Play Console**:
- Go to Play Console → App → Setup → App signing
- Choose "Export and upload a key"
- Upload encrypted.p12 and encryption_password.txt
4. **Download new upload key**:
- After migration, download new upload certificate
- Use this for all future uploads
## Verify Keystore
### List keys in keystore
```bash
keytool -list -v -keystore release.keystore
```
### Check certificate validity
```bash
keytool -list -v \
-keystore release.keystore \
-alias my-app-key \
| grep Valid
```
### Extract certificate fingerprint
```bash
# SHA-256 (for Firebase, etc.)
keytool -list -v \
-keystore release.keystore \
-alias my-app-key \
| grep SHA256
```
## Verify APK/AAB Signature
### Check AAB signature
```bash
jarsigner -verify -verbose -certs app-release.aab
```
### Check APK signature
```bash
jarsigner -verify -verbose -certs app-release.apk
```
## CI/CD Signing
### GitHub Actions Example
```yaml
- name: Decode keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > release.keystore
- name: Build signed AAB
env:
KEYSTORE_FILE: release.keystore
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: |
./gradlew bundleRelease
- name: Clean up keystore
if: always()
run: rm -f release.keystore
```
### Store keystore as base64
```bash
# Encode keystore to base64
base64 -i release.keystore -o keystore_base64.txt
# Add to GitHub Secrets as KEYSTORE_BASE64
```
## Upload Certificate Management
### Register upload certificate for existing app
If you lose your upload key:
1. **Generate new keystore** (as shown above)
2. **Export certificate**:
```bash
keytool -export -rfc \
-keystore new-upload.keystore \
-alias my-app-key \
-file new_upload_cert.pem
```
3. **Contact Google Play support** to reset upload key:
- Go to Play Console → Help
- Request upload certificate reset
- Provide new_upload_cert.pem
## Security Best Practices
### DO:
- ✅ Use strong passwords (16+ characters)
- ✅ Store keystore in multiple secure locations
- ✅ Use different keys for different apps
- ✅ Enable Play App Signing
- ✅ Keep upload key separate from production
- ✅ Document key details securely (not passwords!)
- ✅ Set calendar reminder for key expiration (10-25 years)
### DON'T:
- ❌ Commit keystores to git
- ❌ Share keystores via email/chat
- ❌ Use weak or obvious passwords
- ❌ Store passwords in code
- ❌ Forget to backup keystores
- ❌ Use same key for debug and release
## Keystore Backup Strategy
### What to backup:
1. Keystore file (`release.keystore`)
2. Key alias name
3. Keystore password (in password manager)
4. Key password (in password manager)
### Where to backup:
- Password manager (1Password, LastPass, etc.)
- Encrypted cloud storage
- Company secrets vault
- Physical secure storage (for enterprise)
### Test restore process:
```bash
# Verify you can use the backup
keytool -list -v -keystore backup/release.keystore
```
## Troubleshooting
### "jarsigner: unable to sign jar"
- Check keystore password is correct
- Verify keystore file path
- Ensure keystore alias exists
### "Failed to read key from keystore"
- Key alias might be wrong
- Key password might be wrong
- Keystore might be corrupted
### "Upload certificate doesn't match"
- You're using wrong keystore
- Keystore was regenerated (contact support)
- Using app signing key instead of upload key
### Lost keystore?
- If using Play App Signing: Contact Google to reset upload key
- If not using Play App Signing: Cannot recover, must publish new app
## Multiple Apps, Multiple Keys
### Organize multiple keystores
```
~/keystores/
├── app1-release.keystore
├── app2-release.keystore
└── app3-release.keystore
```
### Use different gradle.properties per app
```properties
# app1/gradle.properties
KEYSTORE_FILE=~/keystores/app1-release.keystore
KEY_ALIAS=app1-key
# app2/gradle.properties
KEYSTORE_FILE=~/keystores/app2-release.keystore
KEY_ALIAS=app2-key
```
## Key Rotation
Android apps are typically signed with long-lived keys (10-25 years), but if you need to rotate:
1. **Only possible with Play App Signing enabled**
2. **Contact Google Play Support** to rotate app signing key
3. **Upload new upload certificate** when prompted
4. **All future builds** must use new upload key
## Documentation Template
Keep this info in your password manager:
```
App Name: My Awesome App
Package: com.example.app
Keystore File: release.keystore (backed up in Dropbox)
Keystore Password: [IN PASSWORD MANAGER]
Key Alias: my-app-key
Key Password: [IN PASSWORD MANAGER]
Certificate Validity: Valid until 2035-02-05
SHA-256 Fingerprint: AB:CD:EF:12:...
Play App Signing: Enabled
Notes: Upload key only, Google manages app signing key
```More Mobile skills
animation-vocabulary
emilkowalski/skills
Reverse-lookup glossary that turns a vague description of a web animation or motion effect into its exact term ("the bouncy thing when a popover opens" → Pop in; "the iOS rubber-band scroll" → Rubber-banding). Use when the user asks "what's it called when…", or describes a motion effect without knowing its name and wants the right word to prompt an AI or designer with. For naming an effect, not designing or building one.
xcode-project-setup
firebase/agent-skills
Safely modifies Xcode projects (.pbxproj) to add Swift Packages and link files. Use this skill whenever an iOS project needs dependencies installed (e.g. Firebase, Alamofire).
cross-border-ecommerce
nexscope-ai/ecommerce-skills
Cross-border e-commerce expansion advisor. Scores target markets on 8 weighted dimensions (market size, ecommerce penetration, competition, regulatory complexity, logistics infrastructure, payment ecosystem, cultural distance, IP protection), compares 5 fulfillment models with cost and transit data, provides country-by-country tax/duty compliance guides (EU VAT/IOSS, UK VAT, US sales tax, CA GST, AU GST, JP consumption tax), maps local payment preferences by market, and builds a phased expansion roadmap. No API key required.

