Agent Skills: Android Keystore Generation

Generate production and local development keystores for Android release signing

UncategorizedID: hitoshura25/claude-devtools/android-keystore-generation

Install this agent skill to your local

pnpm dlx add-skill https://github.com/hitoshura25/claude-devtools/tree/HEAD/skills/android-keystore-generation

Skill Files

Browse the full folder contents for android-keystore-generation.

Download Skill

Loading file tree…

skills/android-keystore-generation/SKILL.md

Skill Metadata

Name
android-keystore-generation
Description
Generate production and local development keystores for Android release signing

Android Keystore Generation

Generates dual keystores for Android release signing: production (CI/CD only) and local development.

Prerequisites

  • JDK installed (keytool command available)
  • Write access to project directory

Inputs

| Input | Required | Default | Description | |-------|----------|---------|-------------| | project_path | Yes | . | Android project root | | organization | Yes | - | Organization name for certificate DN | | country_code | No | US | 2-letter country code |

Process

Organization Name

ALWAYS prompt the user, but provide the auto-detected value as default.

Step 1: Detect organization from package name

# Extract package name from build.gradle.kts
PACKAGE=$(grep "applicationId" app/build.gradle.kts | sed 's/.*"\(.*\)".*/\1/')
echo "Package: $PACKAGE"

# Extract second segment: com.{ORG}.app → ORG
ORG=$(echo $PACKAGE | cut -d. -f2)
echo "Detected organization: $ORG"

Step 2: MANDATORY - Ask the user for confirmation

DO NOT SKIP THIS PROMPT

Ask the user:

"The detected organization name is {ORG}. Press Enter to use this, or type a different name:"

Wait for user response. Use their input if provided, otherwise use the detected default.

Step 3: Store the confirmed organization name

ORGANIZATION="{confirmed_org_name}"
echo "Using organization: $ORGANIZATION"

Why this matters: The organization appears in the certificate's Distinguished Name. While it doesn't affect app functionality, users may want to customize it.

Password Generation Options

Choose one option for keystore passwords:

Option 1 (Recommended): User-Provided Password

Ask the user to provide a password for the production keystore:

"Please enter a password for the production keystore (minimum 12 characters, mix of letters, numbers, and symbols):"

Security benefits:

  • Password never visible to the agent during the conversation
  • User has complete control over password strength and storage
  • Reduces risk of password exposure in logs or conversation history

Instructions for user:

# User will run keytool command manually with their chosen password
# Example:
keytool -genkeypair -v \
  -keystore keystores/production-release.jks \
  -storetype PKCS12 \
  -alias upload \
  -keyalg RSA \
  -keysize 2048 \
  -validity 10000 \
  -storepass "YOUR_PASSWORD_HERE" \
  -keypass "YOUR_PASSWORD_HERE" \
  -dname "CN=Android Release, OU=Android, O={ORGANIZATION}, C=US"

Option 2: Generated Password

If the user prefers a generated password, use the automated generation steps below.

Note: The agent will have access to this password during the session. The password will be stored in temporary files and KEYSTORE_INFO.txt.

"Would you like me to generate a secure password? (The agent will see this password during generation)"

If yes, proceed with the automated generation steps.

Step 1: Create Keystores Directory

mkdir -p keystores

Step 2: Generate Production Keystore

SECURITY: This keystore is for CI/CD only. Never use locally.

⚠️ IMPORTANT: Run each command in a SEPARATE bash call. Do NOT combine commands.

Step 2a: Generate password and save to file

openssl rand -base64 24 | tr -d '/+=' | head -c 24 > /tmp/prod_password.txt

Step 2b: Read and display the password

cat /tmp/prod_password.txt

📝 Copy this password now - you'll need it for the keytool command and KEYSTORE_INFO.txt

Step 2c: Generate the keystore

Replace {PASSWORD} with the password from Step 2b, and {ORGANIZATION} with the confirmed organization name:

keytool -genkeypair -v \
  -keystore keystores/production-release.jks \
  -storetype PKCS12 \
  -alias upload \
  -keyalg RSA \
  -keysize 2048 \
  -validity 10000 \
  -storepass "{PASSWORD}" \
  -keypass "{PASSWORD}" \
  -dname "CN=Android Release, OU=Android, O={ORGANIZATION}, C=US"

If keytool prompts for confirmation, type yes and press Enter.

Step 2d: Verify keystore was created

ls -la keystores/production-release.jks

Expected output:

-rw-------  1 user  staff  2557 Dec 11 10:30 keystores/production-release.jks

Step 3: Generate Local Development Keystore

⚠️ IMPORTANT: Run each command in a SEPARATE bash call. Do NOT combine commands.

Step 3a: Generate password and save to file

openssl rand -base64 24 | tr -d '/+=' | head -c 24 > /tmp/local_password.txt

Step 3b: Read and display the password

cat /tmp/local_password.txt

📝 Copy this password now - you'll need it for the keytool command and KEYSTORE_INFO.txt

Step 3c: Generate the keystore

Replace {PASSWORD} with the password from Step 3b:

keytool -genkeypair -v \
  -keystore keystores/local-dev-release.jks \
  -storetype PKCS12 \
  -alias local-dev \
  -keyalg RSA \
  -keysize 2048 \
  -validity 10000 \
  -storepass "{PASSWORD}" \
  -keypass "{PASSWORD}" \
  -dname "CN=Local Development, OU=Development, O=Local, C=US"

If keytool prompts for confirmation, type yes and press Enter.

Step 3d: Verify keystore was created

ls -la keystores/local-dev-release.jks

Expected output:

-rw-------  1 user  staff  2557 Dec 11 10:30 keystores/local-dev-release.jks

Step 4: Create Credentials File

cat > keystores/KEYSTORE_INFO.txt << EOF
Production Keystore
===================
File: production-release.jks
Alias: upload
Store Password: $PROD_PASSWORD
Key Password: $PROD_PASSWORD (same as store - PKCS12 requirement)

⚠️ SECURITY: CI/CD ONLY - Never use on developer machines

GitHub Secrets:
  SIGNING_KEY_STORE_BASE64: $(base64 -w 0 keystores/production-release.jks 2>/dev/null || base64 -i keystores/production-release.jks)
  SIGNING_KEY_ALIAS: upload
  SIGNING_STORE_PASSWORD: $PROD_PASSWORD
  SIGNING_KEY_PASSWORD: $PROD_PASSWORD

---

Local Development Keystore
==========================
File: local-dev-release.jks
Alias: local-dev
Store Password: $LOCAL_PASSWORD
Key Password: $LOCAL_PASSWORD

Add to ~/.gradle/gradle.properties:
  SIGNING_KEY_STORE_PATH=$(pwd)/keystores/local-dev-release.jks
  SIGNING_KEY_ALIAS=local-dev
  SIGNING_STORE_PASSWORD=$LOCAL_PASSWORD
  SIGNING_KEY_PASSWORD=$LOCAL_PASSWORD
EOF

Step 5: Update .gitignore

# Add to .gitignore if not present
grep -q "keystores/" .gitignore 2>/dev/null || echo "keystores/" >> .gitignore
grep -q "*.jks" .gitignore 2>/dev/null || echo "*.jks" >> .gitignore

Verification

MANDATORY: Run these commands:

# Verify keystores exist
ls -la keystores/*.jks

# Verify credentials documented
cat keystores/KEYSTORE_INFO.txt

# Verify gitignored
grep "keystores" .gitignore

Expected output:

  • Two .jks files in keystores/
  • KEYSTORE_INFO.txt with passwords
  • keystores/ in .gitignore

Outputs

| Output | Location | Description | |--------|----------|-------------| | Production keystore | keystores/production-release.jks | For CI/CD only | | Local keystore | keystores/local-dev-release.jks | For local testing | | Credentials | keystores/KEYSTORE_INFO.txt | Passwords and setup info |

Troubleshooting

"keytool: command not found"

Cause: JDK not installed or not in PATH Fix: Install JDK 17: brew install openjdk@17 (macOS) or apt install openjdk-17-jdk (Linux)

"openssl: command not found"

Cause: OpenSSL not installed Fix: Use alternative password generation: head -c 24 /dev/urandom | base64

Completion Criteria

  • [ ] keystores/production-release.jks exists
  • [ ] keystores/local-dev-release.jks exists
  • [ ] keystores/KEYSTORE_INFO.txt exists with passwords
  • [ ] keystores/ is in .gitignore