Skip to content

iOS CI

iOS CI #11

Workflow file for this run

name: iOS CI
on:
push:
tags: [ 'v*' ]
schedule:
# GitHub Actions cron uses UTC: 21:00 UTC is 05:00 in Asia/Shanghai.
- cron: '0 21 * * *'
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
prepare-version:
name: Prepare version
runs-on: ubuntu-latest
outputs:
version_code: ${{ steps.version.outputs.version_code }}
version_name: ${{ steps.version.outputs.version_name }}
channel: ${{ steps.version.outputs.channel }}
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Resolve version
id: version
run: |
COMMIT_TIMESTAMP="$(git show -s --format=%ct HEAD)"
VERSION_CODE="$(TZ=Asia/Shanghai date -d "@${COMMIT_TIMESTAMP}" +%Y%m%d%H)"
if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then
VERSION_NAME="${GITHUB_REF_NAME#v}"
CHANNEL="release"
else
VERSION_NAME="$(awk -F= '/^appVersionName=/{print $2; exit}' gradle.properties)"
CHANNEL="pre-release"
fi
echo "version_code=${VERSION_CODE}" >> "$GITHUB_OUTPUT"
echo "version_name=${VERSION_NAME}" >> "$GITHUB_OUTPUT"
echo "channel=${CHANNEL}" >> "$GITHUB_OUTPUT"
build-ios:
name: Build iOS IPA
needs: prepare-version
runs-on: macos-15-intel
timeout-minutes: 60
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup JDK
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
- name: Setup Gradle cache
uses: gradle/actions/setup-gradle@v5
- name: Generate Kotlin framework for CocoaPods
run: ./gradlew :shared:core-native:generateDummyFramework
- name: Install CocoaPods dependencies
run: pod install --project-directory=iosApp
- name: Build unsigned IPA
env:
VERSION_CODE: ${{ needs.prepare-version.outputs.version_code }}
VERSION_NAME: ${{ needs.prepare-version.outputs.version_name }}
run: |
ARCHIVE_PATH="$PWD/build/ios/iosApp.xcarchive"
LOG_PATH="$PWD/build/ios/xcodebuild.log"
mkdir -p "$(dirname "${LOG_PATH}")"
xcodebuild \
-workspace iosApp/iosApp.xcworkspace \
-scheme iosApp \
-configuration Release \
-sdk iphoneos \
-jobs 1 \
-archivePath "${ARCHIVE_PATH}" \
-derivedDataPath "$PWD/build/ios/DerivedData" \
archive \
CODE_SIGNING_ALLOWED=NO \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGN_IDENTITY="" \
DEVELOPMENT_TEAM="" \
APP_VERSION_CODE="${VERSION_CODE}" \
APP_VERSION_NAME="${VERSION_NAME}" > "${LOG_PATH}" 2>&1 &
XCODEBUILD_PID=$!
while kill -0 "${XCODEBUILD_PID}" 2>/dev/null; do
sleep 60
echo "::notice::xcodebuild is still running; recent log output follows."
ps -o pid,etime,%mem,command -p "${XCODEBUILD_PID}" || true
pgrep -alf 'GradleDaemon|konanc|xcodebuild' || true
tail -n 60 "${LOG_PATH}" || true
done
if ! wait "${XCODEBUILD_PID}"; then
echo "::error::xcodebuild failed; final log output follows."
tail -n 200 "${LOG_PATH}" || true
exit 1
fi
tail -n 60 "${LOG_PATH}"
APP_PATH="$(find "${ARCHIVE_PATH}/Products/Applications" -maxdepth 1 -type d -name '*.app' -print -quit)"
test -n "${APP_PATH}"
mkdir -p build/ios/ipa/Payload
cp -R "${APP_PATH}" build/ios/ipa/Payload/
ditto -c -k --sequesterRsrc --keepParent build/ios/ipa/Payload build/ios/bangumi-ios.ipa
- name: Upload unsigned IPA
uses: actions/upload-artifact@v7
with:
name: ios-ipa
path: build/ios/bangumi-ios.ipa
if-no-files-found: error
publish-ios:
name: Publish iOS IPA
needs: [ prepare-version, build-ios ]
if: (github.event_name == 'schedule' || github.event_name == 'push' || github.event_name == 'workflow_dispatch') && success()
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Download IPA
uses: actions/download-artifact@v7
with:
name: ios-ipa
path: ios-release
- name: Upload IPA to rolling pre-release
if: needs.prepare-version.outputs.channel == 'pre-release'
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
VERSION_CODE: ${{ needs.prepare-version.outputs.version_code }}
VERSION_NAME: ${{ needs.prepare-version.outputs.version_name }}
run: |
RELEASE_TAG="pre-release"
RELEASE_NAME="Pre-release"
RELEASE_BODY="$(bash .github/scripts/release-notes.sh pre-release "${RELEASE_TAG}")"
if gh release view "${RELEASE_TAG}" >/dev/null 2>&1; then
gh release edit "${RELEASE_TAG}" --title "${RELEASE_NAME}" --prerelease --latest=false --target "${GITHUB_SHA}" --notes "${RELEASE_BODY}"
else
gh release create "${RELEASE_TAG}" --title "${RELEASE_NAME}" --prerelease --latest=false --target "${GITHUB_SHA}" --notes "${RELEASE_BODY}"
fi
gh release upload "${RELEASE_TAG}" ios-release/*.ipa --clobber
- name: Upload IPA to release
if: needs.prepare-version.outputs.channel == 'release'
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
VERSION_CODE: ${{ needs.prepare-version.outputs.version_code }}
VERSION_NAME: ${{ needs.prepare-version.outputs.version_name }}
run: |
RELEASE_TAG="${GITHUB_REF_NAME}"
RELEASE_NAME="Release ${VERSION_NAME}"
RELEASE_BODY="$(bash .github/scripts/release-notes.sh release "${RELEASE_TAG}")"
if gh release view "${RELEASE_TAG}" >/dev/null 2>&1; then
gh release edit "${RELEASE_TAG}" --title "${RELEASE_NAME}" --latest --notes "${RELEASE_BODY}"
else
gh release create "${RELEASE_TAG}" --title "${RELEASE_NAME}" --latest --target "${GITHUB_SHA}" --notes "${RELEASE_BODY}"
fi
gh release upload "${RELEASE_TAG}" ios-release/*.ipa --clobber