[refactor] extract standalone iOS build workflow

This commit is contained in:
dijunkun
2026-10-01 23:31:51 +08:00
parent b2f6bd3204
commit e76cfecac8
5 changed files with 290 additions and 219 deletions
+256
View File
@@ -0,0 +1,256 @@
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:
patch:
description: "Optional patch number from the main build workflow."
required: false
type: string
default: "0"
outputs:
version:
description: "Independent iOS version and build date."
value: ${{ jobs.build.outputs.version }}
pull_request:
paths:
- ".github/workflows/build-ios.yml"
- ".github/workflows/build.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 }}
IOS_DEPLOYMENT_TARGET: "16.0"
EXPECTED_IOS_SDK: "26.5"
XMAKE_VERSION: "3.1.1"
XMAKE_REPO_REVISION: "121109352da272cd1a3d4ed52f2dcda34f839955"
steps:
- name: Extract version number
shell: bash
env:
PATCH_NUMBER: ${{ inputs.patch || '0' }}
run: |
VERSION_REF="${GITHUB_REF##*/}"
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
- name: Select corresponding source tag
shell: bash
run: |
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
echo "CROSSDESK_SOURCE_TAG=${GITHUB_REF_NAME}" >> "${GITHUB_ENV}"
echo "CROSSDESK_RELEASE_BUILD=YES" >> "${GITHUB_ENV}"
fi
- name: Read independent iOS version
id: ios_version
shell: bash
run: |
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 }')"
if [[ ! "${IOS_VERSION_BASE}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid iOS marketing version: ${IOS_VERSION_BASE}" >&2
exit 1
fi
VERSION_NUM="v${IOS_VERSION_BASE}-${VERSION_NUM##*-}"
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_VERSION }}-deps-ios-arm64-source-v1-xcode26.6-xrepo1211093-min16-${{ github.run_id }}"
restore-keys: |
${{ runner.os }}-xmake${{ env.XMAKE_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 -m unittest discover -s apps/ios/tests -p 'third_party_licenses_test.py' -v
python3 -B apps/ios/scripts/generate_third_party_licenses.py
- name: Verify iOS privacy controls
run: python3 -B -m unittest discover -s apps/ios/tests -p 'privacy_controls_test.py' -v
- name: Install xmake
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: "${{ env.XMAKE_VERSION }}"
- name: Verify xmake version
shell: bash
run: |
XMAKE_VERSION_OUTPUT="$(xmake --version)"
echo "${XMAKE_VERSION_OUTPUT}"
if [[ "${XMAKE_VERSION_OUTPUT}" != *"xmake v${XMAKE_VERSION}"* ]]; then
echo "Unexpected xmake version: expected ${XMAKE_VERSION}" >&2
exit 1
fi
- 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 \
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
+7 -218
View File
@@ -311,225 +311,14 @@ jobs:
mkdir -p release
cp crossdesk-macos-${{ matrix.arch }}-${{ env.VERSION_NUM }}.pkg release/
# iOS
# iOS (also available as a standalone workflow)
build-ios:
name: Build on iOS (arm64)
runs-on: macos-26
timeout-minutes: 120
outputs:
version: ${{ steps.ios_version.outputs.version }}
env:
IOS_DEPLOYMENT_TARGET: "16.0"
EXPECTED_IOS_SDK: "26.5"
XMAKE_VERSION: "3.1.1"
XMAKE_REPO_REVISION: "121109352da272cd1a3d4ed52f2dcda34f839955"
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
with:
fetch-depth: 0
- name: Select corresponding source tag
shell: bash
run: |
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
echo "CROSSDESK_SOURCE_TAG=${GITHUB_REF_NAME}" >> "${GITHUB_ENV}"
echo "CROSSDESK_RELEASE_BUILD=YES" >> "${GITHUB_ENV}"
fi
- name: Read independent iOS version
id: ios_version
shell: bash
run: |
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 }')"
if [[ ! "${IOS_VERSION_BASE}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid iOS marketing version: ${IOS_VERSION_BASE}" >&2
exit 1
fi
VERSION_NUM="v${IOS_VERSION_BASE}-${VERSION_NUM##*-}"
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_VERSION }}-deps-ios-arm64-source-v1-xcode26.6-xrepo1211093-min16-${{ github.run_id }}"
restore-keys: |
${{ runner.os }}-xmake${{ env.XMAKE_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 -m unittest discover -s apps/ios/tests -p 'third_party_licenses_test.py' -v
python3 -B apps/ios/scripts/generate_third_party_licenses.py
- name: Verify iOS privacy controls
run: python3 -B -m unittest discover -s apps/ios/tests -p 'privacy_controls_test.py' -v
- name: Install xmake
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: "${{ env.XMAKE_VERSION }}"
- name: Verify xmake version
shell: bash
run: |
XMAKE_VERSION_OUTPUT="$(xmake --version)"
echo "${XMAKE_VERSION_OUTPUT}"
if [[ "${XMAKE_VERSION_OUTPUT}" != *"xmake v${XMAKE_VERSION}"* ]]; then
echo "Unexpected xmake version: expected ${XMAKE_VERSION}" >&2
exit 1
fi
- 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 \
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
name: Build iOS
uses: ./.github/workflows/build-ios.yml
with:
patch: ${{ inputs.patch || '0' }}
permissions:
contents: read
# Android (also available as a standalone workflow)
build-android:
+23 -1
View File
@@ -59,7 +59,7 @@ and builds their dependencies, then merges the iPhoneOS archives into a local li
`Vendor/`. OpenSSL is kept separate and packaged as a static framework with SDK
privacy resources in the Xcode products directory. This build path targets physical devices; simulator builds are
not supported. The exact tool versions used by CI are recorded in the
[workflow](../../.github/workflows/build.yml).
[iOS workflow](../../.github/workflows/build-ios.yml).
You can also build the target without code signing. The resulting app, like
the unsigned CI artifact, requires signing before device installation:
@@ -77,6 +77,28 @@ for that server. Remote control sessions then log in as `C-<identity>` and use
the desktop-compatible `DisplayN`, `control_audio`, `mouse`, `keyboard`,
`control_data`, `clipboard`, `file`, and `file_feedback` streams.
## GitHub Actions
[`Build iOS`](../../.github/workflows/build-ios.yml) can run independently from
the Actions page. Pull requests changing the iOS app, MiniRTC, shared wire code
or relevant build configuration also trigger it. The main
[`Build and Release`](../../.github/workflows/build.yml) workflow calls the same
workflow on branch/tag pushes and manual runs, and waits for its result before
publishing a version-tag release.
The workflow retains the pinned Xcode/SDK and Xmake versions, dependency cache,
license and privacy checks, unsigned arm64 Release build, and app-bundle
verification. It uploads `crossdesk-ios-arm64-unsigned-v<marketing-version>-<date>.zip`,
including the app, source metadata, third-party source catalog, rights notice
and any generated dSYM. The version comes from the iOS target; dated repository
tags provide the build date, otherwise the date uses the Asia/Shanghai timezone.
The main workflow collects this same ZIP for GitHub Releases and the download
server. Standalone runs only upload the build artifact.
No Apple signing secrets are needed. Sign the app yourself before installing
it on a device. Push any referenced MiniRTC commit before the parent repository
so the runner can check out all corresponding sources.
## Announcements
The home toolbar's bell opens **通知公告** and shows the unread count (capped
+2
View File
@@ -238,6 +238,8 @@ xmake r -d crossdesk
原生客户端使用独立 Xcode 工程,要求 iOS 16+ 的 arm64 真机。构建与音视频、文件传输验证步骤见 [iOS 开发说明](../apps/ios/README.md)。当前 CI 导出未签名应用,真机安装需要自行签名。
[iOS CI](../.github/workflows/build-ios.yml) 可独立手动运行,并由主构建工作流调用;相关 Pull Request 也会触发。工具链、许可证及隐私检查、应用验证和 ZIP 打包沿用现有流程,标签发布继续收集同名的未签名应用归档。
## 更新界面截图
README 的桌面图片直接由当前 Slint UI 渲染,复现方式见 [截图说明](images/README.md)。
+2
View File
@@ -250,6 +250,8 @@ For more information, please refer to the [official Xmake documentation](https:/
The native client has a separate Xcode project and requires an arm64 physical device running iOS 16+. See the [iOS development guide](../apps/ios/README.md) for build and media/file-transfer checks. CI exports an unsigned app; device installation requires your own signing.
[iOS CI](../.github/workflows/build-ios.yml) can run manually on its own, is called by the main build workflow, and runs for relevant pull requests. It retains the existing toolchain, license/privacy checks, app verification and ZIP packaging. Tag releases continue to collect the unsigned app archive under the same artifact name.
## Refreshing screenshots
Desktop README images are rendered directly from the current Slint UI. See the [screenshot notes](images/README.md) for reproduction commands.