fix: 使用绝对路径修复 mv 命令错误 #42
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: iOS/Mac - App Store Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| inputs: | |
| submit_for_review: | |
| description: 'Submit to App Store Review after upload' | |
| required: false | |
| default: false | |
| type: boolean | |
| env: | |
| FLUTTER_VERSION: '3.32.2' | |
| jobs: | |
| build-and-release-ios: | |
| name: Build and Release iOS to App Store | |
| runs-on: macos-14 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| channel: 'stable' | |
| cache: true | |
| - name: Get dependencies | |
| working-directory: opencli_mobile | |
| run: flutter pub get | |
| - name: Run code analysis | |
| working-directory: opencli_mobile | |
| run: flutter analyze --no-fatal-infos --no-fatal-warnings | |
| - name: Setup Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: latest-stable | |
| - name: Setup App Store Connect API Key | |
| env: | |
| APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} | |
| APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} | |
| APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }} | |
| run: | | |
| mkdir -p ~/private_keys | |
| echo "$APP_STORE_CONNECT_API_KEY_BASE64" | base64 --decode > ~/private_keys/AuthKey_${APP_STORE_CONNECT_API_KEY_ID}.p8 | |
| chmod 600 ~/private_keys/AuthKey_${APP_STORE_CONNECT_API_KEY_ID}.p8 | |
| echo "✅ App Store Connect API Key configured" | |
| ls -lh ~/private_keys/ | |
| - name: Import Signing Certificate | |
| env: | |
| DISTRIBUTION_CERTIFICATE_BASE64: ${{ secrets.DISTRIBUTION_CERTIFICATE_BASE64 }} | |
| DISTRIBUTION_CERTIFICATE_PASSWORD: ${{ secrets.DISTRIBUTION_CERTIFICATE_PASSWORD }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} | |
| run: | | |
| # Create temporary keychain | |
| KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security set-keychain-settings -lut 21600 $KEYCHAIN_PATH | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| # Import certificate | |
| echo "$DISTRIBUTION_CERTIFICATE_BASE64" | base64 --decode > $RUNNER_TEMP/certificate.p12 | |
| security import $RUNNER_TEMP/certificate.p12 \ | |
| -P "$DISTRIBUTION_CERTIFICATE_PASSWORD" \ | |
| -A -t cert -f pkcs12 -k $KEYCHAIN_PATH | |
| security list-keychain -d user -s $KEYCHAIN_PATH | |
| # Allow codesign to access keychain | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: \ | |
| -s -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| echo "✅ Signing certificate imported" | |
| - name: Install Provisioning Profile | |
| env: | |
| PROVISIONING_PROFILE_BASE64: ${{ secrets.PROVISIONING_PROFILE_BASE64 }} | |
| run: | | |
| mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles | |
| # Install with UUID as filename for manual signing | |
| PP_UUID="77603a37-5393-4eee-a01a-bce52f4fa6b6" | |
| echo "$PROVISIONING_PROFILE_BASE64" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/${PP_UUID}.mobileprovision | |
| echo "✅ Provisioning profile installed with UUID: $PP_UUID" | |
| ls -lh ~/Library/MobileDevice/Provisioning\ Profiles/ | |
| - name: Create ExportOptions.plist | |
| run: | | |
| cat > opencli_mobile/ios/ExportOptions.plist << 'EOF' | |
| <?xml version="1.0" encoding="UTF-8"?> | |
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
| <plist version="1.0"> | |
| <dict> | |
| <key>method</key> | |
| <string>app-store</string> | |
| <key>uploadBitcode</key> | |
| <false/> | |
| <key>uploadSymbols</key> | |
| <true/> | |
| <key>signingStyle</key> | |
| <string>manual</string> | |
| <key>signingCertificate</key> | |
| <string>Apple Distribution</string> | |
| <key>teamID</key> | |
| <string>G9VG22HGJG</string> | |
| <key>provisioningProfiles</key> | |
| <dict> | |
| <key>com.opencli.opencliMobile</key> | |
| <string>OpenCLI Mobile App Store (opencliMobile)</string> | |
| </dict> | |
| </dict> | |
| </plist> | |
| EOF | |
| echo "✅ ExportOptions.plist created" | |
| cat opencli_mobile/ios/ExportOptions.plist | |
| - name: Install CocoaPods dependencies | |
| working-directory: opencli_mobile/ios | |
| run: | | |
| echo "📦 Installing CocoaPods dependencies..." | |
| pod install --repo-update | |
| echo "✅ CocoaPods dependencies installed" | |
| - name: Build IPA | |
| working-directory: opencli_mobile | |
| env: | |
| IPHONEOS_DEPLOYMENT_TARGET: '13.0' | |
| run: | | |
| echo "🔨 Building iOS IPA..." | |
| flutter build ipa --release \ | |
| --export-options-plist=ios/ExportOptions.plist | |
| echo "✅ IPA built successfully" | |
| ls -lh build/ios/ipa/ | |
| - name: Fix App.framework MinimumOSVersion | |
| working-directory: opencli_mobile | |
| run: | | |
| echo "🔧 Fixing App.framework Info.plist..." | |
| # Find the IPA file and get absolute path | |
| IPA_FILE=$(find build/ios/ipa -name "*.ipa" | head -n 1) | |
| ABS_IPA_FILE=$(cd $(dirname "$IPA_FILE") && pwd)/$(basename "$IPA_FILE") | |
| # Create a temporary directory | |
| TEMP_DIR=$(mktemp -d) | |
| # Unzip the IPA | |
| unzip -q "$ABS_IPA_FILE" -d "$TEMP_DIR" | |
| # Fix App.framework Info.plist | |
| APP_PLIST="$TEMP_DIR/Payload/Runner.app/Frameworks/App.framework/Info.plist" | |
| if [ -f "$APP_PLIST" ]; then | |
| /usr/libexec/PlistBuddy -c "Add :MinimumOSVersion string 13.0" "$APP_PLIST" 2>/dev/null || \ | |
| /usr/libexec/PlistBuddy -c "Set :MinimumOSVersion 13.0" "$APP_PLIST" | |
| echo "✅ Set MinimumOSVersion to 13.0 in App.framework" | |
| /usr/libexec/PlistBuddy -c "Print :MinimumOSVersion" "$APP_PLIST" | |
| fi | |
| # Repackage the IPA | |
| cd "$TEMP_DIR" | |
| NEW_IPA="$TEMP_DIR/fixed.ipa" | |
| zip -qr "$NEW_IPA" Payload | |
| cd - | |
| # Replace the original IPA | |
| mv "$NEW_IPA" "$ABS_IPA_FILE" | |
| # Cleanup | |
| rm -rf "$TEMP_DIR" | |
| echo "✅ IPA fixed and repackaged" | |
| - name: Upload IPA Artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ios-release-ipa | |
| path: opencli_mobile/build/ios/ipa/*.ipa | |
| retention-days: 30 | |
| - name: Upload to App Store Connect | |
| env: | |
| APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} | |
| APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} | |
| run: | | |
| IPA_PATH=$(find opencli_mobile/build/ios/ipa -name "*.ipa" | head -n 1) | |
| if [ -z "$IPA_PATH" ]; then | |
| echo "❌ IPA file not found" | |
| exit 1 | |
| fi | |
| echo "🚀 Uploading IPA to App Store Connect..." | |
| echo "📦 IPA path: $IPA_PATH" | |
| xcrun altool --upload-app \ | |
| --type ios \ | |
| --file "$IPA_PATH" \ | |
| --apiKey "$APP_STORE_CONNECT_API_KEY_ID" \ | |
| --apiIssuer "$APP_STORE_CONNECT_ISSUER_ID" \ | |
| --apiKeyPath ~/private_keys/AuthKey_${APP_STORE_CONNECT_API_KEY_ID}.p8 | |
| echo "✅ IPA uploaded successfully to App Store Connect!" | |
| - name: Cleanup Keychain | |
| if: always() | |
| run: | | |
| KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db | |
| if [ -f "$KEYCHAIN_PATH" ]; then | |
| security delete-keychain $KEYCHAIN_PATH | |
| echo "🧹 Keychain cleaned up" | |
| fi | |
| - name: Create GitHub Release | |
| if: startsWith(github.ref, 'refs/tags/') | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| files: opencli_mobile/build/ios/ipa/*.ipa | |
| generate_release_notes: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| notify: | |
| name: Notify on completion | |
| needs: build-and-release-ios | |
| runs-on: ubuntu-latest | |
| if: always() | |
| steps: | |
| - name: Send notification | |
| run: | | |
| if [ "${{ needs.build-and-release-ios.result }}" == "success" ]; then | |
| echo "✅ iOS release to App Store completed successfully!" | |
| else | |
| echo "❌ iOS release to App Store failed!" | |
| exit 1 | |
| fi |