company_banner

Переход c Cocoapods на Swift Package Manager



    Cocoapods считается наиболее популярным менеджером зависимостей для iOS. Последние годы Apple работает над развитием своего нативного менеджера зависимостей Swift Package Manager (SPM).

    Изначально его использование было возможно только для server-side Swift или приложений для терминала. На таких приложениях обкатывали и дорабатывали SPM, комьюнити знакомилось с его работой, а команда Apple получила бета тестеров.

    С релизом Xcode 11 SPM начал приходить и в мир разработки под iOS. Сейчас это уже полноценный инструмент, который можно использовать, но пока с ограничениями.

    В актуальной версии SPM не поддерживает ресурсы (ждем SE-0271). У нас каждый модуль является атомарной самодостаточной зависимостью, которую можно подключить к проекту, так что ресурсы необходимы (локализации, ассеты).

    А пока мы ждем, можно подготовиться к миграции: понять, насколько это сложно, можно ли это автоматизировать и с какими проблемами можно столкнуться.

    Зачем мигрировать с Cocoapods на SPM?


    • Нативность и интеграция в экосистему. Уже сейчас Xcode предлагает создать или добавить SPM Package.
    • В отличие от Cocoapods, больше не обязательно иметь workspace для работы над проектом с зависимостями.
    • Добавив новую зависимость, не нужно делать pod install и пересобирать весь проект.
    • Удобно использовать локальные зависимости: не меняется структура папок, быстрее пересобирается.
    • SPM не меняет структуру файла проекта, как это делает Cocoapods, не требует зависимости от Ruby и даже может сгенерировать файл проекта сам (пока недоступно для iOS-проектов).
    • Cocoapods не успевает справляться с нововведениями в Xcode и компилятор Swift.
    • Не нужно создавать проект Example для каждого репозитория: Xcode умеет открывать Package.swift файл как проект.
    • Не нужно оптимизировать дерево зависимостей при помощи abstract_target: SPM из коробки умеет не перекомпилировать код для разных таргетов с общими зависимостями.
    • Можно смотреть blame в зависимостях, а не только в основном проекте.
    • Не нужно писать скрипты на Ruby, чтобы починить конфигурацию проекта.

    Как выглядит миграция?


    Если ваш проект имеет достаточно много зависимостей, то процесс миграции не сделать за один день. Количество зависимостей в Podfile не равно общему количеству зависимостей, так как одна зависимость может идти в комплекте с еще десятью. Даже если у вас не много зависимостей, но вы разрабатываете свои зависимости, возможно, даже в приватных репозиториях, быстро не мигрировать. К счастью, SPM отлично уживается с Cocoapods, и процесс миграции можно вести итерационно. Главное — учесть нюансы:

    • Не должно быть пересечений между зависимостями SPM и Cocoapods.
    • Миграция должна быть встроена в процесс развития компонентов. Если компонент развивается, поднятие версии должно выполняться как для Cocoapods, так и для SPM.
    • Сложностей для команды быть не должно, а значит, нужно внедрить установку всех зависимостей через единую cli-команду.
    • Миграция должна быть встроена в CI CD. Проект должен собираться как локально так и на агентах CI, во всех конфигурациях.

    С чего начать?


    Прежде всего собираем полный список ваших зависимостей — он представлен в Podfile.lock. Для этого можно использовать утилиты, например SPMReady.



    Далее группируем их по связям. Например, от SMENetwork у нас зависят почти все компоненты, а значит, мы не сможем мигрировать их на SPM, пока не мигрирует сам SMENetwork.

    Затем выделяем один модуль, от которого зависит больше всего модулей, — SMENetwork.
    И наконец переходим в репозиторий этого модуля, чекаутим его в папку и создаем в руте этой папки модуль.

    git clone ssh://.../smenetwork.git Developer/SMENetwork
    cd Developer/SMENetwork
    swift package init
    Creating library package: SMENetwork
    Creating Package.swift
    Creating Sources/
    Creating Sources/SMENetwork/SMENetwork.swift
    Creating Tests/
    Creating Tests/LinuxMain.swift
    Creating Tests/SMENetworkTests/
    Creating Tests/SMENetworkTests/SMENetworkTests.swift
    Creating Tests/SMENetworkTests/XCTestManifests.swift
    

    В результате мы получаем основной файл Package.swift и папки Sources и Tests. Если они у вас уже были, их не перетрет. Файлы SMENetwork.swift, SMENetworkTests.swift, XCTestManifests.swift, LinuxMain.swift созданы для примера работы Package, их можно удалить.

    Файл Package.swift выглядит следующим образом:



    Теперь посмотрим на файл SMENetwork.podspec:



    Как видно, Sources и Tests лежат в других папках. Перенесем файлы и проверим работоспособность Cocoapods Example проекта.



    Добавляем в Package.swift платформу разработки и переносим зависимости из podspec файла сюда. Убеждаемся, что они поддерживают SPM: для этого достаточно проверить, что в Гитхабе есть файл Package.swift. Если его нет и даже нет PR с ним, сделаем PR и поможем Open-Source community.





    Для SPM не нужно создавать Example проект: достаточно открыть Package.swift в Xcode и он сам скачает и подключит зависимости, создаст таргеты согласно нашей спецификации. Нам остается только запустить.



    В нашем случае почти все заработало из коробки, за исключением одного места, где забыли import Foundation: iOS-разработчики привыкли, что UIKit и Foundation необязательны, ведь работает и без них. Пора отучаться от этой привычки.



    Package компилируется, тесты компилируются, но не проходят.



    И тут мы упираемся в ограничение отсутствия ресурсов в Package, тесты основаны на моках, которые лежат в json ждем SE-0271

    Итог


    Переехать с Cocoapods на SPM несложно. Шаги понятны, но flow монотонен и требует автоматизации.

    Без особых усилий исходя из .podspec файла можно создать Package и закоммитить его в репозиторий. А самое главное — можно переехать одним проектом, а другой останется на Cocoapods. Если захочет, конечно.
    Tinkoff.ru
    IT’s Tinkoff.ru — просто о сложном

    Комментарии 6

      0
      А как генерировать Acknowledgements.plist в случае со Swift Package Manager?
        0
        На сколько я понимаю, т.к. SPM децентрализованный менеджер зависимостей, вся информация о лицензии и совместимости должна быть в Readme.md в корне репозитория, который добавляется к проекту. Думаю, со временем, добавят в cпецификацию
          0
          Лицензии то и так хранятся в корне проектов, но нужен способ собрать их в единый список по всем зависимостям подобно тому, как это позволяет сделать CocoaPods. Не вручную же собирать лицензии в файл. Тем более, что текст лицензий может обновляться. Без этой фичи использовать SPM для подключения сторонних проектов в качестве зависимостей крайне проблематично.
            0
            Согласен, процесс подключения внешних зависимостей усложняется, проверять прийдется вручную при обновлении стека зависимостей. В нашем случае большенство зависимостей внутренние, либо MIT популярные библиотеки
              0
              Ну вот MIT в том числе как раз требует приведения текста лицензии в самом приложении или в связанной документации. И Apache License 2.0 тоже, под которой эпловские проекты открытых библиотек выходят.

              В CocoaPods это легко делается: github.com/CocoaPods/CocoaPods/wiki/Acknowledgements

              Удивительно, что такая очевидная и крайне нужная фича не была реализована до встраивания поддержки SPM в Xcode.

                0
                Ну, SPM нормально заработает только в Swift 5.3, и до лицензий позже дойдут

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое