Настройка Code Signing через Fastlane Match
Сертификаты iOS — источник половины CI-инцидентов в мобильных командах. Разработчик уволился и унёс с собой Distribution Certificate, который был создан только на его машине. Сертификат истёк в пятницу вечером перед релизом. В CI No matching provisioning profiles found — и никто не понимает, почему локально собирается, а в пайплайне нет. Fastlane Match решает эти проблемы через единый зашифрованный репозиторий для всей команды.
Как работает Match
Match хранит сертификаты (.cer, .p12) и provisioning profiles (.mobileprovision) в зашифрованном Git-репозитории или S3/Google Cloud Storage. При запуске match на новой машине или в CI:
- Клонирует репозиторий
- Расшифровывает файлы паролем (
MATCH_PASSWORD) - Импортирует сертификат в временную keychain
- Устанавливает provisioning profile
Никакого ручного скачивания из Apple Developer Portal.
Первоначальная настройка
# Инициализация
fastlane match init
# Создание сертификатов и профилей (один раз)
fastlane match development
fastlane match appstore
fastlane match adhoc
Matchfile:
git_url("[email protected]:MyOrg/ios-certificates.git")
storage_mode("git")
type("appstore")
app_identifier(["com.myapp.ios", "com.myapp.ios.extension"])
username("[email protected]")
Важно: email должен принадлежать аккаунту с ролью не ниже App Manager. Лучше создать отдельного CI-пользователя в App Store Connect — тогда ротация паролей личных аккаунтов не ломает пайплайн.
Использование в CI
lane :release do
setup_ci # создаёт временную keychain, устанавливает MATCH_KEYCHAIN_NAME
match(
type: "appstore",
readonly: true,
git_url: ENV["MATCH_GIT_URL"],
password: ENV["MATCH_PASSWORD"],
keychain_name: ENV["MATCH_KEYCHAIN_NAME"],
keychain_password: ENV["MATCH_KEYCHAIN_PASSWORD"]
)
build_app(
scheme: "MyApp",
export_method: "app-store",
export_options: {
provisioningProfiles: {
"com.myapp.ios" => "match AppStore com.myapp.ios"
}
}
)
end
readonly: true критически важен в CI — без него match попытается создать новый сертификат, если не найдёт подходящий, что приведёт к конфликту с уже существующим в Apple Developer Portal.
Ротация сертификатов
Сертификаты Distribution живут 1 год. За 30 дней до истечения нужно запустить fastlane match --force_for_new_devices или fastlane match nuke + пересоздание. nuke отзывает все сертификаты данного типа — делать только если понимаешь последствия. После пересоздания все машины/CI автоматически получат новый сертификат при следующем match.
Несколько приложений и расширений
Если проект содержит App Extensions (Share Extension, Notification Service Extension, Widget), для каждого target нужен отдельный provisioning profile с соответствующим app_identifier. Match поддерживает массив: app_identifier(["com.myapp", "com.myapp.share", "com.myapp.widget"]).
Альтернатива: Xcode Automatic Signing в CI
Apple добавила xcodebuild -allowProvisioningUpdates — Xcode сам запрашивает профили через API. Работает, но требует Apple ID в keychain CI-агента и не подходит для GitHub Actions/GitLab CI без macOS self-hosted агента с постоянным хранилищем.
Процесс
Создание отдельного CI Apple ID → инициализация match репозитория → match init с нужными типами → тест на локальной машине → интеграция в Fastfile → добавление секретов в CI → тест в пайплайне.
Срок: 1–3 дня. Большая часть времени уходит на первоначальное создание сертификатов и профилей, особенно если проект содержит несколько targets. Стоимость рассчитывается индивидуально.







