Привет, Хабр! В преддверии старта курса "iOS Developer. Professional" подготовили для вас традиционный перевод полезного материала. Также приглашаем желающих на онлайн-встречу с преподавателем курса, на которой можно задать преподавателю интересующие вас вопросы об обучении.
И напоследок, предлагаем посмотреть запись вебинара «Пишем приложение на SwiftUI и Combine».
I - Введение
В этой статье мы рассмотрим решение для мгновенного разрешения мерж-конфликтов в файле .xcodeproj
, что является одной из самых трудоемких проблем, с которыми сегодня сталкиваются команды iOS и macOS разработчиков.
К концу этой статьи у вас будет рабочая среда, обеспечивающая бесконфликтное слияние.
II - Прежде чем мы начнем
1. Знакомство с XcodeGen
yonaskolb/XcodeGen
github.com
XcodeGen — это консольная утилита, написанная на Swift, которая генерирует Xcode-проект на основе вашей структуры папок и спецификации проекта.
Для установки XcodeGen мы будем использовать Brew. Просто запустите в терминале brew install xcodegen (дополнительные параметры установки и инструкции можно найти здесь).
2. Проект
В наше время большинство проектов не так уж и просты. У них есть несколько конфигураций, зависимостей (предоставленных третьими лицами или разработанных как часть проекта), скриптов, которые запускаются как часть процесса сборки, CI и т. д.
В этом руководстве вы узнаете, как шаг за шагом настроить проект, который достаточно прост, чтобы объяснить суть XcodeGen, и в то же время достаточно сложен, чтобы охватить достаточно широкий диапазон вариантов использования.
Как мы видим выше, проект содержит:
Зависимости фреймворков
Carthage-зависимости
Схемы и конфигурации
Сборочные скрипты
III - Настройка
1. Настраиваем проект
Проект (sample project), который мы будем использовать в этом туториале, имеет carthage-зависимости. Просто запустите makeProject.sh
в терминале. Это настроит проект со всеми его зависимостями, и мы сможем начать туториал.
2. Создание файла спецификаций проекта XcodeGen
В корневом каталоге проекта создайте папку с именем XcodeGen (имя папки необязательно должно быть таким) с файлом названным project.yml (это имя файла тоже опционально).
XcodeGen/project.yml
: Первоначальная настройка:
name: GoodToGo
options:
bundleIdPrefix: com.GoodToGo
xcodeVersion: '12.0.1'
deploymentTarget: '12.0'
groupSortPosition: top
generateEmptyDirectories: true
findCarthageFrameworks: true
minimumXcodeGenVersion: '2.18.0'
Во время нашей первоначальной настройки для файла .xcodeproj
мы выбираем имя — GoodToGo
— , префикс пакета — com.GoodToGo
— , версию Xcode, целевую платформу развертывания…
3. Первый запуск XcodeGen
Используя описанную выше конфигурацию, мы можем создать наш новый проект, запустив xcodegen -s ./XcodeGen/project.yml -p ./
в терминале.
Обратите внимание, что ./XcodeGen/project.yml
— это путь к файлу спецификации нашего проекта. Если вы выберете другое имя папки/файла, вам также необходимо будет подправить их здесь.
Зеленое сообщение говорит о том, что проект был создан. Ура, мы успешно создали наш проект!
Теперь давайте откроем его и посмотрим, как он выглядит:
Не то, что мы ожидали… Отсутствуют все наши схемы, все фреймворки, вообще все. Они отсутствуют, потому что мы не определили их в нашем файле project.yml.
4. Добавление конфигураций и основного таргета проекта
XcodeGen/project.yml
: Добавление конфигураций. Просто добавьте это в свой файл project.yml
:
configs:
Debug.Dev: debug
Debug.Prod: debug
Release: release
targets:
GoodToGo:
type: application
platform: iOS
deploymentTarget: 12.0
settings:
base:
MARKETING_VERSION: 1.0
sources:
- path: ../GoodToGo
По сути, мы создаем 3 конфигурации — Debug.Dev, Debug.Prod и Release, и заявляем что основной таргет нашего приложения будет называться GoodToGo, с целевой платформой iOS 12 (минимальная версия), а файлы исходного кода находятся в папке GoodToGo.
Папка должна существовать в системных папках, иначе у вас будет следующая ошибка:
Spec validation error: Target “GoodToGo” has a missing source directory
“/Users/ricardosantos/Desktop/GitHub/RJPS_Articles/7/sourcecode/THE_FOLDER_THAT_DOES_NOT_EXISTS_NAME”
Попробуйте снова с нашей обновленной конфигурацией (предыдущее изображение) и…
… теперь у нас есть (предыдущее изображение) схемы, конфигурации и таргет приложения!
5. Добавление фреймворков
Следующее, что нам нужно сделать, — это добавить зависимости наших фреймворков. Для каждого из них нам нужно выбрать платформу, тип, таргет и другие параметры.
Мы знаем с самого начала, что обычно все фреймворки имеют одни и те же настройки, поэтому мы создадим шаблон и назовем его Framework.
Ниже вы можете увидеть простой шаблон, на который мы будем ссылаться в нашем основном файле project.yml, а затем и там, где это необходимо.
XcodeGen/project.yml
: Создание шаблона:
targetTemplates:
Framework:
type: framework
platform: iOS
deploymentTarget: 11.0
settings:
base:
MARKETING_VERSION: 1.0
В этом шаблоне указано, что все целевые объекты будут иметь следующие условия:
тип framework,
платформа iOS,
версию 1.0,
целевую платформу для развертывания, равную или выше, iOS 11.0.
В нашем образце проекта у нас были следующие зависимости фреймворков (смотрите ниже).
Мы добавим парочку для проверки: AppTheme и AppResources.
Начиная с нашего файла project.yml в разделе таргетов мы добавим 2 новые записи (AppTheme и AppResources). Для этих таргетов мы должны определить исходную папку и имя шаблона, как объяснялось в предыдущем шаге.
AppTheme:
templates:
- Framework
sources:
- path: ../AppTheme
AppResources:
templates:
- Framework
sources:
- path: ../AppResources
XcodeGen/project.yml
: Добавление таргетов с помощью шаблона
Попробуем еще раз с нашей обновленной конфигурацией (предыдущее изображение) и…
… теперь у нас есть основной таргет нашего приложения и 2 зависимости, которые мы только что добавили в наш файл спецификации.
Небольшое резюме: раздел таргетов в нашем project.yml
должен выглядеть так:
targets:
GoodToGo:
type: application
platform: iOS
deploymentTarget: 12.0
settings:
base:
MARKETING_VERSION: 1.0
sources:
- path: ../GoodToGo
AppTheme:
templates:
- Framework
sources:
- path: ../AppTheme
AppResources:
templates:
- Framework
sources:
- path: ../AppResources
Для завершения настройки нам нужно добавить остальные фреймворки, после чего наш файл project.yml
должен выглядеть следующим образом:
name: GoodToGo
## options section ##
options:
bundleIdPrefix: com.GoodToGo
xcodeVersion: '12.0.1'
deploymentTarget: '12.0'
groupSortPosition: top
generateEmptyDirectories: true
findCarthageFrameworks: true
minimumXcodeGenVersion: '2.18.0'
## configs section ##
configs:
Debug.Dev: debug
Debug.Prod: debug
Release: release
## targetTemplates section ##
targetTemplates:
Framework:
type: framework
platform: iOS
deploymentTarget: 11.0
settings:
base:
MARKETING_VERSION: 1.0
## targets section ##
targets:
GoodToGo:
type: application
platform: iOS
deploymentTarget: 11.0
settings:
base:
MARKETING_VERSION: 1.0
sources:
- path: ../GoodToGo
AppTheme:
templates:
- Framework
sources:
- path: ../AppTheme
AppResources:
templates:
- Framework
sources:
- path: ../AppResources
AppConstants:
templates:
- Framework
sources:
- path: ../AppConstants
Core:
templates:
- Framework
sources:
- path: ../Core
Core.GalleryApp:
templates:
- Framework
sources:
- path: ../Core.GalleryApp
Domain:
templates:
- Framework
sources:
- path: ../Domain
Core.GalleryApp:
templates:
- Framework
sources:
- path: ../Core.GalleryApp
Designables:
templates:
- Framework
sources:
- path: ../Designables
DevTools:
templates:
- Framework
sources:
- path: ../DevTools
Extensions:
templates:
- Framework
sources:
- path: ../Extensions
Factory:
templates:
- Framework
sources:
- path: ../Factory
PointFreeFunctions:
templates:
- Framework
sources:
- path: ../PointFreeFunctions
Repositories:
templates:
- Framework
sources:
- path: ../Repositories
Repositories.WebAPI:
templates:
- Framework
sources:
- path: ../Repositories.WebAPI
UIBase:
templates:
- Framework
sources:
- path: ../UIBase
Test.GoodToGo:
type: bundle.unit-test
platform: iOS
sources:
- path: ../Test.GoodToGo
scheme: {}
XcodeGen/project.yml
: Полная конфигурация (пока)
На этом этапе после запуска XcodeGen у нас должен получиться проект со всеми фреймворками!
Настраивая подобные вещи, мы всегда натыкаемся на некоторые неровности на дороге. Одна из них — пропавшая ссылка на файл .plist
. Это можно исправить 2-мя способами: первый заключается в указании в project.yml
пути к файлу .plist
, а второй вариант заключается в переименовании GoodToGo-info.plist в Info.plist.
6. Подтягиваем зависимости фреймворков
На этом этапе у нас есть базовая конфигурация проекта, схемы и наши фреймворки. Пришло время подтянуть наши зависимости и успешно скомпилировать наш проект.
Например, мы заметили, что Domain зависит от RxCocoa и RxSwift, а эти зависимости разрешаются с помощью carthage.
Во-первых, нам нужно найти таргет Domain в нашем файле project.yml
…XcodeGen/project.yml
: Таргет Domain без зависимостей:
Domain:
templates:
- Framework
sources:
- path: ../Domain
… а затем добавить недостающие (carthage) зависимости. Вот так просто!XcodeGen / project.yml
: Таргет Domain с зависимостями:
Domain:
templates:
- Framework
sources:
- path: ../Domain
dependencies:
- carthage: RxSwift
- carthage: RxCocoa
Для добавления зависимостей у нас есть несколько вариантов, но в нашем проекте мы используем всего 3:
Добавить carthage-зависимость,
Добавить зависимость проекта с привязкой (link: true),
Добавить зависимость проекта без привязки (link: false).
XcodeGen/project.yml
: Пример трех вариантов зависимостей (carthage, с привязкой и без):
dependencies:
- carthage: RxSwift
- carthage: RxCocoa
- target: BaseUI
link: false
- target: DevTools
link: true
- target: UICarTrack
link: false
Вы можете узнать больше о добавлении зависимостей здесь.
Пришло время подтянуть все зависимости в нашем проекте, и в целом все готово! «В целом» — это просто способ сказать, что эта задача, вероятно, является наиболее трудоемкой, т.к. она состоит из цикла:
1. Создание
.xcodeproject
и его открытие,
2. Компиляция проекта и определение недостающих зависимостей,
3. Добавление недостающих зависимостей в
project.yml
,
4. Возвращение к шагу 1.
7. Дополнительно: скрипты сборки
В исходном проекте у нас было несколько скриптов сборки (как мы видим на изображении ниже):
Мы можем добиться того же результата, добавив чайлда postCompileScript
.
GoodToGo:
type: application
platform: iOS
deploymentTarget: 12.0
settings:
base:
MARKETING_VERSION: 1.0
sources:
- path: ../GoodToGo
dependencies:
...
postCompileScripts:
- script: |
if which swiftlint >/dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
name: Run SwiftLint
8. Дополнительно: папка Documents
Мы также можем добавить папку Documents. Файлы внутри этой папки не будут добавлены ни в какой таргет и, следовательно, не будут обрабатываться как часть сборки. Просто добавьте путь к папке с документами в раздел fileGroups (подробнее о fileGroups здесь).
fileGroups:
- ../Documents
IV - Резюме
Мы создали базовый файл
project.yml
и использовали XcodeGen, чтобы он сгенерировал наш проект (подробнее здесь)
Мы добавили некоторые конфигурации проекта (подробнее здесь)
Мы добавили все необходимые нам таргеты
Мы подтянули зависимости наших таргетов (подробнее здесь)
Мы добавили папку с документами (подробнее здесь)
Мы добавили скрипты сборки
1. Проблемы, с которыми вы можете столкнуться при настройке проекта в первый раз: Потерянные файлы
Иногда такое может случится с каждым из нас. При удалении некоторых старых/устаревших файлов из проекта мы выбираем опцию Remove Reference вместо перемещения файла в корзину. Эти файлы появятся снова, когда мы будем использовать XcodeGen (помните, что все файлы внутри папки будут добавлены в таргет). Если вы действительно хотите сохранить эти файлы, поместите их в папку Documents.
2. Проблемы, с которыми вы можете столкнуться при настройке проекта в первый раз: Разные файлы внутри папок
Иногда внутри папок наших таргетов лежат разные файлы. Опять же, помните, что все файлы внутри папки таргета будут добавлены в таргет и, следовательно, скомпилированы. Вы можете избежать этого, поместив эти файлы в папку Documents.
V - Ссылки
XcodeGen можно найти здесь.
Проект перед преобразованием можно найти здесь.
Код финального проекта можно найти здесь.
Финальный project.yml можно найти здесь.
Больше примеров подобных проектов можно найти здесь.
Узнать подробнее о курсе "iOS Developer. Professional".
Смотреть запись вебинара «Пишем приложение на SwiftUI и Combine».