CocoaPods
CocoaPods - это менеджер зависимостей для iOS-приложения.
Зависимости и конфигурации для ваших проектов задаются в одном текстовом файле, называемом подфайлом. CocoaPods разрешит зависимости между библиотеки, извлечет полученный исходный код, а затем свяжет его вместе в рабочей области Xcode для создания вашего проекта.
Что происходит на практике
В нашим Xcode проектах имеется зависимость на CocoaPod MultiPlatformLibrary
.
Данный CocoaPod имеет особенную реализацию - он не содержит исходного кода, а вместо фазы компиляции Source файлов он имеет фазу запуска shell команды. Именно в этой фазе происходит запуск Gradle для компиляции MultiPlatformLibrary.framework
из Kotlin кода. Когда скрипт завершится, Xcode продолжит сборку iOS проекта уже с использованием готового скомпилированного фреймворка от Kotlin библиотеки.
Рассмотрим процесс детальнее. Для начала посмотрим, что происходит после установки зависимостей через CocoaPods: помимо файла проекта - ios-app.xcodeproj
мы получаем еще один файл - ios-app.xcworkspace
.
Разберемся в разнице между ними:
ios-app.xcodeproj
- файл нашего ios проекта, содержит все настройки проекта, список файлов проекта, фазы сборки и прочее. В нем также указано, что наш iOS проект теперь зависит отPods_ios_app.framework
- фреймворка подключающего все CocoaPods зависимости. При попытке скомпилировать проект черезios-app.xcodeproj
мы получим ошибку о том что фрейворки, от которых зависит проект, не найдены.ios-app.xcworkspace
- файл с объединением нескольких Xcode проектов вместе. Если открыть его в Xcode, то в левой панели мы увидим не толькоios-app
проект, но иPods
, в котором находятся все необходимые для проекта зависимости. При работе черезxcworkspace
мы можем успешно скомпилировать проект, так как зависимостьios-app
проекта будет найдена вPods
проекте. Необходимые зависимости дляios-app
будут автоматически скомплированы также вPods
.
Теперь, понимая как ios-app
связан с зависимостями, установленными CocoaPods, посмотрим детальнее на MultiPlatformLibrary
CocoaPod. Находится данный Pod в Pods/Development Pods/MultiPlatformLibrary
.
Только этот CocoaPod находится в Development Pods
, так как он единственный в Podfile
, который подключен по локальному пути (:path =>
).
info
Все CocoaPod'ы, подключенные по локальному пути, будут находиться в Development Pods
разделе, вместо Pods
.
Podfile
Разберемся что здесь к чему:
# указываем откуда будем скачивать зависимости - с официального репозитория cocoapods
source 'https://cdn.cocoapods.org/'
# скрывает предупреждения от библиотек CocoaPods.
inhibit_all_warnings!
# использование динамических фреймворков вместо статических библиотек для модулей
use_frameworks!
# указывает платформу и ее версию, нужно для проверки всех зависимостей на поддержку этой версии этой платформы
platform :ios, '12.0'
# маппинг конфигураций
project 'ios-app',
'dev-debug' => :debug, 'dev-release' => :release,
'stage-debug' => :debug, 'stage-release' => :release,
'prod-debug' => :debug, 'prod-release' => :release
# обходной путь для https://github.com/CocoaPods/CocoaPods/issues/8073
# нужно для корректного отключения невалидного кеша MultiPlatformLibrary.framework
install! 'cocoapods', :disable_input_output_paths => true
# объявление зависимостей для конкретного таргета
target 'ios-app' do
# зависимость нашей библиотеки, о ней дальше
pod 'MultiPlatformLibrary', :path => '../mpp-library'
# moko поды
pod 'MultiPlatformLibraryUnits/Core',
:git => 'https://github.com/icerockdev/moko-units.git', :tag => 'release/0.6.1'
pod 'MCRCDynamicProxy',
:git => 'https://github.com/icerockdev/moko-crash-reporting.git', :tag => 'release/0.2.0'
pod 'MCRCStaticReporter',
:git => 'https://github.com/icerockdev/moko-crash-reporting.git', :tag => 'release/0.2.0'
# остальные поды, которые могут понадобиться во время разработки
# pod 'Firebase', '~> 6.33.0'
# pod 'R.swift', '~> 5.3.1' # Code generation for resources https://github.com/mac-cain13/R.swift
# pod 'ProgressHUD', '~> 2.70' # Loading animation https://github.com/relatedcode/ProgressHUD
# pod 'Toast-Swift', '~> 5.0.1' # Showing toasts https://github.com/scalessec/Toast-Swift
# pod 'XLPagerTabStrip', '~> 9.0' # Tabs controller like an Android PagerTabStrip
# pod 'AlamofireImage', '~> 3.6.0' # Image loader with cache https://github.com/Alamofire/AlamofireImage
# pod 'Down', '~> 0.10.0' # Markdown rendering https://github.com/johnxnguyen/Down
# pod 'RxKeyboard', '~> 1.0.0' # Reactive way of observing keyboard frame changes https://github.com/RxSwiftCommunity/RxKeyboard
# ...
end
important
Всегда указывайте версию используемой зависимости, чем точнее тем лучше. Иначе со временем может прийти такой апдейт зависимости, который не совместим с вашим кодом.
Что такое маппинг конфигураций?
important
Эмпирическое правило состоит в том, что поды и наш таргет должны иметь одинаковые настройки макросов препроцессора.
Всякий раз, когда вы создаете пользовательскую конфигурацию сборки, Xcode спрашивает, хотите ли вы дублировать Debug
или Release
конфигурацию.
В Podfile
есть способ указать какая конфигурация сборки была скопирована с какой, это второй аргумент "таргетного" параметра project <path> <[String => symbol]>
.
По умолчанию Xcode предосталяет 2 типа конфигруации сборки:
Debug
;Release
;
В нашем же проекте их 6, и, как мы видим, благодаря верно указанным ключам для каждой конфигурации, в Build Settings
у нас различные макросы для препрцессора на каждый тип конфигурации:
Podspec
Из чего устроена данная зависимость MultiPlatformLibrary
, подключеная по локальному пути (:path =>
):
Во-первых, в директории Frameworks
отражается сам скомпилированный фреймворк - MultiPlatformLibrary.framework
.
Во-вторых - MultiPlatformLibrary.podspec
, который как раз и ищет CocoaPods при подключении через :path =>
по пути mpp-library/MultiPlatformLibrary.podspec
.
Podspec
файл является описанием зависимости для CocoaPods. В нем мы определяем имя, версию и прочую метаинформацию о нашем пакете, исходные файлы и прочие настройки таргета, которые будет сгенерирован в проекте Pods
при pod install
. В нашем podspec
мы определили несколько важных моментов:
spec.vendored_frameworks
- путь до заранее скомпилированного framework'а, который и будет предоставляться как зависимостьios-app
проекту. Именно по этому пути Gradle складывает итоговый фреймворк при запуске любой изsyncMultiPlatformLibrary**
задач;spec.pod_target_xcconfig
- настройки конфигурации, которые определяют переменные окружения, доступные нам во время выполнения сборки данного таргета. Мы определили имя библиотеки, без каких либо условий, а также указали переменнуюGRADLE_TASK
, которая имеет разные значения при разных условиях. Например:GRADLE_TASK
будет равнаsyncMultiPlatformLibraryDebugFrameworkIosX64
, когда переменнаяKOTLIN_FRAMEWORK_BUILD_TYPE
будет равнаdebug
,CURENT_SDK
будет равнаiphonesimulator
, аNATIVE_ARCH
будет равнаx86_64
;spec.script_phases
- определяем специальную фазу сборки с запуском shell скрипта, в котором мы запускаем Gradle задачу, сохраненную в переменной окруженияGRADLE_TASK
. Правильный подбор варианта компиляции мы получаем основываясь на схеме ios приложения, которую мы собираем, и на условиях, обозначенных вxcconfig
. Именно этот скрипт позволяет делать сборку общего модуля автоматически, не требуя от разработчика дополнительных действий перед комплияцией iOS проекта.
При выполнении pod install
данный podspec файл считывается и на основе этой информации создается Target в проекте Pods
:
Видно, что таргет MultiPlatformLibrary
отличается от всех остальных иконкой - это потому, что он не содержит исходного кода, а вместо этого содержит кастомный скрипт.
По настройкам Xcode также видно, что ios-app
не имеет прямой зависимости от MultiPlatformLibrary
. Зависимость есть от Pods-ios-app
. Это оптимизация количества изменений в файле основного проекта, сделанная CocoaPods. Все легко объясняется когда посмотрим на сам таргет Pods-ios-app
.
Данный таргет содержит в зависимостях все CocoaPods, а значит когда ios-app
запрашивает сборку Pods-ios-app
, тот затребует сборку всех этих зависимостей и в результате мы получим сборку всего что нам нужно.
После данного разбора у вас должно сформироваться представление о том как происходит компиляция iOS приложения использующего Kotlin библиотеку с интеграцией через CocoaPods.