Создание библиотеки для iOS

Разработчики часто сталкиваются с типовыми задачами, которые появляются в новых проектах. Постепенно накапливается база вспомогательного кода, которая собирается в библиотеки и переносится из проекта в проект. И чем больше проектов, тем тяжелее становится поддерживать такие библиотеки.
image

Скорее всего у вас есть излюбленный набор категорий над NSFoundation/UIKit для удобства или что-то для работы с сетью или с пуш уведомлениями. Логично было бы оформить этот код в библиотеку, хранить в одном месте и подключать с помощью пакетного менеджера, например cocoapods. Cocoapods существенно облегчает интеграцию зависимостей в проект. Он все делает за вас, создает нужные таргеты и интегрирует их проект. Такая легкость и простота приводит к тому, что часто встречаются поды, которые состоят только из исходников и примера интеграции. Такой подход рекомендуется официально. И, фактически, этого достаточно для интеграции через cocoapods, но недостаточно для разработки и поддержки. Для этого лучше всего подойдет xcode проект, с помощью которого можно собирать библиотеку.

Мы назовем нашу тестовую библиотеку Utilities и создадим для нее Xcode проект. Преимущества такого подхода очевидны:


  • можно настроить необходимые параметры сборки (-Wall/-Weverything, iOS7+/iOS8+ итд) и работать над ошибками во время отладки (а не во время интеграции)
  • можно добавить юнит тесты
  • кроме интеграции через cocoapods, есть возможность интеграции через Carthage, вручную или гит сабмодулями.

При создании проекта необходимо выбрать что мы будем собирать: библиотеку (static library) или фреймворк (dynamic framework). Основное их отличие в том, что фреймворк не совместим с iOS7, а библиотека не поддерживается свифтом.

В нашем случае поддержка iOS7 не нужна, поэтому подойдет фреймворк:
image

После создания проекта необходимо изменить структуру файлов в проекте так, чтобы библиотека была совместима с пакетными менеджерами. Самый часто используемый пакетный менеджер это, конечно же, Cocoapods. Остальные используются меньше, но и поддерживать их проще, так как нет необходимости каждый раз после апдейта загружать в хранилище обновленный podspec.

Для поддержки cocoapods необходимо:


  1. добавить файл podspec
  2. добавить файл LICENSE

В этом вам может помочь команда

pod spec create

Кроме того, если вы не хотите делать библиотеку публичной, нужно создать приватное хранилище пакетов. И добавить в него файл podspec:

pod repo add myrepostorage https://github.com/user/podspecs
pod repo push myrepostorage Utilities.podspec

Пример файла podspec:

Pod::Spec.new do |s|
  s.name         = "Utilities"
  s.version      = "0.0.1"
  s.summary      = "My test library"
  s.homepage     = "https://github.com/user/utilities"
  s.authors      = "author name"
  s.license      = "MIT"
  s.platform     = :ios, "8.0"
  s.source       = { :git => "https://github.com/user/utilities.git", :tag => "#{s.version}" }
  s.source_files = "Sources/**/*"
end

Для поддержки Swift PM необходимо:


  1. положить исходники в папку Sources
  2. добавить файл Package.swift

Пример Package.swift:

import PackageDescription

let package = Package(
    name: "Utilities"
)

Для поддержки carthage необходимо чтобы:


  1. файл проекта xcodeproj находился в корневой папке
  2. схема в проекте была отмечена как shared
    image

Кроме того не помешает:


  1. добавить описание в README.md для гитхаба
  2. положить юнит тесты в папку Tests
  3. положить вспомогательные файлы в папку Supporting Files

В результате должна получиться следующая структура:
image

В папке Supporting Files лежит файл Defaults.xcconfig, который применяет настройки компиляции к проекту. Его удобно положить во все подобные библиотеки, чтобы не настраивать все руками. У нас есть желание сделать строгие настройки, чтобы код был лучше, например такие:

CLANG_WARN_ENUM_CONVERSION = YES
CLANG_WARN_INT_CONVERSION = YES
CLANG_WARN_CONSTANT_CONVERSION = YES
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_ASSIGN_ENUM = YES
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
GCC_WARN_64_TO_32_BIT_CONVERSION = YES
GCC_WARN_ABOUT_MISSING_NEWLINE = YES
GCC_WARN_SHADOW = YES
GCC_WARN_SIGN_COMPARE = YES
GCC_TREAT_WARNINGS_AS_ERRORS = YES
WARNING_CFLAGS = -Weverything -Wno-objc-missing-property-synthesis -Wno-gnu -Wno-float-equal -Wno-nullable-to-nonnull-conversion -Wno-auto-import -Wno-direct-ivar-access

Если библиотека имеет зависимость, например от AFNetworking, то интегрировать эту зависимость можно как обычно, привычными методами. Например, с помощью cocoapods или carthage ее можно подключить к нашей библиотеке. Ещё нужно не забыть указать эту зависимость в соответствующих файлах конфигурации для пакетных менеджеров. Для cocoapods это Podfile, а для carhage это Cartfile.

В результате получаем библиотеку, которую легко поддерживать и интегрировать с помощью любого пакетного менеджера.

© Habrahabr.ru