Хотя идея выпуска новой версии нашего приложения с новыми функциями и устранением множества ошибок звучит приятно, реальность такова, что ручной процесс громоздкий и трудоемкий, что делает этот процесс не очень приятным.
Чтобы облегчить эту боль, я автоматизировал этот процесс с помощью CircleCI. Это был нелегкий путь из-за плохой документации и отсутствия рабочих примеров. Иногда у меня было ощущение, что некоторые части документации устарели и не поддерживаются.
В следующей статье вы найдете процесс, которому я следовал, чтобы автоматизировать процесс выпуска приложений для iOS, включая примечания к выпуску и ссылки на всю документацию и примеры, которые я использовал.
🔐 Определите настройки учетной записи App Store Connect и переменные среды CircleCI
Во-первых, нам нужно собрать все связанные идентификаторы, чтобы иметь возможность подключаться к App Store Connect API.
Создайте файл приложения
Нам нужно создать файл приложения, содержащий идентификатор пакета или идентификатор приложения и адрес электронной почты нашей учетной записи Apple:
your_project/ios/fastlane/Appfile app_identifier("com.bla.bla") # The bundle identifier of your app apple_id("[email protected]") # Your Apple email address
Создайте настройки выпуска
В начале файла Fastfile мы определим идентификатор приложения, профиль обеспечения и идентификатор команды, которые будут использоваться на полосе выпуска. Это очень полезно, потому что если у нас есть другие дорожки, такие как Adhoc, мы можем определить разные объекты конфигурации для использования в зависимости от дорожки:
your_project/ios/fastlane/Fastfile APP_ID = "com.bla.bla" PROVISIONING_PROFILE_APPSTORE = "match AppStore com.bla.bla" TEAM_ID = "your_team_id" settings_to_override_release = { :BUNDLE_IDENTIFIER => APP_ID, :PROVISIONING_PROFILE_SPECIFIER => PROVISIONING_PROFILE_APPSTORE, :DEVELOPMENT_TEAM => TEAM_ID, }
Создайте ключ API и добавьте его в переменные среды CircleCI.
Во-первых, нам нужно получить key_id, issuer_id и key_content из нашей учетной записи App Store Connect. Мы можем получить их отсюда:
Во-вторых, мы должны создать переменные среды CircleCI для этих значений, перейдя в ваш проект › ⚙️ Настройки проекта › Переменные среды › Добавить переменную среды.
Наконец, используя команду app_store_connect_api_key в нашем Fastfile, мы прочитаем значения ключа API, ранее определенные как переменные среды, и, таким образом, мы сможем идентифицировать себя в App Store Connect API для доступа и отправки нашего проекта. данные.
your_project/ios/fastlane/Fastfile desc "Export Release IPA & upload Release to App Store" lane :release_ipa do api_key = app_store_connect_api_key( key_id: $APP_STORE_CONNECT_API_KEY_KEY_ID, issuer_id: $APP_STORE_CONNECT_API_KEY_ISSUER_ID, key_content: $APP_STORE_CONNECT_API_KEY_KEY ) end
Делая это таким образом, рекомендуется избегать фактора аутентификации 2, который запрашивается при входе в систему с использованием пользователя и пароля.
🚀 Определите полосу выпуска Fastfile
Нам нужно создать новую полосу, чтобы указать необходимые шаги для успешного выполнения нового выпуска в App Store Connect.
Создать полосу release_ipa
Давайте вернемся к нашему Fastfile, в этом файле мы определим все нужные полосы, связанные с процессами iOS, такие как экспорт adhoc IPA, экспорт IPA выпуска или создание нового выпуска и загрузка IPA выпуска в Магазин приложений.
В этой статье будет рассказано о создании полосы для запуска нового релиза в App Store, помимо генерации IPA и загрузки в новый релиз.
➕ Увеличение номера сборки
Мы продолжим разработку нашей линии release_ipa, добавив вызов increment_build_number:
your_project/ios/fastlane/Fastfile desc "Export Release IPA & upload Release to App Store" lane :release_ipa do api_key = app_store_connect_api_key( key_id: $APP_STORE_CONNECT_API_KEY_KEY_ID, issuer_id: $APP_STORE_CONNECT_API_KEY_ISSUER_ID, key_content: $APP_STORE_CONNECT_API_KEY_KEY ) increment_build_number( build_number: app_store_build_number( api_key: api_key, initial_build_number: 0, version: get_version_number(xcodeproj: "your_project.xcodeproj"), live: false ) + 1, ) end
Этот фрагмент кода будет очень полезен при загрузке нескольких сборок для пользователей Testflight. Автоматически назначает следующую версию сборки с учетом того, существует ли IPA для нового выпуска.
Учтите, что этот вызов должен включать учетные данные api_key, это недостаточно документировано в официальных документах. Подробнее о app_store_build_number.
🔑 команда соответствия
Вызов match — это то, где мы определяем тип разрешений / профилей обеспечения, применяемых к App Store, в этом случае ключевое слово type, назначенное режиму выпуска, — appstore
.
your_project/ios/fastlane/Fastfile desc "Export Release IPA & upload Release to App Store" lane :release_ipa do api_key = app_store_connect_api_key( key_id: $APP_STORE_CONNECT_API_KEY_KEY_ID, issuer_id: $APP_STORE_CONNECT_API_KEY_ISSUER_ID, key_content: $APP_STORE_CONNECT_API_KEY_KEY ) increment_build_number( build_number: app_store_build_number( api_key: api_key, initial_build_number: 0, version: get_version_number(xcodeproj: "your_project.xcodeproj"), live: false ) + 1, ) match( app_identifier: APP_ID, readonly: is_ci, type:"appstore" ) end
🏗 команда сборки приложения
Вызов build_app создает IPA с желаемой конфигурацией. В следующем фрагменте кода вы можете увидеть, как установить конфигурацию Release:
your_project/ios/fastlane/Fastfile desc "Export Release IPA & upload Release to App Store" lane :release_ipa do api_key = app_store_connect_api_key( key_id: $APP_STORE_CONNECT_API_KEY_KEY_ID, issuer_id: $APP_STORE_CONNECT_API_KEY_ISSUER_ID, key_content: $APP_STORE_CONNECT_API_KEY_KEY ) increment_build_number( build_number: app_store_build_number( api_key: api_key, initial_build_number: 0, version: get_version_number(xcodeproj: "your_project.xcodeproj"), live: false ) + 1, ) match( app_identifier: APP_ID, readonly: is_ci, type:"appstore" ) build_app( scheme:"your_project_name", export_method:"app-store", skip_profile_detection:true, configuration: "Release", workspace: "your_project_name.xcworkspace", xcargs: settings_to_override_release, export_options: { provisioningProfiles: { APP_ID => PROVISIONING_PROFILE_APPSTORE }, installerSigningCertificate: "your_installer_signing_certificate_name" } ) end
🛵 доставить команду
Вызов доставить создает новую версию в App Store, а затем загружает двоичный файл IPA, сгенерированный на этапе build_app:
your_project/ios/fastlane/Fastfile APP_ID = "com.bla.bla" PROVISIONING_PROFILE_APPSTORE = "match AppStore com.bla.bla" TEAM_ID = "your_team_id" settings_to_override_release = { :BUNDLE_IDENTIFIER => APP_ID, :PROVISIONING_PROFILE_SPECIFIER => PROVISIONING_PROFILE_APPSTORE, :DEVELOPMENT_TEAM => TEAM_ID, } default_platform(:ios) platform :ios do before_all do setup_circle_ci end desc "Export Release IPA & upload Release to App Store" lane :release_ipa do api_key = app_store_connect_api_key( key_id: $APP_STORE_CONNECT_API_KEY_KEY_ID, issuer_id: $APP_STORE_CONNECT_API_KEY_ISSUER_ID, key_content: $APP_STORE_CONNECT_API_KEY_KEY ) increment_build_number( build_number: app_store_build_number( api_key: api_key, initial_build_number: 0, version: get_version_number(xcodeproj: "your_project.xcodeproj"), live: false ) + 1, ) match( app_identifier: APP_ID, readonly: is_ci, type:"appstore" ) build_app( scheme:"your_project_name", export_method:"app-store", skip_profile_detection:true, configuration: "Release", workspace: "your_project_name.xcworkspace", xcargs: settings_to_override_release, export_options: { provisioningProfiles: { APP_ID => PROVISIONING_PROFILE_APPSTORE }, installerSigningCertificate: "your_installer_signing_certificate_name" } ) deliver( api_key: api_key, submit_for_review: false, force: true, precheck_include_in_app_purchases: false ) end end
Этот шаг также должен включать учетные данные api_key, это четко не задокументировано в официальных документах.
☝️ Если мы установим submit_for_review: true
, новый выпуск будет отправлен на проверку автоматически, поэтому нам не нужно нажимать на него вручную с веб-сайта Apple Store Connect.
Дополнительный совет. Если у вас нет покупок в приложении, установите precheck_include_in_app_purchases: false
, иначе рабочий процесс завершится сбоем в CircleCI, даже если IPA был успешно отправлен в App Store.
Precheck не может проверять покупки в приложении с помощью ключа API App Store Connect · Проблема № 18250 · fastlane/fastlane
Теперь наш Fastfile готов 🎉
🐾 Определите задание Release в config.yml
Как только наша полоса будет завершена, нам нужно создать задание, которое вызывает эту полосу среди других процессов, чтобы наш поток был готов.
Создайте файл .env
В файле config.yml мы создадим задание ios-release.
В этом задании нам понадобится шаг для создания файла .env, содержащего ранее определенные ключи, связанные с App Store Connect, в переменных среды CircleCI:
- run: name: "Create .env file" command: echo -e "APP_STORE_CONNECT_API_KEY_ISSUER_ID=${APP_STORE_CONNECT_API_KEY_ISSUER_ID}\nAPP_STORE_CONNECT_API_KEY_KEY=${APP_STORE_CONNECT_API_KEY_KEY}\nAPP_STORE_CONNECT_API_KEY_KEY_ID=${APP_STORE_CONNECT_API_KEY_KEY_ID}" > .env
Если вы уже создали этот шаг, просто добавьте новые переменные среды.
Звонок на переулок release_ipa
В config.yml мы добавим новый шаг для вызова нашей ранее созданной дорожки release_ipa:
- run: command: rm -rf Pods && pod install && bundle exec fastlane release_ipa --verbose no_output_timeout: 30m working_directory: ios
Скелет задания релиза config.yml будет примерно таким:
ios-release: macos: xcode: '13.3.0' working_directory: ~/your-working-directory # use a --login shell so our "set Ruby version" command gets picked up for later steps shell: /bin/bash --login -o pipefail steps: - checkout - run: name: "Create .env file" command: echo -e "APP_STORE_CONNECT_API_KEY_ISSUER_ID=${APP_STORE_CONNECT_API_KEY_ISSUER_ID}\nAPP_STORE_CONNECT_API_KEY_KEY=${APP_STORE_CONNECT_API_KEY_KEY}\nAPP_STORE_CONNECT_API_KEY_KEY_ID=${APP_STORE_CONNECT_API_KEY_KEY_ID}" > .env (...) - run: command: rm -rf Pods && pod install && bundle exec fastlane release_ipa --verbose no_output_timeout: 30m working_directory: ios - store_artifacts: path: ios/your_project.ipa
🕹 Определите рабочий процесс выпуска в config.yml
Мы собираемся определить два задания в файле config.yml:
- request-ipa-and-prepare-release: чтобы иметь возможность решить, когда мы хотим создать выпуск, это задание даст нам возможность решить, на какой ветке мы хотим инициировать новый выпуск. iOS-релиз.
- ios-release: при нажатии на палец вверх в задании request-ipa-and-prepare-release будет запущен процесс выпуска iOS, поэтому будет выпущен новый выпуск. созданный в App Store Connect, и будет загружен новый сгенерированный IPA.
Скелет рабочих процессов будет примерно таким:
workflows: version: 2 ios: jobs: - request-ipa-and-prepare-release: type: approval filters: <<: *filters-node - ios-release: requires: - request-ipa-and-prepare-release filters: <<: *filters-node
А вот как это будет выглядеть на CircleCI:
🆕 Автоматически загружать примечания к выпуску
Автоматизировать загрузку примечаний к выпуску для каждого нового выпуска iOS очень просто, поэтому нам не нужно заходить в App Store Connect и заполнять его для каждого языка. Ниже приведен уникальный шаг:
- Создайте папку для каждого из языков, поддерживаемых вашим приложением, в следующем месте:
ios/fastlane/metadata/en-US/release_notes.txt ios/fastlane/metadata/es-ES/release_notes.txt ios/fastlane/metadata/fr-FR/release_notes.txt
В файлах release_notes.txt добавьте текст так, как вы бы это сделали: Никаких дополнительных шагов или дополнительных флагов не требуется.
Это автоматически определяется командой доставить, поэтому нет необходимости добавлять дополнительную конфигурацию.
Поздравляем, вы сделали это! Теперь ваш процесс выпуска iOS автоматизирован! 🥳
🥹 При попытке нового процесса выпуска вы заметите, что IPA появляется МГНОВЕННО на портале App Store Connect, когда вы делаете это через CircleCI, в отличие от того, когда мы делали это вручную из Xcode, для появления которого потребовалось около 20 минут. .
🐞 Ошибки, обнаруженные в процессе
CircleCI показывает ошибку, связанную с iTMSTransporter: ошибка An exception has occurred: issuerId is required
[пилот] не может загрузить сборку в TestFlight с помощью ключа API после автоматического обновления iTMSTransporter до версии 3.0.0 с ошибкой «Произошло исключение: требуется issuerId · Проблема № 20741 · fastlane/fastlane»
Это было решено путем добавления следующей переменной env в CircleCI: ITMSTRANSPORTER_FORCE_ITMS_PACKAGE_UPLOAD = true
И обновление fastlane версии до 2.210.1 на Gemfile.lock:
// on the Terminal, go to your project cd ios bundle update // after these steps, commit and push the Gemfile.lock
В следующей статье мы узнаем, как автоматизировать процесс выпуска приложений для Android в Google Play Store и CircleCI 🤖
📚 Документы
Документация и дополнительные руководства
- Официальное руководство Fastlane по развертыванию в Apple Store
- Как создать идеальный конвейер fastline для iOS
- Как использовать fastlane для быстрого развертывания приложения iOS
— Создайте и разверните приложение iOS для Testflight с помощью Github Actions
— Установите переменные среды в CI
— Дорожки
— App Store Connect API
— Аутентификация с помощью сервисов Apple
Примеры
-circleci-demo-ios/config.yml на мастере · CircleCI-Public/circleci-demo-ios
- circleci-demo-ios/Fastfile на master · CircleCI-Public/circleci-demo-ios
— https://webcache.googleusercontent.com/search?q=cache:DFydATxAjUEJ:https://circleci.com/docs/ios-tutorial&cd= 2&hl=en&ct=clnk&gl=es