Skip to content

Instantly share code, notes, and snippets.

@huynguyencong
Last active September 11, 2024 11:15
Show Gist options
  • Save huynguyencong/004e98e4d9e7671f93fec280ddb7fc18 to your computer and use it in GitHub Desktop.
Save huynguyencong/004e98e4d9e7671f93fec280ddb7fc18 to your computer and use it in GitHub Desktop.
Script to build iOS and deploy it to TestFlight using GitHub action

When merging code to build/test-flight branch, it is built and uploaded to TestFlight automatically by GitHub Action.

Set up/update the following secrets:

  • CERTIFICATES_FILE_BASE64: Base64 of the App Store distribution certificate.
  • CERTIFICATES_PASSWORD: App Store distribution certificate password.
  • APPSTORE_ISSUER_ID: App Store Connect API key's issuer ID.
  • APPSTORE_KEY_ID: App Store Connect API key's key ID.
  • APPSTORE_PRIVATE_KEY: App Store Connect API key's private key (raw p8 file).

Get base64 of a file:

base64 -i <input-file> -o <output-file>

Update Support/ExportOptions.plist

Update it when changing provisioning entitlement, or when GitHub action is failed because of this file.
You can have the new file by exporting an IPA file using your Xcode, the new ExportOptions.plist file is in the same folder as the IPA file. Remove the teamID key. Then replace the old file with the new file.

The GitHub Action configuration follows this example from Apple-Actions' GitHub. Copy and update the Build file, the .yml file and create a Support/ExportOptions.plist file.

#!/usr/bin/env bash
set -xeu
set -o pipefail
# Note: Change "MyApp" to your project name
# Note: Use PROJECT instead of WORKSPACE if you build a project, not a workspace
function finish() {
ditto -c -k --sequesterRsrc --keepParent "${RESULT_BUNDLE_PATH}" "${RESULT_BUNDLE_PATH}.zip"
rm -rf "${RESULT_BUNDLE_PATH}"
}
trap finish EXIT
SDK="${SDK:-iphoneos}"
WORKSPACE="${WORKSPACE:-MyApp.xcworkspace}"
# PROJECT="${PROJECT:-MyApp.xcodeproj}"
SCHEME="${SCHEME:-MyApp}"
CONFIGURATION=${CONFIGURATION:-Release}
BUILD_DIR=${BUILD_DIR:-.build}
ARTIFACT_PATH=${RESULT_PATH:-${BUILD_DIR}/Artifacts}
RESULT_BUNDLE_PATH="${ARTIFACT_PATH}/${SCHEME}.xcresult"
ARCHIVE_PATH=${ARCHIVE_PATH:-${BUILD_DIR}/Archives/${SCHEME}.xcarchive}
DERIVED_DATA_PATH=${DERIVED_DATA_PATH:-${BUILD_DIR}/DerivedData}
CURRENT_PROJECT_VERSION=${BUILD_NUMBER:-0}
EXPORT_OPTIONS_FILE="Support/ExportOptions.plist"
rm -rf "${RESULT_BUNDLE_PATH}"
xcrun xcodebuild \
-workspace "${WORKSPACE}" \
# -project "${PROJECT}" \
-scheme "${SCHEME}" \
-configuration "${CONFIGURATION}" \
-sdk "${SDK}" \
-parallelizeTargets \
-showBuildTimingSummary \
-disableAutomaticPackageResolution \
-derivedDataPath "${DERIVED_DATA_PATH}" \
-archivePath "${ARCHIVE_PATH}" \
-resultBundlePath "${RESULT_BUNDLE_PATH}" \
CURRENT_PROJECT_VERSION="${CURRENT_PROJECT_VERSION}" \
archive
xcrun xcodebuild \
-exportArchive \
-exportOptionsPlist "${EXPORT_OPTIONS_FILE}" \
-archivePath "${ARCHIVE_PATH}" \
-exportPath "${ARTIFACT_PATH}/${SCHEME}.ipa"
# Zip up the Xcode Archive into Artifacts folder.
ditto -c -k --sequesterRsrc --keepParent "${ARCHIVE_PATH}" "${ARTIFACT_PATH}/${SCHEME}.xcarchive.zip"
name: "Build Test Flight"
on:
push:
branches:
- build/testflight
workflow_dispatch:
jobs:
build:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Import code sign
uses: Apple-Actions/import-codesign-certs@v1
with:
p12-file-base64: ${{ secrets.CERTIFICATES_FILE_BASE64 }}
p12-password: ${{ secrets.CERTIFICATES_PASSWORD }}
- name: Download provisioning
uses: Apple-Actions/download-provisioning-profiles@v1
with:
bundle-id: com.myApp.MyApp
issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }}
api-key-id: ${{ secrets.APPSTORE_KEY_ID }}
api-private-key: ${{ secrets.APPSTORE_PRIVATE_KEY }}
- run: ./Build
- name: Upload to TestFlight
uses: Apple-Actions/upload-testflight-build@master
with:
app-path: .build/Artifacts/MyApp.ipa/MyApp.ipa
issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }}
api-key-id: ${{ secrets.APPSTORE_KEY_ID }}
api-private-key: ${{ secrets.APPSTORE_PRIVATE_KEY }}
<?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>destination</key>
<string>export</string>
<key>manageAppVersionAndBuildNumber</key>
<true/>
<key>method</key>
<string>app-store</string>
<key>provisioningProfiles</key>
<dict>
<key>com.myapp.MyApp</key>
<string>MyApp profile</string>
</dict>
<key>signingCertificate</key>
<string>Apple Distribution</string>
<key>signingStyle</key>
<string>manual</string>
<key>stripSwiftSymbols</key>
<true/>
<key>uploadSymbols</key>
<true/>
</dict>
</plist>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment