Skip to content

Capacitor Android Build #12

Capacitor Android Build

Capacitor Android Build #12

name: Capacitor Android Build
on:
workflow_dispatch:
inputs:
build_type:
description: Android build type
required: true
default: debug
type: choice
options:
- debug
- release
release_to_google_play:
description: Release the signed AAB to Google Play internal track
required: true
default: false
type: boolean
concurrency:
group: capacitor-android-build-${{ github.ref }}-${{ inputs.build_type }}-${{ inputs.release_to_google_play }}
cancel-in-progress: false
jobs:
build:
name: Build Android ${{ inputs.build_type }}
runs-on: ubuntu-latest
permissions:
contents: write
env:
ANDROID_BUILD_TOOLS_VERSION: 36.0.0
PLAY_PACKAGE_NAME: me.payky
PLAY_TRACK: internal
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Install Android SDK packages
run: |
sdkmanager \
"platform-tools" \
"platforms;android-36" \
"build-tools;${ANDROID_BUILD_TOOLS_VERSION}"
- name: Configure Android SDK environment
run: |
echo "ANDROID_SDK_ROOT=${ANDROID_HOME}" >> "${GITHUB_ENV}"
echo "${ANDROID_HOME}/build-tools/${ANDROID_BUILD_TOOLS_VERSION}" >> "${GITHUB_PATH}"
- name: Cache Bun dependencies
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Cache Gradle dependencies
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-capacitor-${{ hashFiles('android/**/*.gradle*', 'android/gradle/wrapper/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-capacitor-
${{ runner.os }}-gradle-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Validate Google Play release inputs
if: ${{ inputs.release_to_google_play }}
run: |
if [[ "${{ inputs.build_type }}" != "release" ]]; then
echo "::error::Google Play releases require build_type to be release."
exit 1
fi
- name: Validate release signing secrets
if: ${{ inputs.build_type == 'release' }}
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 }}
run: |
if [[ -z "${ANDROID_KEYSTORE_BASE64}" || -z "${ANDROID_KEYSTORE_PASSWORD}" || -z "${ANDROID_KEY_ALIAS}" || -z "${ANDROID_KEY_PASSWORD}" ]]; then
echo "::error::Release builds require ANDROID_KEYSTORE_BASE64, ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS, and ANDROID_KEY_PASSWORD secrets."
exit 1
fi
- name: Validate Google Play release secrets
if: ${{ inputs.release_to_google_play }}
env:
GOOGLE_PLAY_SERVICE_ACCOUNT_JSON: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }}
run: |
if [[ -z "${GOOGLE_PLAY_SERVICE_ACCOUNT_JSON}" ]]; then
echo "::error::Google Play releases require the GOOGLE_PLAY_SERVICE_ACCOUNT_JSON secret."
exit 1
fi
- name: Build debug Android app
if: ${{ inputs.build_type == 'debug' }}
run: |
bun run cap:android:sync
cd android
./gradlew assembleDebug bundleDebug
- name: Decode release keystore
if: ${{ inputs.build_type == 'release' }}
env:
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
run: |
printf '%s' "${ANDROID_KEYSTORE_BASE64}" | base64 --decode > payky-release.keystore
- name: Set Google Play build version code
if: ${{ inputs.release_to_google_play }}
run: |
perl -0pi -e "s/versionCode\s+\d+/versionCode ${GITHUB_RUN_NUMBER}/" android/app/build.gradle
- name: Build release Android app
if: ${{ inputs.build_type == 'release' }}
env:
PAYKY_ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
PAYKY_ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
PAYKY_ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
run: |
bun run cap:android:sync
bun cap build android --androidreleasetype APK --signing-type apksigner --keystorepath ../payky-release.keystore --keystorepass "${PAYKY_ANDROID_KEYSTORE_PASSWORD}" --keystorealias "${PAYKY_ANDROID_KEY_ALIAS}" --keystorealiaspass "${PAYKY_ANDROID_KEY_PASSWORD}"
bun cap build android --androidreleasetype AAB --keystorepath ../payky-release.keystore --keystorepass "${PAYKY_ANDROID_KEYSTORE_PASSWORD}" --keystorealias "${PAYKY_ANDROID_KEY_ALIAS}" --keystorealiaspass "${PAYKY_ANDROID_KEY_PASSWORD}"
- name: Upload debug Android artifacts
if: ${{ inputs.build_type == 'debug' }}
uses: actions/upload-artifact@v4
with:
name: payky-capacitor-android-debug
path: |
android/app/build/outputs/apk/**/*.apk
android/app/build/outputs/bundle/**/*.aab
if-no-files-found: error
- name: Upload release Android artifacts
if: ${{ inputs.build_type == 'release' }}
uses: actions/upload-artifact@v4
with:
name: payky-capacitor-android-release
path: |
android/app/build/outputs/apk/**/*.apk
android/app/build/outputs/bundle/**/*.aab
if-no-files-found: error
- name: Release to Google Play internal track
if: ${{ inputs.release_to_google_play }}
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }}
packageName: ${{ env.PLAY_PACKAGE_NAME }}
releaseFiles: android/app/build/outputs/bundle/**/*-signed.aab
tracks: ${{ env.PLAY_TRACK }}
status: completed
- name: Create canary release
if: ${{ inputs.build_type == 'release' }}
uses: softprops/action-gh-release@v2
with:
tag_name: canary-${{ github.run_number }}
target_commitish: ${{ github.sha }}
name: Payky Canary ${{ github.run_number }}
body: |
Canary Android build from `${{ github.sha }}` on `${{ github.ref_name }}`.
Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
prerelease: true
make_latest: false
files: |
android/app/build/outputs/apk/**/*.apk
fail_on_unmatched_files: true