Skip to content

Conversation

@graycreate
Copy link
Member

Summary

  • Fixed HTTP 204 error by adding alt=media parameter to download requests
  • Implemented smart APK availability checking to reduce wait times
  • Fixed APK selection logic to properly find universal APKs
  • Integrated download job with Play Store upload pipeline

Key Changes

  1. Fixed download API calls: Added alt=media parameter to get binary content instead of metadata
  2. Smart checking: Check if APK exists before waiting, with periodic polling
  3. Improved APK detection: Look for generatedUniversalApk field first, then fallback to base split APKs
  4. Pipeline integration: Download job now properly depends on Play Store upload

Test Results

  • ✅ Successfully downloads Google Play signed APKs
  • ✅ Skips waiting when APK already exists (saves ~5 minutes)
  • ✅ Properly handles URL query parameters
  • ✅ Downloads complete in 25 seconds when APK is ready

Fixes the download-signed-apk job that was failing with HTTP 204 errors.

graycreate and others added 18 commits September 9, 2025 21:58
- Remove job dependencies to test download independently
- Hardcode v2.3.3 version values for testing existing APK
- This is a temporary test configuration

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Remove AAB artifact download step (not needed)
- Remove fallback bundletool generation (focus only on signed APK)
- Simplify workflow to only download actual signed APK from Google Play

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Use generatedapks.list to get downloadId from APK manifest
- Use generatedapks.download to fetch binary APK with downloadId
- Improve universal APK detection with better targeting logic
- Add detailed logging for debugging APK selection

Based on correct API documentation:
- GET /applications/{packageName}/generatedApks/{versionCode}
- GET /applications/{packageName}/generatedApks/{versionCode}/downloads/{downloadId}:download

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Print complete APK object structure to understand available fields
- This will help identify the correct field name for downloadId

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
…cture

- Changed from looking for generatedUniversalApK field to generatedSplitApks array
- Look for base module with variantId=1 and no splitId to identify universal APK
- Added better debugging output to understand API response structure
- Fixed duplicate download_id validation
- Replace direct execute() call with proper Google API media download
- Add progress tracking during download
- Use BytesIO buffer for binary data handling
- Remove hard-coded variantId=1 requirement
- Accept any variant ID for base module without splitId
- Add better debugging output to show splitId values
- Try variantId=1 without splitId first (original approach)
- Fall back to variantId=2 without splitId
- Fall back to variantId=3 without splitId
- Finally try first base module even with splitId
- Add detailed logging for each strategy attempt
- Try variantId=2 first since variantId=1 consistently returns 404
- Use variantId=3 as secondary option
- Keep variantId=1 as last resort for debugging
- Add better logging for all base APK candidates
- Changed from download() to download_media() method
- This fixes the HTTP 204 error when downloading signed APKs
- download_media() returns the actual media content instead of metadata

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- First check generatedUniversalApk field as per API documentation
- Fallback to base module in generatedSplitApks if needed
- Simplified variant selection logic
- This should resolve HTTP 204 errors by using correct APK structure

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Add ?alt=media to download request URL to get binary content
- Without alt=media, API returns HTTP 204 with metadata only
- This follows Google APIs media download convention

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Check for existing query params and use & instead of ?
- Prevents double question mark (??) in URL which caused HTTP 400
- Now properly handles URLs that already contain query parameters

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Add dependency on play-store-upload job
- Add proper execution conditions (requires signing and play store upload enabled)
- Use dynamic version info from prepare job instead of hardcoded values
- Increase wait time to 5 minutes for Google Play processing
- Update error messages to be more accurate
- Ensure download job only runs after successful Play Store upload

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Check if Google Play signed APK already exists before waiting
- Implement periodic polling (every 30s) with 10min maximum wait
- Skip unnecessary waiting if APK is already available
- Provide better progress feedback during waiting
- Reduce overall pipeline execution time when APK is ready

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Use known existing version 2.3.3 (code 233) in Google Play
- This should skip waiting and go directly to download
- Will revert after testing to use dynamic version

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Remove job dependencies temporarily
- Use hardcoded version 2.3.3 (233) which exists in Google Play
- This should demonstrate immediate APK detection and skip waiting
- Will revert after testing

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Copilot AI review requested due to automatic review settings September 9, 2025 15:48

This comment was marked as outdated.

@graycreate graycreate requested a review from Copilot September 9, 2025 15:52
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes the Google Play signed APK download functionality by resolving HTTP 204 errors and implementing smart availability checking. The changes ensure proper binary content retrieval and reduce unnecessary waiting time during the CI/CD pipeline.

Key changes made:

  • Fixed API calls by adding the alt=media parameter to download binary content instead of metadata
  • Implemented smart checking logic to verify APK availability before waiting, with periodic polling
  • Enhanced APK detection to prioritize universal APKs and fallback to base split APKs with proper targeting

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

download-signed-apk:
name: Download Google Play Signed APK
needs: [prepare, play-store-upload]
if: ${{ vars.ENABLE_PLAY_STORE_UPLOAD == 'true' && vars.ENABLE_SIGNING == 'true' }}
Copy link

Copilot AI Sep 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition expression has redundant ${{ }} wrapper. GitHub Actions automatically evaluates expressions in if conditions, so this should be if: vars.ENABLE_PLAY_STORE_UPLOAD == 'true' && vars.ENABLE_SIGNING == 'true'

Suggested change
if: ${{ vars.ENABLE_PLAY_STORE_UPLOAD == 'true' && vars.ENABLE_SIGNING == 'true' }}
if: vars.ENABLE_PLAY_STORE_UPLOAD == 'true' && vars.ENABLE_SIGNING == 'true'

Copilot uses AI. Check for mistakes.
Comment on lines +639 to +643
# Add alt=media parameter correctly (URL already has query params, so use &)
if '?' in download_request.uri:
download_request.uri += '&alt=media'
else:
download_request.uri += '?alt=media'
Copy link

Copilot AI Sep 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Direct URI manipulation is fragile and error-prone. Consider using URL parsing libraries like urllib.parse to properly handle query parameters instead of string concatenation.

Suggested change
# Add alt=media parameter correctly (URL already has query params, so use &)
if '?' in download_request.uri:
download_request.uri += '&alt=media'
else:
download_request.uri += '?alt=media'
# Add alt=media parameter correctly using urllib.parse
from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
parsed = urlparse(download_request.uri)
query = parse_qs(parsed.query)
query['alt'] = ['media']
new_query = urlencode(query, doseq=True)
download_request.uri = urlunparse(parsed._replace(query=new_query))

Copilot uses AI. Check for mistakes.
Comment on lines +648 to +649
import io
from googleapiclient.http import MediaIoBaseDownload
Copy link

Copilot AI Sep 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import statements should be placed at the top of the script with other imports (lines 414-419) rather than in the middle of the function for better code organization and readability.

Copilot uses AI. Check for mistakes.
- Universal APK is guaranteed to exist for all releases
- Removed fallback logic that looked for base modules in split APKs
- Simplified code by only checking for generatedUniversalApk field
- This makes the code cleaner and more maintainable

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@graycreate graycreate merged commit 06fa0ab into main Sep 9, 2025
5 checks passed
@graycreate graycreate deleted the test/download-only branch September 9, 2025 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants