[iOS] Создание фреймворка Framework с использованием Cocoapods

—

от автора

Вступление

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

Тестировалось на xcode 12.4, swift 5

Как создать статическую библиотеку Static Library с Cocoapods я писал здесь

1. Билдим фреймворк

Что ж, перейдем сразу к делу, открываем xcode, создаем новый проект, выбираем Framework, жмем далее, назовем проект FrameworkExample, тесты включать/не включать — на ваше усмотрение.

Я включил юнит-тесты, в итоге получили пустой проект-фреймворк:

Теперь мы можем создавать .swift-файлы и добавлять их в наш пока еще пустой фреймворк.

Не забываем указывать модификаторы доступа public и open для классов свойств и функций!

Шрифты, локализацию Localizable.strings, картинки Assets не вносим в библиотеку, их добавим в клиентский проект отдельно!

Если же у нас имеются файлы(например мы хотим из другого проекта перенести в фреймворк), которые нужно включить в фреймворк, то просто переносим(drag and drop) их в FrameworkExample:

Щелкнув на таргет FrameworkExamples -> General не забудьте настроить с какой версии доступен фреймворк и для каких устройств:

После этого билдим наш фреймворк Ctrl+B (два раза — для устройства и симулятора), и, если у вас нет cocoapods, то все должно сбилдится успешно Build Succeeded — переходим к окончанию пункта 1.

Если же есть подсы, то получим ошибку что они не найдены:

Итак, создаем Podfile в папке проекта, вставляем нужные подсы, не забываем указывать use_frameworks! :

platform :ios, '13.0'  target 'FrameworkExample' do   use_frameworks! pod 'Moya'  pod 'Alamofire'   pod 'Kingfisher'   pod 'EasyPeasy'   pod 'KeychainAccess'  pod 'SwiftPhoneNumberFormatter' end

Устанавливаем поды, открываем workspace, билдим Ctrl+B — для симулятора и устройства — должны получить Build Succeeded:

Находим папку Products, щелкаем правой кнопкой по framework-файлу, затем Show In Finder:

Попадаем либо в папку Debug-iphoneos, либо Debug-iphonesimulator в зависимости на какой product нажали, видим папку нашего фреймворка FrameworkExample.framework, а также подгруженные подсы.

Если перейти на уровень выше в папку Products, то увидим такую же папку и для устройства:

Таким образом, на этом этапе мы сбилдили фреймворк, в котором будут все файлы, помещенные в проект, сам фреймворк состоит из следующих файлов:

2. Компилируем Universal Framework

Под Universal Framework имеется в виду фреймворк, который подходит и под устройство и под симулятор. То есть, мы объединим фреймворки из папок Debug-iphoneos и Debug-iphonesimulator.

Для начала добавим новый target -> Aggregator:

Назовем его UniversalFramework, должно получиться так:

Далее добавим Run Script Phase — код, который будет выполняться при билде UniversalFramework’a и создавать нам объединенный фреймворк:

Вставляем следующий скрипт:

echo "project" # 1) Открываем "${PROJECT_DIR}" if [ "true" == ${ALREADYINVOKED:-false} ] then echo "RECURSION: Detected, stopping" else export ALREADYINVOKED="true"  UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-iosuniversal  # 2) Переходим (либо создаем) папку с выходными файлами mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"  # 3) Билдим для устройства и симулятора echo "iphone" xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" build  echo "iphonesim" xcodebuild -target "${TARGET_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" build  # 4) Копируем из папки Debug-iphoneos в папку universal echo "universal" cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"  # 5) Копируем swift modules echo "iphone simulator path" SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule" fi  # 6) С помощью lipo создаем universal framework echo "lipo create" lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"  echo "end" fi  

Билдим UniversalFramework Ctrl+B,

Теперь выбрав правой кнопкой FrameworkExample.framework и нажав Show In Finder, переходим в папку с фреймворком, и, поднявшись на уровень выше в папку Products, видим созданную папку с нашим универсальным фреймворком:

В этой папке находятся все файлы нашего UniversalFramework. Переходим к следующему этапу!

3. Внедряем фреймворк в ClientApp

Под «ClientApp» имеется в виду любой проект

Cоздаем новый проект xcode -> new -> file -> project -> App

Назовем его ClientAppWithFramework:

Перенесем папку Debug-iosuniversal, т.е. наш универсальный фреймворк в папку с нашим проектом, затем подключим его в Build Phases -> Link Binary With Libraries:

Далее скачиваем pods в наш клиентский проект — Podfile можно взять из FrameworkExample:

platform :ios, '13.0'  target 'ClientAppWithFramework' do   use_frameworks! pod 'Moya'  pod 'Alamofire'   pod 'Kingfisher'   pod 'EasyPeasy'   pod 'KeychainAccess'  pod 'SwiftPhoneNumberFormatter' end

Установив pods, открываем workspace. Импортируем FrameworkExample во ViewController.swift:

Отлично, переходим к тестировке и к возможным ошибкам!

4. Тестируем и правим ошибки

Среди моих файлов фреймворка был файл для тестирования, который содержит публичную функцию, которая печатает нам The Framework works!:

public class TestViewController: UIViewController {      public override func viewDidLoad() {         super.viewDidLoad()      }          public func printLog() {         print("The Framework works!")     }  }

Попробуем вызвать эту функцию из ClientApp, добавляем две строчки:

import FrameworkExample  class ViewController: UIViewController {          override func viewDidLoad() {         super.viewDidLoad()                  let vc = TestViewController()         vc.printLog()              }   }

Выше я писал, что шрифты и картинки мы подгрузим отдельно, так вот, если у вас имеются шрифты, картинки, локализация, то самое время перенести их в ClientApp

Запускаем приложение, если у вас падает с ошибкой:

То необходимо на вкладке General сменить Do Not Embed на Embed & Sign:

Пытаемся запустить вновь, и снова возможна ошибка:

Здесь решение на вкладке Build Phases -> Validate Workspace сменить с No на Yes, сбилдить проект, ошибка должна стать Warning’oм (Магия!), затем измените Validate Workspace снова на No — ошибка и ворнинг должны исчезнуть:

Запускаем приложение, убеждаемся, что все работает корректно:

Отлично, фреймворк внедрен в другой проект и им можно пользоваться!


ссылка на оригинал статьи https://habr.com/ru/articles/586756/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *