Как определить модули для вашего приложения с помощью Swift Package Manager
Еще в 2018 году во время WWDC Apple анонсировала Swift Package Manager (SPM или SwiftPM). Цель SPM - позволить разработчикам определять модули, которые можно повторно использовать в различных приложениях и платформах. Пакет может быть определен для работы, например, как с iOS, так и с macOS, поэтому его функции могут совместно использоваться инструментами и приложениями на этих платформах.
Вначале диспетчер пакетов был весьма ограничен: например, он не поддерживал ресурсы, относящиеся к конкретным модулям. В последующие годы SPM значительно улучшился. Теперь он позволяет разработчикам определять исполняемые файлы, отличные от пакетов и библиотек. Он поддерживает ресурсы, так что мы можем, например, добавлять изображения непосредственно в модуль пользовательского интерфейса и повторно использовать их. Совсем недавно он заменил также файлы Xcodeproj: теперь Xcode может создавать проект на лету, начиная с определения Package.swift
!
У него все еще есть некоторые ограничения: например, он не обрабатывает приложения iOS автоматически. Однако есть способ заставить его работать, и сегодня я хочу вместе с вами изучить, как создать модульное приложение iOS с помощью SPM.
Начать
Первым шагом к созданию модульного приложения с SPM является создание папки для проекта. Откройте терминал и выполните следующие команды:
mkdir SPMApp cd SPMApp mkdir SPMAppKit cd SPMAppKit swift package init --name SPMAppKit
Эти команды создают папку с именем SPMApp
и другую папку с именем SPMAppKit
и перемещают нас в нее. Нам нужно это вложение, чтобы поддерживать порядок в нашем проекте. Позже в этой статье мы собираемся создать папку для приложения iOS, потому что SPM не позволяет создавать приложение iOS напрямую. Весь код приложения останется в SPMAppKit
пакете; SPMApp
будет работать как контейнер для пакета. Наконец, последней командой создается пакет с именем SPMAppKit
.
Результат должен выглядеть так:
SPM создает файл Package.swift
, который является файлом определения нашего проекта. Затем он создает стандартный README.md
, содержащий только заголовок, описание по умолчанию и предопределенный .gitignore
, чтобы мы могли немедленно добавить проект в репозиторий Git.
Что еще более интересно, он создает структуру папок по умолчанию для нашего кода. Он создает основной модуль с именем SPMAppKit
, который содержит весь его исходный код в папке Sources
, и тестовый модуль с именем SPMAppKitTests
, который содержит шаблон для модульного теста в папке Tests
.
Если мы затем введем следующее, Xcode должен открыть наш проект:
open Package.swift
В навигаторе проекта вы должны увидеть структуру, которую я описал выше. Это выглядит так:
Осмотрите Package.swift
Наша цель - создать приложение для iOS, но SPM на данный момент не поддерживает это. Вот почему мы назвали наш пакет SPMAppKit
: он генерирует библиотеку со всем, что нужно приложению, но это не может быть приложение.
Чтобы создать все необходимые нам модули с помощью SPM, нам нужно изменить наш Package.swift
файл. Исходный файл выглядит так:
Файловая структура довольно проста. Он определяет имя пакета и то, что создается: библиотека с именем SPMAppKit
, которая зависит от цели с тем же именем. Затем идет список внешних зависимостей, на данный момент пустой список. Наконец, он определяет текущее целевое дерево нашего проекта (модуль SPMAppKit
и соответствующий тестовый модуль).
Каждая цель может зависеть от других целей или от внешних зависимостей. Например, SPMAppTests
необходим доступ к модулю SMPApp
, чтобы запускать на нем тесты, поэтому это зависит от этого модуля.
platforms
property не определено. SPM предполагает, что нам нужна многоплатформенная библиотека без ограничений по версиям. На данный момент это нормально: мы всегда можем настроить файл Package.swift
позже, если нам понадобится их добавить.
Теперь мы можем выбрать iPhone из списка целей, как на картинке ниже, и нажать ⌘ + b
, чтобы построить цель. Нажав ⌘ + u
, мы можем построить и запустить тесты на симуляторе.
Свяжите пакет с приложением
Этот шаг может быть отложен до конца процесса разработки. Однако все мы хотим быть уверены, что работаем в правильном направлении.
Это идеальный момент, чтобы увидеть, как мы можем создать приложение для iOS и получить доступ к только что созданному пакету.
Создайте приложение Xcode
В качестве первого шага создадим новое приложение для iOS. Из Xcode давайте:
- Нажмите
⌘ + ⇧ + N
, чтобы создать новый проект. - Выберите
iOS
на вкладках вверху иApp
из предопределенных шаблонов. - Назовите наше приложение
SPMApp
и используйтеSwiftUI
в качестве интерфейса. - Сохраните наше приложение в папке
SPMApp
, которую мы создали ранее.
Xcode создает для нас проект, готовый к запуску. Структура примерно такая.
Создайте репозиторий Git для пакета
Пришло время связать пакет с приложением. SPM создан для работы с git
, чтобы иметь возможность получать правильную версию пакета. SPM также поддерживает локальные репозитории: нет необходимости размещать незаконченный пакет в сети только для того, чтобы протестировать его.
Давайте снова откроем Терминал и перейдем в папку SPMAppKit
. Там мы можем просто запустить следующие команды:
git init git add . git commit -m "initial commit"
Эти команды создают пустой репозиторий Git, отслеживают все файлы в папке (помните, что SPM также создали для нас .gitignore
по умолчанию!) И фиксируют работу в репозитории.
Импортируйте пакет в приложение
Теперь мы можем вернуться к нашему приложению iOS. Мы можем использовать интеграцию IDE с SPM, чтобы добавить пакет в наш проект. Для этого мы можем щелкнуть меню File ›Swift Packages› Add Package Dependency ... и следовать подсказкам.
Эта опция вызывает диалоговое окно с запросом URL-адреса. Уловка состоит в том, чтобы использовать полный URL-адрес нашего пакета. Мы можем получить это, запустив в Терминале команду pwd
и добавив к ней схему file://
.
Итак, в моем случае, когда я запускаю pwd
, я получаю:
/Users/riccardocipolleschi/Documents/Personal2/SPMApp/SPMAppKit
Тогда правильный URL для локального пакета будет file:///Users/riccardocipolleschi/Documents/Personal2/SPMApp/SPMAppKit
После того, как мы вставим этот URL-адрес в текстовое поле repository
, кнопка «Далее» станет активной. Давайте коснемся его, чтобы отобразить этот экран.
Мы еще не выпустили наш пакет, поэтому мы не можем следовать первому правилу: пока нет доступных версий. Мы можем выбрать второе правило, указав текущую ветку, над которой мы работаем. В моем случае это все еще main
, поэтому я могу оставить значение по умолчанию в текстовом поле имени ветки.
При нажатии кнопки «Далее» открывается последний экран, на котором нас спрашивают, в какую цель мы хотим добавить продукт пакета. Мы можем оставить значение по умолчанию и нажать «Готово».
Теперь приложение может использовать пакет, над которым мы работаем! Например, если мы откроем файл SPMAppApp.swift
, мы можем ввести import SPMAppKit
, и приложение должно построить безупречно.
Теперь новый проект выглядит так. Раздел «Зависимости пакетов Swift» содержит код всех пакетов, импортированных нашим приложением.
Добавить новый модуль в SPMAppKit
Подведем итоги текущей ситуации. У нас есть:
- Пакет SPM
- Приложение для iOS
Приложение связано с пакетом и может его использовать.
Если мы исследуем код в пакете, он не имеет public
членов: приложение может получить доступ к модулю, но нет сущностей, которые оно может использовать.
Давайте исправим это, добавив AppSetupView.swift
с помощью SwiftUI. AppSetupView
- это представление, которое загружается в приложение как самое первое представление, в то время как приложение загружает все необходимые ему ресурсы.
Учитывая, что это часть пользовательского интерфейса с очень специфической семантикой и ответственностью, мы хотим создать его в отдельном модуле. Для этого мы можем изменить Package.swift
следующим образом:
Здесь есть два важных изменения:
product
теперь экспортирует другую цель,AppSetupView
.- Мы определяем новую цель в строке 28 с именем
AppSetupView
и относительным путем, указывающим на папкуAppSetupView
.
Благодаря свойству path
мы можем поддерживать аккуратную структуру папок на диске и в проекте. Однако теперь SPM жалуется через Xcode.
Мы определили новый модуль в файле определения, но Xcode не может найти соответствующие файлы и папки. Чтобы это исправить, давайте создадим их. Давайте запустим следующие команды из папки SPMAppKit
:
mkdir AppSetupView cd AppSetupView touch AppSetupView.swift
Они создают новую папку, которая находится по тому же пути, который указан в файле Package.swift
. Он перемещает нас в него и создает новый пустой файл с именем AppSetupView.swift
.
Если мы сейчас проверим Xcode, ошибка должна быть устранена, и новая папка должна быть автоматически добавлена в нашу рабочую область.
Примечание. Нам нужно создавать соответствующие папки и первый пустой файл каждый раз, когда мы создаем новый модуль, чтобы удовлетворить SPM, но нам нужно делать это только один раз для каждого модуля. Мы всегда можем добавить новые файлы к существующим модулям стандартным способом, используя ярлык ⌘ + N
и выбрав правильное целевое членство.
Теперь мы можем создать представление SwiftUI. Давайте изменим пустой файл, добавив следующий код:
Этот файл создает новое представление SwiftUI, которое представляет loading...
текст в середине экрана. Представление - это public
, а также его init
, так что мы можем создать его в другом модуле.
Мы не хотим отправлять код предварительного просмотра при выпуске библиотеки; поэтому мы обернули #if DEBUG
условие компиляции вокруг кода предварительного просмотра SwiftUI. Это также уменьшит размер нашей библиотеки после выпуска!
Однако Xcode все еще жалуется. SwiftUI - это функция, которая доступна в некоторых очень специфических версиях macOS и iOS, но мы не указали их в нашем Package.swift
. Давайте исправим эту ошибку, изменив Package.swift
следующим образом:
В строке 3 мы добавили необходимые платформы с некоторыми подходящими версиями.
Теперь мы можем ввести ⌘+b
и увидеть, что проект строится. Мы даже можем использовать предварительный просмотр, чтобы увидеть, как он будет отображаться на экране. Нам не хватает еще одного шага, прежде чем мы сможем использовать это представление в нашем приложении: нам нужно зафиксировать эти изменения в локальном репозитории пакетов. Выполним следующие команды:
git add -A git commit -m "feat: add AppSetupView module"
Используйте AppSetupView
Вернемся к нашему приложению и подключим новое представление. Прежде всего, нам нужно добавить в проект новые изменения, внесенные в пакет SPMAppKit
.
Мы можем сделать это с помощью пункта «Обновить до последних версий пакета» в меню «Файл»> «Пакет Swift».
Эта команда извлекает для нас все изменения во всех пакетах Swift, включенных в наш проект. Фактически новая структура проекта выглядит так:
Вы можете увидеть, как раздел «Зависимости пакетов Swift» теперь содержит модуль AppSetupView
.
Последний шаг - изменить файл SPMAppApp.swift
для использования нового файла AppSetupView
. Давайте изменим код следующим образом:
Как видите, мы импортируем новый модуль AppSetupView
и создаем это представление в WindowGroup
. Теперь давайте нажмем ⌘+r
, чтобы запустить приложение: мы должны увидеть, что представлено новое представление настройки приложения.
Заключение
В сегодняшней статье мы затронули несколько концепций. Мы увидели, как создать пакет SPM, как интегрировать его в приложение и как создавать разные модули в одном пакете.
Настоящее преимущество этого подхода заключается в том, что весь код приложения может быть фактически разработан в контексте SPM и интегрирован в реальное приложение только в конце или когда требуется демонстрация. Время сборки отдельных модулей очень быстрое. Xcode может перестраивать только те модули, которые действительно изменились. Поэтому нам не нужно ждать полной перестройки приложений при каждом изменении модуля.
Помимо этого улучшения, мы можем очень быстро проверить, как выглядит пользовательский интерфейс, используя предварительные просмотры SwiftUI (и мы можем использовать предварительные просмотры даже с UIKit), а логику приложения можно изолировать в определенных модулях, которые можно тестировать изолированно. .