Release #26
Workflow file for this run
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: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to release (e.g., v1.0.0)' | |
| required: true | |
| type: string | |
| track: | |
| description: 'Play Store release track' | |
| required: false | |
| type: choice | |
| default: 'internal' | |
| options: | |
| - internal | |
| - alpha | |
| - beta | |
| - production | |
| status: | |
| description: 'Play Store release status' | |
| required: false | |
| type: choice | |
| default: 'draft' | |
| options: | |
| - draft | |
| - completed | |
| permissions: | |
| contents: write | |
| jobs: | |
| prepare: | |
| name: Prepare Release | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| version_code: ${{ steps.version_info.outputs.version_code }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Determine version | |
| id: version | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| VERSION="${{ github.event.inputs.version }}" | |
| else | |
| VERSION="${{ github.ref_name }}" | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Version: $VERSION" | |
| - name: Extract version code | |
| id: version_info | |
| run: | | |
| # Extract version code from config.gradle | |
| VERSION_CODE=$(grep "versionCode:" config.gradle | sed 's/.*versionCode: \([0-9]*\).*/\1/') | |
| echo "version_code=$VERSION_CODE" >> $GITHUB_OUTPUT | |
| echo "Version Code: $VERSION_CODE" | |
| build-apk: | |
| name: Build Release APK | |
| needs: prepare | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '17' | |
| distribution: 'temurin' | |
| cache: gradle | |
| - name: Grant execute permission for gradlew | |
| run: chmod +x gradlew | |
| - name: Decode Keystore | |
| if: ${{ vars.ENABLE_SIGNING == 'true' && env.KEYSTORE_BASE64 != '' }} | |
| env: | |
| KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }} | |
| run: | | |
| echo "$KEYSTORE_BASE64" | base64 --decode > app/keystore.jks | |
| - name: Debug keystore info | |
| if: ${{ vars.ENABLE_SIGNING == 'true' }} | |
| run: | | |
| echo "Keystore file exists: $([ -f app/keystore.jks ] && echo 'Yes' || echo 'No')" | |
| echo "Keystore size: $([ -f app/keystore.jks ] && ls -la app/keystore.jks | awk '{print $5}' || echo 'N/A')" | |
| echo "Key alias configured: ${{ secrets.KEY_ALIAS != '' && 'Yes' || 'No' }}" | |
| - name: Build release APK | |
| run: | | |
| if [ "${{ vars.ENABLE_SIGNING }}" = "true" ] && [ -f "app/keystore.jks" ]; then | |
| echo "Building signed release APK" | |
| echo "Using key alias: ${{ secrets.KEY_ALIAS }}" | |
| ./gradlew assembleRelease \ | |
| -Pandroid.injected.signing.store.file=${{ github.workspace }}/app/keystore.jks \ | |
| -Pandroid.injected.signing.store.password=${{ secrets.KEYSTORE_PASSWORD }} \ | |
| -Pandroid.injected.signing.key.alias=${{ secrets.KEY_ALIAS }} \ | |
| -Pandroid.injected.signing.key.password=${{ secrets.KEY_PASSWORD }} | |
| else | |
| echo "Building unsigned release APK" | |
| ./gradlew assembleRelease --stacktrace | |
| fi | |
| - name: Clean up keystore | |
| if: always() | |
| run: | | |
| rm -f app/keystore.jks | |
| - name: Upload release APK | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-apk | |
| path: app/build/outputs/apk/**/*.apk | |
| retention-days: 30 | |
| - name: APK Summary | |
| run: | | |
| echo "## APK Build Results :package:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| APK_PATH=$(find app/build/outputs/apk -name "*.apk" | grep -E "release" | head -1) | |
| if [ -f "$APK_PATH" ]; then | |
| APK_SIZE=$(du -h "$APK_PATH" | cut -f1) | |
| echo "- APK Size: $APK_SIZE" >> $GITHUB_STEP_SUMMARY | |
| echo "- APK Name: \`$(basename "$APK_PATH")\`" >> $GITHUB_STEP_SUMMARY | |
| echo "- Signed: ${{ vars.ENABLE_SIGNING == 'true' && 'Yes' || 'No' }}" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "No APK found" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| build-aab: | |
| name: Build Release Bundle | |
| needs: prepare | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '17' | |
| distribution: 'temurin' | |
| cache: gradle | |
| - name: Grant execute permission for gradlew | |
| run: chmod +x gradlew | |
| - name: Decode Keystore | |
| if: ${{ vars.ENABLE_SIGNING == 'true' && env.KEYSTORE_BASE64 != '' }} | |
| env: | |
| KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }} | |
| run: | | |
| echo "$KEYSTORE_BASE64" | base64 --decode > app/keystore.jks | |
| - name: Build release bundle | |
| run: | | |
| if [ "${{ vars.ENABLE_SIGNING }}" = "true" ] && [ -f "app/keystore.jks" ]; then | |
| echo "Building signed release bundle" | |
| ./gradlew bundleRelease \ | |
| -Pandroid.injected.signing.store.file=${{ github.workspace }}/app/keystore.jks \ | |
| -Pandroid.injected.signing.store.password=${{ secrets.KEYSTORE_PASSWORD }} \ | |
| -Pandroid.injected.signing.key.alias=${{ secrets.KEY_ALIAS }} \ | |
| -Pandroid.injected.signing.key.password=${{ secrets.KEY_PASSWORD }} | |
| else | |
| echo "Skipping bundle build - signing not configured" | |
| fi | |
| - name: Generate debug symbols | |
| if: ${{ vars.ENABLE_SIGNING == 'true' }} | |
| run: | | |
| echo "Checking for debug symbols..." | |
| find app/build/outputs -name "*.zip" -type f | grep -i debug || echo "No debug symbol zips found" | |
| find app/build/outputs -name "*symbols*" -type f || echo "No symbol files found" | |
| ls -la app/build/outputs/bundle/release/ || true | |
| - name: Clean up keystore | |
| if: always() | |
| run: | | |
| rm -f app/keystore.jks | |
| - name: Upload release bundle | |
| if: ${{ vars.ENABLE_SIGNING == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-bundle | |
| path: | | |
| app/build/outputs/bundle/**/*.aab | |
| app/build/outputs/mapping/release/mapping.txt | |
| retention-days: 30 | |
| release: | |
| name: Create GitHub Release | |
| needs: [prepare, build-apk, build-aab] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Download APK artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: release-apk | |
| path: release-artifacts/ | |
| - name: Download AAB artifact | |
| if: ${{ vars.ENABLE_SIGNING == 'true' }} | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: release-bundle | |
| path: release-artifacts/ | |
| continue-on-error: true | |
| - name: Prepare release assets | |
| id: assets | |
| run: | | |
| # Find APK | |
| APK_PATH=$(find release-artifacts -name "*.apk" | grep -E "release" | head -1) | |
| if [ -f "$APK_PATH" ]; then | |
| APK_NAME="v2er-${{ needs.prepare.outputs.version }}.apk" | |
| mv "$APK_PATH" "$APK_NAME" | |
| echo "apk_path=$APK_NAME" >> $GITHUB_OUTPUT | |
| fi | |
| # Find AAB | |
| AAB_PATH=$(find release-artifacts -name "*.aab" 2>/dev/null | head -1) | |
| if [ -f "$AAB_PATH" ]; then | |
| AAB_NAME="v2er-${{ needs.prepare.outputs.version }}.aab" | |
| mv "$AAB_PATH" "$AAB_NAME" | |
| echo "aab_path=$AAB_NAME" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Generate changelog | |
| id: changelog | |
| run: | | |
| echo "## What's Changed" > CHANGELOG.md | |
| echo "" >> CHANGELOG.md | |
| # Get commits since last tag | |
| LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") | |
| if [ -n "$LAST_TAG" ]; then | |
| git log --pretty=format:"* %s by @%an" "$LAST_TAG"..HEAD >> CHANGELOG.md | |
| else | |
| git log --pretty=format:"* %s by @%an" -10 >> CHANGELOG.md | |
| fi | |
| echo "" >> CHANGELOG.md | |
| echo "" >> CHANGELOG.md | |
| echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LAST_TAG}...${{ needs.prepare.outputs.version }}" >> CHANGELOG.md | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.prepare.outputs.version }} | |
| name: Release ${{ needs.prepare.outputs.version }} | |
| body_path: CHANGELOG.md | |
| draft: false | |
| prerelease: false | |
| files: | | |
| ${{ steps.assets.outputs.apk_path }} | |
| ${{ steps.assets.outputs.aab_path }} | |
| fail_on_unmatched_files: false | |
| play-store-upload: | |
| name: Upload to Play Store | |
| needs: [prepare, build-aab] | |
| if: ${{ vars.ENABLE_PLAY_STORE_UPLOAD == 'true' && vars.ENABLE_SIGNING == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Download AAB artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: release-bundle | |
| path: release-artifacts/ | |
| - name: Find bundle and symbols | |
| id: find-files | |
| run: | | |
| AAB_PATH=$(find release-artifacts -name "*.aab" | head -1) | |
| echo "aab_path=$AAB_PATH" >> $GITHUB_OUTPUT | |
| # Look for debug symbols | |
| SYMBOLS_PATH=$(find release-artifacts -name "native-debug-symbols.zip" 2>/dev/null | head -1) | |
| if [ -n "$SYMBOLS_PATH" ]; then | |
| echo "symbols_path=$SYMBOLS_PATH" >> $GITHUB_OUTPUT | |
| echo "Found debug symbols at: $SYMBOLS_PATH" | |
| else | |
| echo "No debug symbols found" | |
| fi | |
| # Look for ProGuard/R8 mapping file | |
| MAPPING_PATH=$(find release-artifacts -name "mapping.txt" 2>/dev/null | head -1) | |
| if [ -n "$MAPPING_PATH" ]; then | |
| echo "mapping_path=$MAPPING_PATH" >> $GITHUB_OUTPUT | |
| echo "Found ReTrace mapping file at: $MAPPING_PATH" | |
| else | |
| echo "No ReTrace mapping file found" | |
| fi | |
| - name: Determine release track and status | |
| id: release-config | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| TRACK="${{ github.event.inputs.track }}" | |
| STATUS="${{ github.event.inputs.status }}" | |
| else | |
| # Default for tag pushes | |
| TRACK="internal" | |
| STATUS="draft" | |
| fi | |
| echo "track=$TRACK" >> $GITHUB_OUTPUT | |
| echo "status=$STATUS" >> $GITHUB_OUTPUT | |
| echo "Deploying to track: $TRACK with status: $STATUS" | |
| - name: Create whatsnew directory | |
| run: | | |
| mkdir -p whatsnew | |
| # Generate release notes | |
| echo "Release ${{ needs.prepare.outputs.version }}" > whatsnew/whatsnew-en-US | |
| echo "" >> whatsnew/whatsnew-en-US | |
| # Get recent commits | |
| git log --pretty=format:"• %s" -5 >> whatsnew/whatsnew-en-US | |
| # Chinese version | |
| echo "版本 ${{ needs.prepare.outputs.version }}" > whatsnew/whatsnew-zh-CN | |
| echo "" >> whatsnew/whatsnew-zh-CN | |
| git log --pretty=format:"• %s" -5 >> whatsnew/whatsnew-zh-CN | |
| - name: Upload to Play Store (with debug symbols) | |
| if: steps.find-files.outputs.symbols_path != '' | |
| uses: r0adkll/upload-google-play@v1 | |
| with: | |
| serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }} | |
| packageName: me.ghui.v2er | |
| releaseFiles: ${{ steps.find-files.outputs.aab_path }} | |
| track: ${{ steps.release-config.outputs.track }} | |
| status: ${{ steps.release-config.outputs.status }} | |
| debugSymbols: ${{ steps.find-files.outputs.symbols_path }} | |
| mappingFile: ${{ steps.find-files.outputs.mapping_path }} | |
| whatsNewDirectory: whatsnew/ | |
| continue-on-error: true | |
| id: upload-with-symbols | |
| - name: Upload to Play Store (without debug symbols) | |
| if: steps.find-files.outputs.symbols_path == '' || steps.upload-with-symbols.outcome == 'failure' | |
| uses: r0adkll/upload-google-play@v1 | |
| with: | |
| serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }} | |
| packageName: me.ghui.v2er | |
| releaseFiles: ${{ steps.find-files.outputs.aab_path }} | |
| track: ${{ steps.release-config.outputs.track }} | |
| status: ${{ steps.release-config.outputs.status }} | |
| mappingFile: ${{ steps.find-files.outputs.mapping_path }} | |
| whatsNewDirectory: whatsnew/ | |
| - name: Play Store Upload Summary | |
| if: success() | |
| run: | | |
| echo "## Play Store Upload Complete :rocket:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Version**: ${{ needs.prepare.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Track**: ${{ steps.release-config.outputs.track }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Status**: ${{ steps.release-config.outputs.status }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Package**: me.ghui.v2er" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "[View in Play Console](https://play.google.com/console/u/0/app/me.ghui.v2er)" >> $GITHUB_STEP_SUMMARY | |
| download-signed-apk: | |
| name: Download Google Play Signed APK | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.x' | |
| - name: Install dependencies | |
| run: | | |
| pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib requests | |
| - name: Wait for Google Play processing | |
| run: | | |
| echo "Waiting for Google Play to process and sign the APK..." | |
| sleep 120 # Wait 2 minutes for Google Play to process | |
| # AAB artifact not needed for Google Play signed APK download | |
| - name: Download Google Play Signed APK | |
| id: download-apk | |
| env: | |
| PLAY_STORE_SERVICE_ACCOUNT_JSON: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }} | |
| run: | | |
| VERSION_NAME="v2.3.3" | |
| VERSION_CODE="233" | |
| PACKAGE_NAME="me.ghui.v2er" | |
| # Create Python script to download signed universal APK | |
| cat > download_signed_apk.py << 'EOF' | |
| import json | |
| import os | |
| import sys | |
| import requests | |
| from google.oauth2 import service_account | |
| from googleapiclient.discovery import build | |
| def download_signed_apk(): | |
| try: | |
| # Load service account credentials | |
| service_account_info = json.loads(os.environ['PLAY_STORE_SERVICE_ACCOUNT_JSON']) | |
| credentials = service_account.Credentials.from_service_account_info( | |
| service_account_info, | |
| scopes=['https://www.googleapis.com/auth/androidpublisher'] | |
| ) | |
| # Build the service | |
| service = build('androidpublisher', 'v3', credentials=credentials) | |
| package_name = os.environ['PACKAGE_NAME'] | |
| version_code = int(os.environ['VERSION_CODE']) | |
| print(f"Attempting to download signed APK for {package_name} version {version_code}") | |
| # Step 1: Get the generated APKs list to find downloadId | |
| print("Getting generated APKs list...") | |
| result = service.generatedapks().list( | |
| packageName=package_name, | |
| versionCode=version_code | |
| ).execute() | |
| if 'generatedApks' not in result or not result['generatedApks']: | |
| print("No generated APKs found. App may not be processed yet by Google Play.") | |
| return False | |
| print(f"Found {len(result['generatedApks'])} generated APKs") | |
| # Debug: Print all APK structures | |
| for i, apk in enumerate(result['generatedApks']): | |
| print(f"APK {i} structure:") | |
| for key, value in apk.items(): | |
| print(f" {key}: {value}") | |
| print() | |
| # Find universal APK in generatedSplitApks (based on API debug output) | |
| download_id = None | |
| universal_apk = None | |
| for apk in result['generatedApks']: | |
| if 'generatedSplitApks' in apk: | |
| split_apks = apk['generatedSplitApks'] | |
| print(f"Found {len(split_apks)} split APKs") | |
| # Look for the base/universal APK - typically variantId=1, moduleName='base' | |
| for split_apk in split_apks: | |
| print(f"Split APK: variantId={split_apk.get('variantId')}, moduleName={split_apk.get('moduleName')}") | |
| # Universal APK is typically the base module without splitId | |
| if (split_apk.get('moduleName') == 'base' and | |
| split_apk.get('variantId') == 1 and | |
| 'splitId' not in split_apk): | |
| download_id = split_apk.get('downloadId') | |
| universal_apk = split_apk | |
| print(f"Found universal APK: {universal_apk}") | |
| break | |
| if download_id: | |
| break | |
| if not download_id: | |
| print("Universal APK not found in generatedSplitApks") | |
| print("Available APK structure:") | |
| print(json.dumps(result['generatedApks'], indent=2)) | |
| return False | |
| print(f"Found universal APK with downloadId: {download_id}") | |
| # Step 2: Download the APK using the downloadId | |
| print("Downloading APK binary...") | |
| download_request = service.generatedapks().download( | |
| packageName=package_name, | |
| versionCode=version_code, | |
| downloadId=download_id | |
| ) | |
| output_filename = f"v2er-{os.environ['VERSION_NAME']}_google_play_signed.apk" | |
| # Execute the download request and save to file | |
| # Use media download with googleapiclient.http to handle binary content | |
| import io | |
| from googleapiclient.http import MediaIoBaseDownload | |
| file_io = io.BytesIO() | |
| downloader = MediaIoBaseDownload(file_io, download_request) | |
| done = False | |
| while done is False: | |
| status, done = downloader.next_chunk() | |
| if status: | |
| print(f"Download progress: {int(status.progress() * 100)}%") | |
| # Write to file | |
| with open(output_filename, 'wb') as f: | |
| f.write(file_io.getvalue()) | |
| print(f"Successfully downloaded: {output_filename}") | |
| print(f"apk_path={output_filename}") | |
| return True | |
| except Exception as e: | |
| print(f"Error downloading signed APK: {str(e)}") | |
| print("This may be because:") | |
| print("1. The app hasn't been processed by Google Play yet") | |
| print("2. The version hasn't been released to any track") | |
| print("3. API permissions are insufficient") | |
| return False | |
| if __name__ == "__main__": | |
| success = download_signed_apk() | |
| sys.exit(0 if success else 1) | |
| EOF | |
| # Set environment variables for the script | |
| export PACKAGE_NAME="$PACKAGE_NAME" | |
| export VERSION_CODE="$VERSION_CODE" | |
| export VERSION_NAME="$VERSION_NAME" | |
| # Run the download script | |
| echo "Attempting to download Google Play signed APK..." | |
| if python3 download_signed_apk.py > download_output.txt 2>&1; then | |
| echo "Successfully downloaded Google Play signed APK" | |
| cat download_output.txt | |
| # Extract the APK path from output | |
| APK_PATH=$(grep "apk_path=" download_output.txt | cut -d'=' -f2) | |
| if [ -f "$APK_PATH" ]; then | |
| echo "apk_path=$APK_PATH" >> $GITHUB_OUTPUT | |
| echo "found=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "APK file not found after download" | |
| echo "found=false" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| echo "Failed to download Google Play signed APK" | |
| cat download_output.txt | |
| echo "found=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create Google Play link info | |
| if: steps.download-apk.outputs.found == 'true' | |
| id: play-link | |
| run: | | |
| VERSION_NAME="v2.3.3" | |
| VERSION_CODE="233" | |
| # Create info file about Google Play signing | |
| cat > "v2er-${VERSION_NAME}_google_play_signed_info.txt" << EOF | |
| Google Play Signed APK Information | |
| ================================== | |
| Version: ${VERSION_NAME} | |
| Version Code: ${VERSION_CODE} | |
| Package: me.ghui.v2er | |
| The APK attached (v2er-${VERSION_NAME}_google_play_signed.apk) is a universal APK | |
| generated from the AAB (Android App Bundle) that was uploaded to Google Play. | |
| When downloaded from Google Play Store, the APK will be signed with Google Play's | |
| app signing certificate instead of the upload certificate. | |
| Internal Testing Link: | |
| https://play.google.com/apps/test/me.ghui.v2er/${VERSION_CODE} | |
| Note: Access to internal testing track required. | |
| EOF | |
| echo "info_path=v2er-${VERSION_NAME}_google_play_signed_info.txt" >> $GITHUB_OUTPUT | |
| - name: Upload signed APK to GitHub Release | |
| if: steps.download-apk.outputs.found == 'true' | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v2.3.3 | |
| files: | | |
| ${{ steps.download-apk.outputs.apk_path }} | |
| ${{ steps.play-link.outputs.info_path }} | |
| fail_on_unmatched_files: false | |
| - name: Summary | |
| if: always() | |
| run: | | |
| echo "## Google Play Signed APK :package:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ steps.download-apk.outputs.found }}" = "true" ]; then | |
| echo "✅ **Universal APK generated successfully**" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Version**: v2.3.3" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Version Code**: 233" >> $GITHUB_STEP_SUMMARY | |
| echo "- **File**: v2er-v2.3.3_google_play_signed.apk" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Notes" >> $GITHUB_STEP_SUMMARY | |
| echo "- This APK is generated from the AAB uploaded to Google Play" >> $GITHUB_STEP_SUMMARY | |
| echo "- When installed from Play Store, it will use Google Play's signing certificate" >> $GITHUB_STEP_SUMMARY | |
| echo "- The APK has been uploaded to the GitHub Release" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "⚠️ **No AAB found in artifacts**" >> $GITHUB_STEP_SUMMARY | |
| echo "Signed APK generation requires a release bundle (AAB)" >> $GITHUB_STEP_SUMMARY | |
| fi |