# Compila o APK do Android no GitHub e o devolve como artefato. # # O runner entra só como máquina de build, pelo mesmo motivo do desktop: a VPS # tem ~2 GB de RAM livres e roda a produção, então um Gradle com o SDK do # Android ali dentro arrisca derrubar as chamadas de quem está usando o app. # # O APK sai **sem assinatura**. A chave de assinatura fica na VPS e não sobe # para cá: quem assina é /opt/ops/release-android.sh, depois de baixar este # artefato. Um APK assinado é instalável por qualquer um, e a chave é o que # prova que uma atualização veio de nós — ela não tem por que existir em duas # máquinas. name: Android APK on: workflow_dispatch: push: tags: ['android-v*'] permissions: contents: read jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Setup Java uses: actions/setup-java@v4 with: distribution: temurin java-version: '21' # cache/cache-dependency-path apontando para o npm deste pacote não é só # otimização: sem eles o setup-node lê o campo `packageManager` do # package.json da raiz, tenta usar pnpm — que este workflow não instala — # e falha antes de rodar qualquer coisa. - name: Setup Node.js uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: node-version: 22 cache: npm cache-dependency-path: packages/mobile/package-lock.json # npm, não pnpm: packages/mobile fica fora do workspace de propósito # (ver pnpm-workspace.yaml). Ele tem o próprio package-lock.json. - name: Install Capacitor working-directory: packages/mobile run: npm ci # Copia a config e os arquivos de public/ para dentro do projeto nativo. # Sem isso o APK sai com o que estiver commitado em assets/, que pode # estar velho — esses arquivos são gerados, não versionados. - name: Sync Capacitor working-directory: packages/mobile run: npx cap sync android - name: Cache Gradle uses: actions/cache@v4 with: path: | ~/.gradle/caches ~/.gradle/wrapper key: gradle-${{ hashFiles('packages/mobile/android/**/*.gradle', 'packages/mobile/android/gradle/wrapper/gradle-wrapper.properties') }} restore-keys: gradle- - name: Build unsigned release APK working-directory: packages/mobile/android run: ./gradlew assembleRelease --no-daemon --stacktrace # O nome do arquivo muda conforme a versão do AGP (app-release-unsigned.apk # ou app-release.apk quando não há config de assinatura). Localiza em vez # de supor, e falha alto se nada saiu — um artefato vazio só apareceria # como erro lá na frente, na hora de assinar. - name: Collect APK run: | set -euo pipefail mkdir -p out found=$(find packages/mobile/android/app/build/outputs/apk/release -name '*.apk' | head -1) [ -n "$found" ] || { echo "::error::o build não produziu APK nenhum"; exit 1; } cp "$found" out/resenhacord-unsigned.apk ls -l out/ - name: Upload APK artifact uses: actions/upload-artifact@v4 with: name: resenhacord-apk-unsigned path: out/resenhacord-unsigned.apk retention-days: 14 if-no-files-found: error