Publish to Google Play #3
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: Publish to Google Play | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| inputs: | |
| track: | |
| description: 'Play Store track to publish to' | |
| required: true | |
| default: 'internal' | |
| type: choice | |
| options: | |
| - internal | |
| - alpha | |
| - beta | |
| - production | |
| permissions: | |
| contents: read | |
| jobs: | |
| publish: | |
| name: Build signed AAB and upload to Play | |
| runs-on: ubuntu-latest | |
| env: | |
| # Track input is only set on workflow_dispatch; default to 'internal' on tag push. | |
| PLAY_TRACK: ${{ github.event.inputs.track || 'internal' }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| # androidGitVersion needs full history + tags to compute versionCode/versionName. | |
| fetch-depth: 0 | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 | |
| - name: Decode upload keystore | |
| env: | |
| ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} | |
| run: | | |
| if [ -z "$ANDROID_KEYSTORE_BASE64" ]; then | |
| echo "::error::ANDROID_KEYSTORE_BASE64 secret is not set" | |
| exit 1 | |
| fi | |
| echo "$ANDROID_KEYSTORE_BASE64" | base64 --decode > "${RUNNER_TEMP}/upload.keystore" | |
| echo "ANDROID_KEY_FILE=${RUNNER_TEMP}/upload.keystore" >> "$GITHUB_ENV" | |
| - name: Build signed release AAB | |
| env: | |
| ORG_GRADLE_PROJECT_ANDROID_SIGNING_KEY: ${{ secrets.ANDROID_KEY_ALIAS }} | |
| ORG_GRADLE_PROJECT_ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} | |
| ORG_GRADLE_PROJECT_ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }} | |
| ORG_GRADLE_PROJECT_ANDROID_KEY_FILE: ${{ env.ANDROID_KEY_FILE }} | |
| run: ./gradlew :app:bundleProdRelease --no-daemon --stacktrace | |
| - name: Locate AAB and read package name | |
| id: artifacts | |
| run: | | |
| AAB_PATH=$(find app/build/outputs/bundle/prodRelease -name '*.aab' | head -n1) | |
| if [ -z "$AAB_PATH" ]; then | |
| echo "::error::No AAB found under app/build/outputs/bundle/prodRelease" | |
| exit 1 | |
| fi | |
| echo "aab=$AAB_PATH" >> "$GITHUB_OUTPUT" | |
| # AGP emits native-debug-symbols.zip when buildTypes.release sets | |
| # ndk.debugSymbolLevel = 'FULL' (it does in app/build.gradle). Upload | |
| # it alongside the AAB so Play can symbolicate native crashes. | |
| SYMBOLS_PATH=$(find app/build/outputs/native-debug-symbols/prodRelease -name 'native-debug-symbols.zip' 2>/dev/null | head -n1) | |
| echo "symbols=$SYMBOLS_PATH" >> "$GITHUB_OUTPUT" | |
| PACKAGE_NAME=$(./gradlew -q :app:properties \ | |
| | awk -F': ' '/^namespace: /{print $2; exit}') | |
| if [ -z "$PACKAGE_NAME" ]; then | |
| # Fallback: grep the build.gradle for namespace | |
| PACKAGE_NAME=$(grep -E '^\s*namespace\s*=' app/build.gradle \ | |
| | head -n1 | sed -E 's/.*"([^"]+)".*/\1/') | |
| fi | |
| echo "package=$PACKAGE_NAME" >> "$GITHUB_OUTPUT" | |
| echo "Resolved package: $PACKAGE_NAME" | |
| echo "Resolved AAB: $AAB_PATH" | |
| - name: Upload AAB artifact | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | |
| with: | |
| name: app-prod-release.aab | |
| path: ${{ steps.artifacts.outputs.aab }} | |
| if-no-files-found: error | |
| - name: Publish to Google Play | |
| # No first-party Google action exists for the Play Developer API; r0adkll's | |
| # action is the de-facto community standard. Pinned by tag SHA. | |
| uses: r0adkll/upload-google-play@e738b9dd8f2476ea806d921b64aacd24f34515a5 # v1.1.5 | |
| with: | |
| serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }} | |
| packageName: ${{ steps.artifacts.outputs.package }} | |
| releaseFiles: ${{ steps.artifacts.outputs.aab }} | |
| debugSymbols: ${{ steps.artifacts.outputs.symbols }} | |
| tracks: ${{ env.PLAY_TRACK }} | |
| status: completed |