Release #6
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: | |
| tag_name: | |
| description: "Release tag (手动运行可自定义,留空则使用 manual-<short_sha>)" | |
| required: false | |
| type: string | |
| release_name: | |
| description: "Release 名称(可选,默认与 tag 相同)" | |
| required: false | |
| type: string | |
| prerelease: | |
| description: "是否标记为 Pre-release(手动运行默认 true)" | |
| required: false | |
| default: true | |
| type: boolean | |
| create_release: | |
| description: "是否创建 GitHub Release(手动运行可设为 false,仅构建与产出 Actions Artifacts)" | |
| required: false | |
| default: false | |
| type: boolean | |
| permissions: | |
| contents: write | |
| env: | |
| FLUTTER_VERSION: "3.27.3" | |
| jobs: | |
| android: | |
| name: Android (APK + AAB) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Java 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: "zulu" | |
| java-version: "17" | |
| - name: Setup Android SDK | |
| uses: android-actions/setup-android@v3 | |
| - name: Install Android build-tools and platforms | |
| run: | | |
| sdkmanager --install "platform-tools" "platforms;android-34" "build-tools;34.0.0" | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| channel: "stable" | |
| cache: true | |
| - name: Flutter pub get | |
| run: flutter pub get | |
| - name: Build APK (release) | |
| run: flutter build apk --release | |
| - name: Build App Bundle (AAB) | |
| run: flutter build appbundle --release | |
| - name: List Android outputs (debug) | |
| run: | | |
| echo "== build/app/outputs ==" | |
| ls -R build/app/outputs || true | |
| - name: Upload Android artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: android | |
| if-no-files-found: error | |
| path: | | |
| build/app/outputs/flutter-apk/*.apk | |
| build/app/outputs/bundle/release/*.aab | |
| windows: | |
| name: Windows (zip) | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| channel: "stable" | |
| cache: true | |
| - name: Enable Windows desktop | |
| run: flutter config --enable-windows-desktop | |
| - name: Flutter pub get | |
| run: flutter pub get | |
| - name: Build Windows (release) | |
| run: flutter build windows --release | |
| - name: Package Windows zip | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $src = "build/windows/x64/runner/Release" | |
| if (!(Test-Path $src)) { Get-ChildItem -Recurse build/windows | Write-Output } | |
| $dst = "xplayer-windows-x64.zip" | |
| if (Test-Path $dst) { Remove-Item $dst } | |
| Compress-Archive -Path "$src/*" -DestinationPath $dst | |
| - name: Upload Windows artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: windows | |
| if-no-files-found: error | |
| path: xplayer-windows-x64.zip | |
| macos: | |
| name: macOS (app.zip) | |
| runs-on: macos-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| channel: "stable" | |
| cache: true | |
| - name: Enable macOS desktop | |
| run: flutter config --enable-macos-desktop | |
| - name: Flutter pub get | |
| run: flutter pub get | |
| - name: Build macOS (release) | |
| run: flutter build macos --release | |
| - name: Package macOS .app to zip (unsigned) | |
| run: | | |
| set -euo pipefail | |
| APP_PATH=$(ls -d build/macos/Build/Products/Release/*.app | head -n 1) | |
| echo "Found app: $APP_PATH" | |
| ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" xplayer-macos.zip | |
| - name: Package macOS .app to DMG (unsigned) | |
| run: | | |
| set -euo pipefail | |
| APP_PATH=$(ls -d build/macos/Build/Products/Release/*.app | head -n 1) | |
| VOLUME_NAME="xplayer" | |
| DMG_PATH="xplayer-macos.dmg" | |
| [ -f "$DMG_PATH" ] && rm -f "$DMG_PATH" | |
| # 创建临时目录以生成 DMG 内容 | |
| TMPDIR=$(mktemp -d) | |
| cp -R "$APP_PATH" "$TMPDIR/" | |
| hdiutil create -volname "$VOLUME_NAME" -srcfolder "$TMPDIR" -ov -format UDZO "$DMG_PATH" | |
| rm -rf "$TMPDIR" | |
| - name: Upload macOS artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: macos | |
| if-no-files-found: error | |
| path: | | |
| xplayer-macos.zip | |
| xplayer-macos.dmg | |
| ios: | |
| name: iOS (app.zip + unsigned .ipa) | |
| runs-on: macos-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| channel: "stable" | |
| cache: true | |
| - name: Flutter pub get | |
| run: flutter pub get | |
| - name: Build iOS (no codesign) | |
| run: flutter build ios --release --no-codesign | |
| - name: Package iOS Runner.app (unsigned) | |
| run: | | |
| set -euo pipefail | |
| APP_PATH="build/ios/iphoneos/Runner.app" | |
| if [ ! -d "$APP_PATH" ]; then | |
| echo "Runner.app not found at $APP_PATH" >&2 | |
| ls -la build/ios/iphoneos || true | |
| exit 1 | |
| fi | |
| ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" Runner-iphoneos.app.zip | |
| mkdir -p Payload | |
| cp -R "$APP_PATH" Payload/ | |
| /usr/bin/zip -qry Runner-unsigned.ipa Payload | |
| - name: Upload iOS artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ios | |
| path: | | |
| Runner-iphoneos.app.zip | |
| Runner-unsigned.ipa | |
| release: | |
| name: Create GitHub Release | |
| runs-on: ubuntu-latest | |
| needs: [android, windows, macos, ios] | |
| steps: | |
| - name: Prepare release metadata | |
| id: meta | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| IS_TAG="false" | |
| TAG_NAME="" | |
| if [[ "${GITHUB_REF:-}" == refs/tags/* ]]; then | |
| IS_TAG="true" | |
| TAG_NAME="${GITHUB_REF#refs/tags/}" | |
| fi | |
| if [[ -z "$TAG_NAME" ]]; then | |
| INPUT_TAG="${{ github.event.inputs.tag_name || '' }}" | |
| if [[ -n "$INPUT_TAG" ]]; then | |
| TAG_NAME="$INPUT_TAG" | |
| else | |
| SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7) | |
| TAG_NAME="manual-${SHORT_SHA}" | |
| fi | |
| fi | |
| # 手动触发默认 prerelease=true;tag 触发默认 false | |
| INPUT_PRERELEASE="${{ github.event.inputs.prerelease || '' }}" | |
| if [[ "$IS_TAG" == "true" ]]; then | |
| PRERELEASE="false" | |
| else | |
| PRERELEASE=${INPUT_PRERELEASE:-true} | |
| fi | |
| # 是否创建 Release | |
| INPUT_CREATE="${{ github.event.inputs.create_release || '' }}" | |
| if [[ "$IS_TAG" == "true" ]]; then | |
| CREATE_RELEASE="true" | |
| else | |
| CREATE_RELEASE=${INPUT_CREATE:-false} | |
| fi | |
| RELEASE_NAME_INPUT="${{ github.event.inputs.release_name || '' }}" | |
| if [[ -n "$RELEASE_NAME_INPUT" ]]; then | |
| RELEASE_NAME="$RELEASE_NAME_INPUT" | |
| else | |
| RELEASE_NAME="$TAG_NAME" | |
| fi | |
| echo "is_tag=$IS_TAG" >> $GITHUB_OUTPUT | |
| echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT | |
| echo "prerelease=$PRERELEASE" >> $GITHUB_OUTPUT | |
| echo "create_release=$CREATE_RELEASE" >> $GITHUB_OUTPUT | |
| echo "release_name=$RELEASE_NAME" >> $GITHUB_OUTPUT | |
| - name: Download Android artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: android | |
| path: ./dist/android | |
| - name: List downloaded artifacts (debug) | |
| run: | | |
| echo "== dist tree ==" | |
| ls -R ./dist || true | |
| - name: Download Windows artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: windows | |
| path: ./dist/windows | |
| - name: Download macOS artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: macos | |
| path: ./dist/macos | |
| - name: Download iOS artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ios | |
| path: ./dist/ios | |
| - name: Generate release notes | |
| id: notes | |
| run: | | |
| TAG="${{ steps.meta.outputs.tag_name }}" | |
| cat > RELEASE_NOTES.md << 'EOF' | |
| 🚀 xplayer Release | |
| 附件包含: | |
| - Android: APK 与 AAB | |
| - Windows: xplayer-windows-x64.zip(未签名) | |
| - macOS: xplayer-macos.zip / xplayer-macos.dmg(未签名,首次运行需通过 Gatekeeper) | |
| - iOS: Runner-iphoneos.app.zip 与 Runner-unsigned.ipa(均为未签名,无法直接安装或上架,仅供存档/后续签名) | |
| EOF | |
| echo "notes_file=RELEASE_NOTES.md" >> $GITHUB_OUTPUT | |
| - name: Create Release | |
| if: ${{ steps.meta.outputs.create_release == 'true' }} | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.meta.outputs.tag_name }} | |
| name: ${{ steps.meta.outputs.release_name }} | |
| prerelease: ${{ steps.meta.outputs.prerelease == 'true' }} | |
| body_path: ${{ steps.notes.outputs.notes_file }} | |
| files: | | |
| dist/android/**/*.apk | |
| dist/android/**/*.aab | |
| dist/windows/* | |
| dist/macos/* | |
| dist/ios/* | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |