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


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


Xcode проект


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


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

Static Library vs Framework


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


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


Структура файлов


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


Сocoapods


Для поддержки 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 Package Manager


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


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

Пример Package.swift:


import PackageDescription

let package = Package(
    name: "Utilities"
)

Carthage


Для поддержки 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.


Итог


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

Поделиться с друзьями
-->

Комментарии (7)


  1. Makaveli
    13.05.2016 14:24
    +1

    Есть ещё хорошая инструкция на английском как сделать кросс-платформенный фреймворк (tvOS, iOS, OS X, watchOS).


    1. zaazza
      16.05.2016 12:11

      спасибо за ссылку, отличная инструкция


  1. house2008
    13.05.2016 16:54
    -1

    Помню делал статик либу ios 6.0+ с CoreData схемой на все 4 платформы + под Unity3d mac os .bundle версию с интеграцией через cocoapods, вот это был адъ. Также в корне проекта лежал скрипт install.sh который собирал и раскидывал по папкам все либы. Больше всего раздражало, что при изменении версии xcode, он постоянно менял имена папок куда компилирует либы или вообще логика компиляции momd файла менялась.

    .podspec файл также можно создавать через:

    pod spec create MyFramework
    

    получим дэфолтный шаблон с большим количеством дэфолтных опций )


    1. sstepashka
      16.05.2016 11:33

      Тут же описаные различные способы публикации, не только CocoaPods и данная конфигурация может не подойти.


  1. sstepashka
    16.05.2016 11:29

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


    Мне кажется, что это не совсем правда… Вы хотите сказать, что если я буду писать фреймворк на Objective-C и выставлю Mach-O Type как Static Library, то не смогу этим пользоваться, на iOS 7?


    1. zaazza
      16.05.2016 12:20

      Я хочу сказать, что до iOS8 были способы линковать фреймворки, но это было связано с большим количеством проблем и официально этот способ не поддерживался.


      1. sstepashka
        16.05.2016 15:09

        Думаю, что тогда это необходимо явно указать, так как в водит в заблуждение. Создаётся впечатление, что сейчас невозможно поддерживать iOS меньше 8-ой версии, а на самом деле это не так…