|
| 1 | +# Android APK Signing Guide |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +Android requires all APKs to be signed before they can be installed on devices. This repository supports both **debug signing** (for development/testing) and **release signing** (for production releases). |
| 6 | + |
| 7 | +## CI/PR Builds (Debug Signing) |
| 8 | + |
| 9 | +PR builds in the `ci.yml` workflow automatically sign APKs with a **debug keystore**. These are suitable for: |
| 10 | +- Testing on development devices |
| 11 | +- Internal QA |
| 12 | +- Feature validation |
| 13 | + |
| 14 | +The debug-signed APKs can be downloaded from the PR's workflow artifacts and installed on any Android device with developer mode enabled. |
| 15 | + |
| 16 | +## Release Builds (Production Signing) |
| 17 | + |
| 18 | +For production releases via the `release.yml` workflow, you should configure a **release keystore** using GitHub Secrets. |
| 19 | + |
| 20 | +### Creating a Release Keystore |
| 21 | + |
| 22 | +If you don't already have a release keystore, create one: |
| 23 | + |
| 24 | +```bash |
| 25 | +keytool -genkeypair -v \ |
| 26 | + -keystore betaflight-release.keystore \ |
| 27 | + -storepass <YOUR_STORE_PASSWORD> \ |
| 28 | + -alias betaflight \ |
| 29 | + -keypass <YOUR_KEY_PASSWORD> \ |
| 30 | + -keyalg RSA \ |
| 31 | + -keysize 2048 \ |
| 32 | + -validity 10000 \ |
| 33 | + -dname "CN=Betaflight,O=Betaflight,C=US" |
| 34 | +``` |
| 35 | + |
| 36 | +**⚠️ IMPORTANT**: Keep this keystore file and passwords secure. If you lose them, you cannot update your app on the Play Store! |
| 37 | + |
| 38 | +### Configure GitHub Secrets |
| 39 | + |
| 40 | +Add the following secrets to your GitHub repository (Settings → Secrets and variables → Actions): |
| 41 | + |
| 42 | +1. **ANDROID_KEYSTORE_BASE64** |
| 43 | + ```bash |
| 44 | + base64 -w 0 betaflight-release.keystore |
| 45 | + ``` |
| 46 | + Copy the output and paste it as the secret value. |
| 47 | + |
| 48 | +2. **ANDROID_KEYSTORE_PASSWORD** |
| 49 | + The password you used for `-storepass` when creating the keystore. |
| 50 | + |
| 51 | +3. **ANDROID_KEY_ALIAS** |
| 52 | + The alias you used (e.g., `betaflight`). |
| 53 | + |
| 54 | +4. **ANDROID_KEY_PASSWORD** |
| 55 | + The password you used for `-keypass` when creating the keystore. |
| 56 | + |
| 57 | +### How Release Signing Works |
| 58 | + |
| 59 | +When you trigger a release build: |
| 60 | + |
| 61 | +1. If **all four secrets are configured**, the workflow will: |
| 62 | + - Decode the base64 keystore |
| 63 | + - Sign both the APK and AAB with your release key |
| 64 | + - Upload signed artifacts with `-release-signed` suffix |
| 65 | + |
| 66 | +2. If **secrets are NOT configured**, the workflow will: |
| 67 | + - Fall back to debug signing |
| 68 | + - Upload APKs with `-debug-signed` suffix |
| 69 | + - ⚠️ These cannot be uploaded to the Play Store! |
| 70 | + |
| 71 | +## Verifying Signed APKs |
| 72 | + |
| 73 | +To verify an APK signature: |
| 74 | + |
| 75 | +```bash |
| 76 | +# Check signature |
| 77 | +jarsigner -verify -verbose -certs your-app.apk |
| 78 | + |
| 79 | +# View certificate details |
| 80 | +keytool -printcert -jarfile your-app.apk |
| 81 | +``` |
| 82 | + |
| 83 | +For release APKs, the certificate should match your release keystore. |
| 84 | +For debug APKs, the certificate will show "CN=Android Debug". |
| 85 | + |
| 86 | +## Installing Signed APKs |
| 87 | + |
| 88 | +### Debug-signed APKs |
| 89 | +- Enable "Install from unknown sources" or "Install unknown apps" on your Android device |
| 90 | +- Download the APK from GitHub Actions artifacts |
| 91 | +- Install via file manager or `adb install path/to/app.apk` |
| 92 | + |
| 93 | +### Release-signed APKs |
| 94 | +- Can be installed the same way as debug APKs |
| 95 | +- Can be uploaded to Google Play Store for distribution |
| 96 | +- Must be signed with the same keystore for app updates |
| 97 | + |
| 98 | +## Security Best Practices |
| 99 | + |
| 100 | +1. **Never commit keystores to the repository** |
| 101 | +2. **Keep keystore passwords in GitHub Secrets only** |
| 102 | +3. **Back up your release keystore securely** (preferably in multiple secure locations) |
| 103 | +4. **Use strong passwords** for both keystore and key alias |
| 104 | +5. **Limit access** to GitHub Secrets to trusted maintainers only |
| 105 | + |
| 106 | +## Troubleshooting |
| 107 | + |
| 108 | +### "APK not signed" error during installation |
| 109 | +- The APK must be signed (either debug or release) |
| 110 | +- Check workflow logs to ensure signing step completed successfully |
| 111 | + |
| 112 | +### "App not installed" or "Package conflicts" error |
| 113 | +- You may have an existing version signed with a different key |
| 114 | +- Uninstall the old version first, then install the new APK |
| 115 | + |
| 116 | +### Release workflow falls back to debug signing |
| 117 | +- Check that all four GitHub Secrets are configured correctly |
| 118 | +- Verify the base64-encoded keystore is valid: `echo "$SECRET" | base64 -d > test.keystore` |
| 119 | +- Check workflow logs for any error messages in the "Setup release keystore" step |
0 commit comments