Created
October 15, 2025 13:43
-
-
Save husnaintahir/2b9af02e2a20cf5e8afa0093e4f07226 to your computer and use it in GitHub Desktop.
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 TestFlight Deployment | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| release: | |
| description: "Trigger release to TestFlight" | |
| required: true | |
| default: "true" | |
| type: choice | |
| options: [ "true", "false" ] | |
| version: | |
| description: "App version (e.g. 1.0.0)" | |
| default: "0.1.4" | |
| required: true | |
| buildNumber: | |
| description: "Build number (e.g. 1)" | |
| default: "3" | |
| required: true | |
| jobs: | |
| build-ios: | |
| runs-on: macos-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '18' | |
| - name: Install dependencies | |
| run: npm install | |
| - name: Setup Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: '16.0' | |
| - name: Setup Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: '3.2' | |
| - name: Install CocoaPods | |
| run: gem install cocoapods | |
| - name: Patch xcodeproj for Xcode 16 compatibility | |
| run: | | |
| XCODEPROJ_PATH=$(gem which xcodeproj | sed 's/\.rb$//') | |
| CONSTANTS_FILE="$XCODEPROJ_PATH/project/object/native_target.rb" | |
| # Add support for object version 70 | |
| if [ -f "$CONSTANTS_FILE" ]; then | |
| sed -i '' "s/LAST_KNOWN_OBJECT_VERSION = '[0-9]*'/LAST_KNOWN_OBJECT_VERSION = '70'/" "$CONSTANTS_FILE" 2>/dev/null || true | |
| fi | |
| # Alternative: directly patch the constants | |
| ruby -i -pe "gsub(/LAST_KNOWN_OBJECT_VERSION = '[0-9]*'/, \"LAST_KNOWN_OBJECT_VERSION = '70'\")" $(gem which xcodeproj/project/object/native_target.rb) 2>/dev/null || true | |
| - name: Install CocoaPods dependencies | |
| run: | | |
| cd ios | |
| pod install --repo-update | |
| cd .. | |
| - name: Setup Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: 'latest-stable' | |
| - name: Create temporary keychain | |
| run: | | |
| security create-keychain -p "${{ secrets.APPLE_CERT_PASSWORD }}" build.keychain | |
| security default-keychain -s build.keychain | |
| security unlock-keychain -p "${{ secrets.APPLE_CERT_PASSWORD }}" build.keychain | |
| security set-keychain-settings -t 3600 -u build.keychain | |
| - name: Import certificate | |
| run: | | |
| echo "${{ secrets.APPLE_CERT_P12 }}" | base64 --decode > certificate.p12 | |
| security import certificate.p12 -k build.keychain -P "${{ secrets.APPLE_CERT_PASSWORD }}" -T /usr/bin/codesign | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${{ secrets.APPLE_CERT_PASSWORD }}" build.keychain | |
| rm certificate.p12 | |
| - name: Install provisioning profiles | |
| run: | | |
| mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles | |
| # Decode and save provisioning profiles | |
| echo "${{ secrets.APPLE_MATCH_PROVISIONING_PROFILE }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/ios_distribution_provision.mobileprovision | |
| echo "${{ secrets.APPLE_EXTENSION_PROVISION_PROFILE }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/ios_extension_provision.mobileprovision | |
| echo "β Installed provisioning profiles:" | |
| ls -l ~/Library/MobileDevice/Provisioning\ Profiles | |
| echo "π Profile names detected:" | |
| /usr/libexec/PlistBuddy -c "Print :Name" ~/Library/MobileDevice/Provisioning\ Profiles/ios_distribution_provision.mobileprovision || true | |
| /usr/libexec/PlistBuddy -c "Print :Name" ~/Library/MobileDevice/Provisioning\ Profiles/ios_extension_provision.mobileprovision || true | |
| - name: Update version and build number | |
| run: | | |
| cd ios | |
| agvtool new-marketing-version ${{ github.event.inputs.version }} | |
| agvtool new-version -all ${{ github.event.inputs.buildNumber }} | |
| cd .. | |
| - name: Patch provisioning profile in Xcode project | |
| run: | | |
| cd ios | |
| echo "π Injecting provisioning profile into project settings..." | |
| /usr/libexec/PlistBuddy -c "Set :objects:$(/usr/libexec/PlistBuddy -c 'Print :rootObject' MyApp.xcodeproj/project.pbxproj):attributes:TargetAttributes:$(grep -A1 'MyApp' MyApp.xcodeproj/project.pbxproj | grep -Eo '[A-F0-9]{24}' | head -1):ProvisioningStyle Manual" MyApp.xcodeproj/project.pbxproj || true | |
| - name: Build iOS app | |
| run: | | |
| cd ios | |
| xcodebuild -workspace MyApp.xcworkspace \ | |
| -scheme MyApp \ | |
| -configuration Release \ | |
| -destination generic/platform=iOS \ | |
| -archivePath $PWD/build/App.xcarchive \ | |
| clean archive \ | |
| CODE_SIGN_STYLE=Manual \ | |
| DEVELOPMENT_TEAM=[MY_TEAM_ID] \ | |
| CODE_SIGN_IDENTITY="Apple Distribution" \ | |
| OTHER_CODE_SIGN_FLAGS="--verbose" \ | |
| ONLY_ACTIVE_ARCH=NO | |
| - name: Export IPA | |
| run: | | |
| cd ios | |
| echo "π¦ Exporting IPA..." | |
| xcodebuild -exportArchive \ | |
| -archivePath $PWD/build/App.xcarchive \ | |
| -exportOptionsPlist exportOptions.plist \ | |
| -exportPath $PWD/build \ | |
| -allowProvisioningUpdates \ | |
| -verbose | |
| - name: Create App Store Connect API Key | |
| run: | | |
| mkdir -p ~/.appstoreconnect/private_keys | |
| echo "${{ secrets.APPLE_APP_STORE_CONNECT_API_KEY }}" | base64 --decode > ~/.appstoreconnect/private_keys/AuthKey_${{ secrets.APPLE_APP_STORE_CONNECT_API_KEY_ID }}.p8 | |
| - name: Upload to TestFlight | |
| if: github.event.inputs.release == 'true' | |
| run: | | |
| echo "π Uploading to TestFlight..." | |
| xcrun altool --upload-app \ | |
| -f ios/build/*.ipa \ | |
| -t ios \ | |
| --apiKey ${{ secrets.APPLE_APP_STORE_CONNECT_API_KEY_ID }} \ | |
| --apiIssuer ${{ secrets.APPLE_APP_STORE_CONNECT_API_ISSUER_ID }} | |
| - name: Upload IPA as artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ios-app-${{ github.event.inputs.version }}-${{ github.event.inputs.buildNumber }} | |
| path: ios/build/*.ipa | |
| retention-days: 30 | |
| - name: Cleanup | |
| if: always() | |
| run: | | |
| security delete-keychain build.keychain | |
| rm -rf ~/Library/MobileDevice/Provisioning\ Profiles | |
| rm -rf ~/.appstoreconnect |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment