name: Build iOS on: push: branches: - "**" - "!ci/linux-build-image" tags: - "*" workflow_dispatch: inputs: patch: description: "Hotfix patch number, for example 1 or 2. Use 0 for a normal build." required: false default: "0" permissions: contents: read env: IOS_DEPLOYMENT_TARGET: "16.0" EXPECTED_IOS_SDK: "26.5" jobs: build-ios: name: Build iOS (arm64) runs-on: macos-26 timeout-minutes: 120 steps: - name: Extract version number shell: bash run: | VERSION_REF="${GITHUB_REF##*/}" VERSION_BASE="${VERSION_REF#v}" BUILD_DATE=$(TZ=Asia/Shanghai date +%Y%m%d) PATCH_NUMBER="${{ github.event.inputs.patch }}" if [[ ! "${PATCH_NUMBER}" =~ ^[0-9]+$ ]]; then PATCH_NUMBER=0 fi if [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]+)-([0-9]{8})$ ]]; then VERSION_BASE="${BASH_REMATCH[1]}" PATCH_NUMBER="${BASH_REMATCH[3]}" BUILD_DATE="${BASH_REMATCH[4]}" elif [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then VERSION_BASE="${BASH_REMATCH[1]}" BUILD_DATE="${BASH_REMATCH[3]}" PATCH_NUMBER="${BASH_REMATCH[4]}" elif [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})$ ]]; then VERSION_BASE="${BASH_REMATCH[1]}" BUILD_DATE="${BASH_REMATCH[3]}" elif [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]+)$ && "${PATCH_NUMBER}" == "0" ]]; then VERSION_BASE="${BASH_REMATCH[1]}" PATCH_NUMBER="${BASH_REMATCH[3]}" fi if [[ "${PATCH_NUMBER}" != "0" ]]; then VERSION_NUM="v${VERSION_BASE}-${PATCH_NUMBER}-${BUILD_DATE}" else VERSION_NUM="v${VERSION_BASE}-${BUILD_DATE}" fi echo "VERSION_NUM=${VERSION_NUM}" >> "${GITHUB_ENV}" echo "VERSION_NUM=${VERSION_NUM}" - name: Select Xcode 26.6 shell: bash run: | sudo xcode-select -s /Applications/Xcode_26.6.app/Contents/Developer xcodebuild -version SDK_VERSION="$(xcrun --sdk iphoneos --show-sdk-version)" if [[ "${SDK_VERSION}" != "${EXPECTED_IOS_SDK}" ]]; then echo "Unexpected iOS SDK: expected ${EXPECTED_IOS_SDK}, got ${SDK_VERSION}" >&2 exit 1 fi - name: Checkout code uses: actions/checkout@v5 - name: Initialize submodules run: git submodule update --init --recursive - name: Cache xmake dependencies uses: actions/cache@v5 with: path: ios/.xmake/packages key: "${{ runner.os }}-xmake-deps-ios-arm64-xcode26.6-python3.13-min16-${{ github.run_id }}" restore-keys: | ${{ runner.os }}-xmake-deps-ios-arm64-xcode26.6-python3.13-min16- - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.13" - name: Install xmake run: brew install xmake - name: Update xmake repositories run: xmake repo -u - name: Build CrossDesk Mobile shell: bash run: | DERIVED_DATA="${RUNNER_TEMP}/CrossDeskMobileDerivedData" echo "DERIVED_DATA=${DERIVED_DATA}" >> "${GITHUB_ENV}" xcodebuild \ -project ios/CrossDeskMobile.xcodeproj \ -scheme CrossDeskMobile \ -configuration Release \ -destination 'generic/platform=iOS' \ -derivedDataPath "${DERIVED_DATA}" \ CODE_SIGNING_ALLOWED=NO \ CODE_SIGNING_REQUIRED=NO \ COMPILER_INDEX_STORE_ENABLE=NO \ IPHONEOS_DEPLOYMENT_TARGET="${IOS_DEPLOYMENT_TARGET}" \ build - name: Verify CrossDesk Mobile shell: bash run: | APP_PATH="${DERIVED_DATA}/Build/Products/Release-iphoneos/CrossDeskMobile.app" EXECUTABLE_PATH="${APP_PATH}/CrossDeskMobile" INFO_PLIST="${APP_PATH}/Info.plist" if [[ ! -x "${EXECUTABLE_PATH}" ]]; then echo "CrossDeskMobile executable is missing from ${APP_PATH}" >&2 exit 1 fi xcrun lipo "${EXECUTABLE_PATH}" -verify_arch arm64 MINIMUM_OS=$(/usr/libexec/PlistBuddy -c 'Print :MinimumOSVersion' "${INFO_PLIST}") if [[ "${MINIMUM_OS}" != "${IOS_DEPLOYMENT_TARGET}" ]]; then echo "Unexpected minimum iOS version: expected ${IOS_DEPLOYMENT_TARGET}, got ${MINIMUM_OS}" >&2 exit 1 fi xcrun lipo -info "${EXECUTABLE_PATH}" echo "Minimum iOS version: ${MINIMUM_OS}" - name: Package CrossDesk Mobile shell: bash run: | APP_PATH="${DERIVED_DATA}/Build/Products/Release-iphoneos/CrossDeskMobile.app" PACKAGE_DIR="${RUNNER_TEMP}/crossdesk-ios-arm64-unsigned-${VERSION_NUM}" PACKAGE_FILE="${GITHUB_WORKSPACE}/crossdesk-ios-arm64-unsigned-${VERSION_NUM}.zip" mkdir -p "${PACKAGE_DIR}" cp -R "${APP_PATH}" "${PACKAGE_DIR}/" DSYM_PATH="${DERIVED_DATA}/Build/Products/Release-iphoneos/CrossDeskMobile.app.dSYM" if [[ -d "${DSYM_PATH}" ]]; then cp -R "${DSYM_PATH}" "${PACKAGE_DIR}/" fi ditto -c -k --sequesterRsrc --keepParent "${PACKAGE_DIR}" "${PACKAGE_FILE}" echo "PACKAGE_FILE=${PACKAGE_FILE}" >> "${GITHUB_ENV}" - name: Upload build artifact uses: actions/upload-artifact@v6 with: name: crossdesk-ios-arm64-unsigned-${{ env.VERSION_NUM }} path: ${{ env.PACKAGE_FILE }} if-no-files-found: error