Build Release APK #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build Release APK | |
| concurrency: | |
| group: android-release-${{ github.ref }} | |
| cancel-in-progress: true | |
| on: | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| build-release-apk: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| env: | |
| ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} | |
| ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} | |
| ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} | |
| ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Java | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Validate signing secrets | |
| run: | | |
| for key in ANDROID_KEYSTORE_BASE64 ANDROID_KEYSTORE_PASSWORD ANDROID_KEY_ALIAS ANDROID_KEY_PASSWORD; do | |
| if [ -z "${!key}" ]; then | |
| echo "Missing required secret: $key" | |
| exit 1 | |
| fi | |
| done | |
| - name: Prepare signing keystore | |
| run: | | |
| mkdir -p android/app/keystore | |
| echo "$ANDROID_KEYSTORE_BASE64" | base64 --decode > android/app/keystore/release.jks | |
| test -s android/app/keystore/release.jks || { | |
| echo "Failed to generate release keystore" | |
| exit 1 | |
| } | |
| - name: Validate keystore credentials | |
| run: | | |
| keytool -list \ | |
| -keystore android/app/keystore/release.jks \ | |
| -storepass "$ANDROID_KEYSTORE_PASSWORD" \ | |
| -alias "$ANDROID_KEY_ALIAS" \ | |
| -keypass "$ANDROID_KEY_PASSWORD" >/dev/null | |
| - name: Build release APK | |
| working-directory: android | |
| env: | |
| RELEASE_STORE_FILE: keystore/release.jks | |
| RELEASE_STORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} | |
| RELEASE_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} | |
| RELEASE_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} | |
| run: | | |
| chmod +x gradlew | |
| ./gradlew --no-daemon --console=plain --stacktrace :app:assembleRelease | |
| - name: Normalize APK artifact | |
| run: | | |
| apk_path=$(find android/app/build/outputs/apk/release -name '*.apk' | head -n 1) | |
| test -n "$apk_path" || { | |
| echo "Release APK not found"; | |
| exit 1; | |
| } | |
| cp "$apk_path" app-release.apk | |
| - name: Verify APK signature | |
| run: | | |
| apksigner_bin=$(find "${ANDROID_HOME}/build-tools" -type f -name apksigner | sort | tail -n 1) | |
| test -n "$apksigner_bin" || { | |
| echo "apksigner not found in Android SDK build-tools" | |
| exit 1 | |
| } | |
| "$apksigner_bin" verify --verbose app-release.apk | |
| - name: Upload APK artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: android-release-apk | |
| path: app-release.apk | |
| - name: Cleanup signing keystore | |
| if: always() | |
| run: rm -f android/app/keystore/release.jks | |
| - name: Read Android version | |
| id: android-version | |
| run: | | |
| version_name=$(sed -n 's/.*versionName = "\([^"]*\)"/\1/p' android/app/build.gradle.kts | head -n 1) | |
| version_code=$(sed -n 's/.*versionCode = \([0-9][0-9]*\).*/\1/p' android/app/build.gradle.kts | head -n 1) | |
| test -n "$version_name" || { | |
| echo "Unable to determine Android versionName"; | |
| exit 1; | |
| } | |
| test -n "$version_code" || { | |
| echo "Unable to determine Android versionCode"; | |
| exit 1; | |
| } | |
| echo "version_name=$version_name" >> "$GITHUB_OUTPUT" | |
| echo "version_code=$version_code" >> "$GITHUB_OUTPUT" | |
| - name: Create GitHub release | |
| if: github.ref == 'refs/heads/main' | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: android-v${{ steps.android-version.outputs.version_name }} | |
| name: Android Release v${{ steps.android-version.outputs.version_name }} | |
| files: app-release.apk | |
| generate_release_notes: true | |
| append_body: true | |
| body: | | |
| Android versionCode: ${{ steps.android-version.outputs.version_code }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |