mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-15 00:09:39 +08:00
273 lines
10 KiB
YAML
273 lines
10 KiB
YAML
name: Build iOS
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
patch:
|
|
description: "Optional patch number, matching the main build workflow."
|
|
required: false
|
|
type: string
|
|
default: "0"
|
|
workflow_call:
|
|
inputs:
|
|
source_tag:
|
|
description: "Existing source tag for a standalone iOS release."
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
patch:
|
|
description: "Optional patch number from the main build workflow."
|
|
required: false
|
|
type: string
|
|
default: "0"
|
|
outputs:
|
|
version:
|
|
description: "iOS artifact version; combined releases match the desktop tag."
|
|
value: ${{ jobs.build.outputs.version }}
|
|
pull_request:
|
|
paths:
|
|
- ".github/workflows/build-ios.yml"
|
|
- ".github/workflows/build.yml"
|
|
- ".github/workflows/release-mobile.yml"
|
|
- ".gitmodules"
|
|
- "LICENSE"
|
|
- "apps/ios/**"
|
|
- "deps/submodules/minirtc"
|
|
- "libs/wire/**"
|
|
- "xmake.lua"
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
build:
|
|
name: Build on iOS (arm64)
|
|
runs-on: macos-26
|
|
timeout-minutes: 120
|
|
outputs:
|
|
version: ${{ steps.ios_version.outputs.version }}
|
|
env:
|
|
GITHUB_TOKEN: ${{ github.token }}
|
|
CROSSDESK_SOURCE_TAG: ${{ inputs.source_tag || '' }}
|
|
IOS_DEPLOYMENT_TARGET: "16.0"
|
|
EXPECTED_IOS_SDK: "26.5"
|
|
# Exercise the minimum supported version; local builds may use newer Xmake.
|
|
XMAKE_MIN_VERSION: "3.1.1"
|
|
XMAKE_REPO_REVISION: "121109352da272cd1a3d4ed52f2dcda34f839955"
|
|
|
|
steps:
|
|
- name: Extract version number
|
|
shell: bash
|
|
env:
|
|
PATCH_NUMBER: ${{ inputs.patch || '0' }}
|
|
run: |
|
|
VERSION_REF="${CROSSDESK_SOURCE_TAG:-${GITHUB_REF##*/}}"
|
|
VERSION_REF="${VERSION_REF#ios-}"
|
|
VERSION_BASE="${VERSION_REF#v}"
|
|
BUILD_DATE=$(TZ=Asia/Shanghai date +%Y%m%d)
|
|
|
|
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
|
|
with:
|
|
fetch-depth: 0
|
|
ref: ${{ inputs.source_tag || github.ref }}
|
|
|
|
- name: Select corresponding source tag
|
|
shell: bash
|
|
run: |
|
|
if [[ -n "${CROSSDESK_SOURCE_TAG}" ]]; then
|
|
echo "CROSSDESK_RELEASE_BUILD=YES" >> "${GITHUB_ENV}"
|
|
elif [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
|
|
echo "CROSSDESK_SOURCE_TAG=${GITHUB_REF_NAME}" >> "${GITHUB_ENV}"
|
|
echo "CROSSDESK_RELEASE_BUILD=YES" >> "${GITHUB_ENV}"
|
|
fi
|
|
|
|
- name: Resolve iOS version
|
|
id: ios_version
|
|
shell: bash
|
|
run: |
|
|
if [[ "${CROSSDESK_SOURCE_TAG}" == v* ]]; then
|
|
# Combined releases share the desktop version, including the date
|
|
# and optional hotfix suffix in the artifact filename.
|
|
IOS_VERSION_BASE="${VERSION_NUM#v}"
|
|
IOS_VERSION_BASE="${IOS_VERSION_BASE%%-*}"
|
|
else
|
|
IOS_VERSION_BASE="$(xcodebuild \
|
|
-project apps/ios/CrossDeskMobile.xcodeproj \
|
|
-scheme CrossDeskMobile \
|
|
-configuration Release \
|
|
-destination 'generic/platform=iOS' \
|
|
-showBuildSettings CODE_SIGNING_ALLOWED=NO | \
|
|
awk '$1 == "MARKETING_VERSION" && $2 == "=" { print $3 }')"
|
|
VERSION_NUM="v${IOS_VERSION_BASE}-${VERSION_NUM##*-}"
|
|
fi
|
|
if [[ ! "${IOS_VERSION_BASE}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
echo "Invalid iOS marketing version: ${IOS_VERSION_BASE}" >&2
|
|
exit 1
|
|
fi
|
|
if [[ "${CROSSDESK_SOURCE_TAG}" == ios-v* && "${CROSSDESK_SOURCE_TAG#ios-}" != "${VERSION_NUM}" ]]; then
|
|
echo "iOS source tag does not match the app version: ${CROSSDESK_SOURCE_TAG} vs ${VERSION_NUM}" >&2
|
|
exit 1
|
|
fi
|
|
echo "IOS_VERSION_BASE=${IOS_VERSION_BASE}" >> "${GITHUB_ENV}"
|
|
echo "VERSION_NUM=${VERSION_NUM}" >> "${GITHUB_ENV}"
|
|
echo "version=${VERSION_NUM}" >> "${GITHUB_OUTPUT}"
|
|
|
|
- name: Initialize submodules
|
|
run: git submodule update --init --recursive
|
|
|
|
- name: Cache xmake dependencies
|
|
uses: actions/cache@v5
|
|
with:
|
|
path: apps/ios/.xmake/packages
|
|
key: "${{ runner.os }}-xmake${{ env.XMAKE_MIN_VERSION }}-deps-ios-arm64-source-v1-xcode26.6-xrepo1211093-min16-${{ github.run_id }}"
|
|
restore-keys: |
|
|
${{ runner.os }}-xmake${{ env.XMAKE_MIN_VERSION }}-deps-ios-arm64-source-v1-xcode26.6-xrepo1211093-min16-
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v6
|
|
with:
|
|
python-version: "3.13"
|
|
|
|
- name: Verify iOS license catalog
|
|
run: python3 -B apps/ios/scripts/generate_third_party_licenses.py
|
|
|
|
- name: Install xmake
|
|
uses: xmake-io/github-action-setup-xmake@v1
|
|
with:
|
|
xmake-version: "${{ env.XMAKE_MIN_VERSION }}"
|
|
|
|
- name: Verify minimum xmake version
|
|
shell: bash
|
|
run: |
|
|
xmake --version | tee "${RUNNER_TEMP}/xmake-version.txt"
|
|
python3 -B apps/ios/scripts/generate_third_party_licenses.py \
|
|
--xmake-version "${RUNNER_TEMP}/xmake-version.txt"
|
|
|
|
- name: Pin xmake package repository
|
|
shell: bash
|
|
run: |
|
|
xmake repo -u
|
|
XMAKE_REPO_DIR="${HOME}/.xmake/repositories/xmake-repo"
|
|
git -C "${XMAKE_REPO_DIR}" fetch --depth=1 origin "${XMAKE_REPO_REVISION}"
|
|
git -C "${XMAKE_REPO_DIR}" checkout --detach "${XMAKE_REPO_REVISION}"
|
|
test "$(git -C "${XMAKE_REPO_DIR}" rev-parse HEAD)" = "${XMAKE_REPO_REVISION}"
|
|
|
|
- name: Build CrossDesk Mobile
|
|
shell: bash
|
|
run: |
|
|
DERIVED_DATA="${RUNNER_TEMP}/CrossDeskMobileDerivedData"
|
|
echo "DERIVED_DATA=${DERIVED_DATA}" >> "${GITHUB_ENV}"
|
|
xcodebuild \
|
|
-project apps/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 \
|
|
MARKETING_VERSION="${IOS_VERSION_BASE}" \
|
|
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
|
|
APP_VERSION=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "${INFO_PLIST}")
|
|
if [[ "${APP_VERSION}" != "${IOS_VERSION_BASE}" ]]; then
|
|
echo "Unexpected iOS app version: expected ${IOS_VERSION_BASE}, got ${APP_VERSION}" >&2
|
|
exit 1
|
|
fi
|
|
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
|
|
|
|
VERIFY_FLAGS=()
|
|
if [[ "${CROSSDESK_RELEASE_BUILD:-NO}" == "YES" ]]; then
|
|
VERIFY_FLAGS+=(--require-release)
|
|
fi
|
|
python3 apps/ios/scripts/verify_app_bundle.py "${APP_PATH}" "${VERIFY_FLAGS[@]}"
|
|
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}/"
|
|
cp apps/ios/licenses/sources.json "${PACKAGE_DIR}/ThirdPartySources.json"
|
|
cp apps/ios/licenses/OPEN_SOURCE_NOTICE.txt "${PACKAGE_DIR}/OPEN_SOURCE_NOTICE.txt"
|
|
cp "${APP_PATH}/SourceMetadata.json" "${PACKAGE_DIR}/SourceMetadata.json"
|
|
|
|
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
|