Настройка автоматичної сборки iOS-додатків
Build Automation для iOS—це не просто «додати xcodebuild у CI». Це управління сертифікатами, provisioning profiles, схемами, конфігураціями, build number-ами та артефактами так, щоб сборка воспроізводилася однаково на будь-якій машині без ручного втручання.
Анатомія iOS-сборки та точки відмови
Типова команда сборки:
xcodebuild archive \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-configuration Release \
-destination generic/platform=iOS \
-archivePath build/MyApp.xcarchive \
CODE_SIGN_STYLE=Manual \
PROVISIONING_PROFILE_SPECIFIER="MyApp AdHoc" \
CODE_SIGN_IDENTITY="Apple Distribution: Acme Corp (XXXXXXXXXX)"
Чотири параметри кодування підписей—кожен може впасти з власної причини. CODE_SIGN_IDENTITY вимагає точного імені сертифіката з Keychain. PROVISIONING_PROFILE_SPECIFIER—точне імя профіля, встановленого на машині. На чистому CI-раннері ні того, ні іншого немає.
Стратегія рішення: fastlane match або ручна установка сертифіката + профіля через скрипт (описано далі).
Ручна установка сертифіката без fastlane
Якщо fastlane match не вписується:
#!/bin/bash
set -euo pipefail
# Створюємо тимчасовий keychain
KEYCHAIN_NAME="ci-build.keychain"
KEYCHAIN_PASS=$(openssl rand -hex 16)
security create-keychain -p "$KEYCHAIN_PASS" "$KEYCHAIN_NAME"
security set-keychain-settings -lut 7200 "$KEYCHAIN_NAME"
security unlock-keychain -p "$KEYCHAIN_PASS" "$KEYCHAIN_NAME"
security list-keychains -d user -s "$KEYCHAIN_NAME" login.keychain
# Імпортуємо сертифікат
echo "$DISTRIBUTION_CERT_BASE64" | base64 --decode > /tmp/cert.p12
security import /tmp/cert.p12 -k "$KEYCHAIN_NAME" \
-P "$CERT_PASSWORD" -T /usr/bin/codesign -T /usr/bin/xcodebuild
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASS" "$KEYCHAIN_NAME"
# Встановлюємо provisioning profile
PROFILE_PATH="$HOME/Library/MobileDevice/Provisioning Profiles"
mkdir -p "$PROFILE_PATH"
echo "$PROVISIONING_PROFILE_BASE64" | base64 --decode > "/tmp/profile.mobileprovision"
PROFILE_UUID=$(grep -a -A 1 'UUID' /tmp/profile.mobileprovision | grep string | sed 's/.*<string>//;s/<\/string>//')
cp /tmp/profile.mobileprovision "$PROFILE_PATH/$PROFILE_UUID.mobileprovision"
Скрипт параметризований через змінні оточення—всі секрети приходять з CI, не зберігаються в скрипті.
xcconfig та управління конфігураціями
Захардкодити Bundle ID, Team ID та Provisioning Profile у .pbxproj—шлях до конфліктів при мерже. Краще—xcconfig файли:
# Configurations/Release.xcconfig
PRODUCT_BUNDLE_IDENTIFIER = com.acme.myapp
DEVELOPMENT_TEAM = XXXXXXXXXX
PROVISIONING_PROFILE_SPECIFIER = MyApp AppStore
CODE_SIGN_IDENTITY = Apple Distribution
У Xcode: Project → Info → Configurations → вкажіть xcconfig для кожної. На CI передаємо PROVISIONING_PROFILE_SPECIFIER через environment, не переписуючи xcconfig.
Build Number: автоматизація без колізій
# З номера CI pipeline
BUILD_NUMBER=${CI_PIPELINE_IID:-$(git rev-list --count HEAD)}
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" MyApp/Info.plist
# Або через agvtool
xcrun agvtool new-version -all $BUILD_NUMBER
agvtool оновлює CFBundleVersion у всіх Info.plist проекту, включаючи Extensions—важливо для Watch, Notification Service, Share Extensions.
Export та артефакти
Після архівації—експорт .ipa:
xcodebuild -exportArchive \
-archivePath build/MyApp.xcarchive \
-exportPath build/export \
-exportOptionsPlist ExportOptions.plist
ExportOptions.plist—ключовий файл:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "...">
<plist version="1.0">
<dict>
<key>method</key>
<string>ad-hoc</string>
<key>teamID</key>
<string>XXXXXXXXXX</string>
<key>provisioningProfiles</key>
<dict>
<key>com.acme.myapp</key>
<string>MyApp AdHoc</string>
</dict>
<key>uploadBitcode</key>
<false/>
<key>thinning</key>
<string><none></string>
</dict>
</plist>
Для різних таргетів (основний + Extensions)—додавайте всі bundle ID в provisioningProfiles.
Сборка без Xcode: xcode-build-server + LSP
Для команд з CI без обмежень ліцензії на Xcode: xcode-build-server дозволяє використовувати xcodebuild з командної строки без відкриття Xcode. Корисно на headless Mac mini з мінімальним GUI.
Часова шкала
Базовий скрипт сборки з підписанням (без fastlane): 3–5 днів. Повна автоматизація з xcconfig, автоматичним build number, кількома таргетами, інтеграцією з CI-системою: 1–2 тижні. Стоимость рассчитывается индивидуально.







