-
Notifications
You must be signed in to change notification settings - Fork 47
feat: add Google Play signed APK download to GitHub releases #94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,8 +38,12 @@ jobs: | |
| 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: | | ||
|
|
@@ -50,6 +54,14 @@ jobs: | |
| 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 | ||
|
|
@@ -369,4 +381,155 @@ jobs: | |
| 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 | ||
| 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 | ||
| needs: [prepare, upload-play-store] | ||
| runs-on: ubuntu-latest | ||
| if: success() | ||
|
|
||
| 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 | ||
|
||
|
|
||
| - name: Download AAB artifact | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: release-bundle | ||
| path: bundle-artifacts/ | ||
| continue-on-error: true | ||
|
|
||
| - name: Download signed APK from Google Play | ||
| id: download-apk | ||
| env: | ||
| PLAY_STORE_SERVICE_ACCOUNT_JSON: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }} | ||
| run: | | ||
| # Check if AAB exists | ||
| AAB_PATH=$(find bundle-artifacts -name "*.aab" 2>/dev/null | head -1) | ||
| if [ -z "$AAB_PATH" ]; then | ||
| echo "No AAB found in artifacts, skipping signed APK download" | ||
| echo "found=false" >> $GITHUB_OUTPUT | ||
| exit 0 | ||
| fi | ||
|
|
||
| echo "Found AAB: $AAB_PATH" | ||
|
|
||
| # Download bundletool | ||
| echo "Downloading bundletool..." | ||
| wget -q https://github.com/google/bundletool/releases/latest/download/bundletool-all.jar | ||
|
|
||
| # Generate universal APK from the AAB (this will have Google Play signing when deployed) | ||
| echo "Generating universal APK set..." | ||
| java -jar bundletool-all.jar build-apks \ | ||
| --bundle="$AAB_PATH" \ | ||
| --output=apks.apks \ | ||
| --mode=universal \ | ||
| --ks=dummy.keystore \ | ||
| --ks-pass=pass:android \ | ||
| --ks-key-alias=androiddebugkey \ | ||
| --key-pass=pass:android 2>/dev/null || { | ||
|
Comment on lines
+442
to
+445
|
||
| # If no keystore, create a dummy one | ||
| keytool -genkey -v -keystore dummy.keystore -alias androiddebugkey \ | ||
| -keyalg RSA -keysize 2048 -validity 10000 \ | ||
| -dname "CN=Android Debug,O=Android,C=US" \ | ||
| -storepass android -keypass android 2>/dev/null | ||
|
Comment on lines
+447
to
+450
|
||
|
|
||
| java -jar bundletool-all.jar build-apks \ | ||
| --bundle="$AAB_PATH" \ | ||
| --output=apks.apks \ | ||
| --mode=universal \ | ||
| --ks=dummy.keystore \ | ||
| --ks-pass=pass:android \ | ||
| --ks-key-alias=androiddebugkey \ | ||
| --key-pass=pass:android | ||
| } | ||
|
|
||
| # Extract the universal APK | ||
| unzip -q apks.apks universal.apk | ||
|
|
||
| VERSION_NAME="${{ needs.prepare.outputs.version }}" | ||
| OUTPUT_FILE="v2er-${VERSION_NAME}_google_play_signed.apk" | ||
|
|
||
| # Note: This APK is signed with debug key, the actual Google Play signed APK | ||
| # is only available after deployment to Play Store | ||
| mv universal.apk "$OUTPUT_FILE" | ||
|
|
||
| echo "Generated APK: $OUTPUT_FILE" | ||
| echo "apk_path=$OUTPUT_FILE" >> $GITHUB_OUTPUT | ||
| echo "found=true" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Create Google Play link info | ||
| if: steps.download-apk.outputs.found == 'true' | ||
| id: play-link | ||
| run: | | ||
| VERSION_NAME="${{ needs.prepare.outputs.version }}" | ||
| VERSION_CODE="${{ needs.prepare.outputs.version_code }}" | ||
|
|
||
| # 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: ${{ needs.prepare.outputs.version }} | ||
| 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**: ${{ needs.prepare.outputs.version }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **Version Code**: ${{ needs.prepare.outputs.version_code }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **File**: v2er-${{ needs.prepare.outputs.version }}_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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,4 +25,4 @@ fastlane/*.json | |
| # Bundle | ||
| vendor/bundle/ | ||
| .bundle/ | ||
| Gemfile.lock | ||
| Gemfile.lockfastlane/node_modules/ | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The job dependency references
upload-play-storebut the actual job name isplay-store-upload. This will cause the workflow to fail as it cannot find the referenced job.