Skip to content

Android release

Android release #6

name: Android release
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: Existing release tag to rebuild
required: true
type: string
permissions:
contents: write
concurrency:
group: android-release-${{ github.event.release.id || inputs.tag }}
cancel-in-progress: false
jobs:
build-apk:
name: Build signed APK
runs-on: ubuntu-24.04
timeout-minutes: 30
env:
PULSE_RELEASE_TAG: ${{ github.event.release.tag_name || inputs.tag }}
steps:
- name: Check out release
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
ref: ${{ github.event.release.tag_name || inputs.tag }}
- name: Pin web build version
shell: bash
run: |
if ! grep -q 'version:' svelte.config.js; then
perl -0pi -e 's/adapter: adapter\(\),/adapter: adapter(),\n version: { name: "$ENV{PULSE_RELEASE_TAG}" },/' svelte.config.js
fi
- name: Set up Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.13
- name: Set up Node
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 22
package-manager-cache: false
- name: Set up Java
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: 21
- name: Set up Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6
with:
cache-provider: basic
- name: Validate release source
run: bun run release:check "$PULSE_RELEASE_TAG"
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Verify web app
run: bun run verify
- name: Sync Android app
run: bun run mobile:sync
- name: Build release APK
working-directory: android
run: ./gradlew assembleRelease --no-daemon
- name: Install reproducible signing tools
run: |
"$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "build-tools;34.0.0"
- name: Sign and verify APK
id: sign
env:
PULSE_ANDROID_KEYSTORE_BASE64: ${{ secrets.PULSE_ANDROID_KEYSTORE_BASE64 }}
PULSE_ANDROID_KEYSTORE_PASSWORD: ${{ secrets.PULSE_ANDROID_KEYSTORE_PASSWORD }}
run: |
test -n "$PULSE_ANDROID_KEYSTORE_BASE64"
test -n "$PULSE_ANDROID_KEYSTORE_PASSWORD"
keystore="$RUNNER_TEMP/pulse-release.p12"
printf '%s' "$PULSE_ANDROID_KEYSTORE_BASE64" | base64 --decode > "$keystore"
safe_tag="${PULSE_RELEASE_TAG//\//-}"
apk="$RUNNER_TEMP/Pulse-$safe_tag.apk"
unsigned_apk="android/app/build/outputs/apk/release/app-release-unsigned.apk"
align_tools="$ANDROID_HOME/build-tools/36.0.0"
sign_tools="$ANDROID_HOME/build-tools/34.0.0"
"$align_tools/zipalign" -f -p 4 "$unsigned_apk" "$apk"
"$sign_tools/apksigner" sign \
--ks "$keystore" \
--ks-type PKCS12 \
--ks-key-alias pulse \
--ks-pass env:PULSE_ANDROID_KEYSTORE_PASSWORD \
--key-pass env:PULSE_ANDROID_KEYSTORE_PASSWORD \
"$apk"
"$sign_tools/apksigner" verify --verbose --print-certs "$apk"
echo "apk=$apk" >> "$GITHUB_OUTPUT"
- name: Attach APK to release
env:
GH_TOKEN: ${{ github.token }}
APK_PATH: ${{ steps.sign.outputs.apk }}
run: gh release upload "$PULSE_RELEASE_TAG" "$APK_PATH" --clobber