Подтвердить что ты не робот

Публикация предварительно скомпилированного Cocoapod

В настоящее время мы создаем SDK для клиента, использующего Cocoapods.

Основная проблема заключается в том, что наш босс хотел бы, чтобы SDK был черным ящиком. Он хочет, чтобы мы предварительно скомпилировали код, чтобы защитить наш источник.

Есть ли что-то, что мы можем сделать в Podspec, чтобы защитить наш код?

4b9b3361

Ответ 1

Мне удалось использовать этот Podspec в качестве примера:

Pod::Spec.new do |s|
  s.name         = "EstimoteSDK"
  s.version      = "1.3.0"
  s.summary      = "iOS library for Estimote iBeacon devices"
  s.homepage     = "http://estimote.com"
  s.author       = { "Estimote, Inc" => "[email protected]" }
  s.platform     = :ios 
  s.source       = { :git => "https://github.com/Estimote/iOS-SDK.git", :tag => "  {s.version}" }
  s.source_files =  'EstimoteSDK/Headers/*.h'
  s.preserve_paths = 'EstimoteSDK/libEstimoteSDK.a'
  s.vendored_libraries = 'EstimoteSDK/libEstimoteSDK.a'
  s.ios.deployment_target = '7.0'
  s.frameworks = 'UIKit', 'Foundation', 'SystemConfiguration', 'MobileCoreServices', 'CoreLocation'
  s.requires_arc = true
  s.xcconfig  =  { 'LIBRARY_SEARCH_PATHS' => '"$(PODS_ROOT)/EstimoteSDK"',
               'HEADER_SEARCH_PATHS' => '"${PODS_ROOT}/Headers/EstimoteSDK"' }
  s.license      = {
    :type => 'Copyright',
    :text => <<-LICENSE
      Copyright 2013 Estimote, Inc. All rights reserved.
      LICENSE
  }
end

Ответ 2

Вы можете сделать именно это, создав Static Framework и включив его в свойство spec.vendored_frameworks на свой podspec.

http://guides.cocoapods.org/syntax/podspec.html#vendored_frameworks

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

https://github.com/jverkoey/iOS-Framework#walkthrough

Как создать статическую структуру для iOS

Есть несколько ограничений, которые мы хотим удовлетворить при построении .framework:

  • Быстрая итеративная сборка при разработке фреймворка. У нас может быть простое приложение, которое имеет .framework как зависимость, и мы хотим быстро переходить к разработке .framework.
  • Редкие рассылки сборки .framework.
  • Распределение ресурсов должно быть интуитивным и не раздувать приложение.
  • Настройка сторонних разработчиков с использованием .framework должна быть легкой.

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

Обзор

Просмотрите пример проекта, который показывает результат следующих шагов в sample/Serenityкаталог.

В рамках проекта у нас будет три цели: статическая библиотека, пакет и совокупность.

Статическая целевая библиотека библиотеки будет создавать источник в статической библиотеке (.a) и указывать, какие заголовки будут "общедоступными", то есть они будут доступны из .framework при его распространении.

Задача связки будет содержать все наши ресурсы и будет загружаться из фреймворка.

Агрегатная цель будет создавать статическую библиотеку для i386/armv6/armv7/armv7s, генерировать жировую структуру бинарный, а также построить пакет. Вы запустите эту цель, когда будете планировать распространение .framework.

Когда вы работаете над каркасом, у вас, вероятно, будет внутреннее приложение, которое ссылается на фреймворк. Это приложение будет ссылаться на цель статической библиотеки, как обычно, и скопировать .bundle на этапе копирования ресурсов. Это имеет смысл только для создания кода структуры для платформы, над которой вы активно работаете, значительно улучшает время сборки. Мы сделаем немного работы в рамках проекта, чтобы убедиться, что вы можете использовать свою инфраструктуру в своем приложении так же, как разработчик третьей стороны (то есть импорт должен работать как и ожидалось). Перейти к зависимому прохождению проекта.

Создать цель статической библиотеки

Шаг 1. Создание нового проекта Cocoa Touch Static Library

Название продукта будет именем вашей структуры. Например, Serenity будет генерировать Serenity.framework после того, как мы создали проект.

Шаг 2. Создание заголовка первичной структуры

Разработчики ожидают, что смогут импортировать вашу инфраструктуру, импортировав <Serenity/Serenity.h> заголовок. Убедитесь, что ваш проект имеет такой заголовок (если вы создали новую статическую библиотеку, то там должен быть файл Serenity.h и Serenity.m; вы можете удалить .m).

В этом заголовке вы собираетесь импортировать все публичные заголовки для своей структуры. Для например, допустим, что у нас есть Widget с .h и .m. Наш файл Serenity.h будет выглядеть например:

#import <Foundation/Foundation.h>
#import <Serenity/Widget.h>

Как только вы создали файл заголовка фреймворка, вам нужно сделать его "общедоступным" заголовком. общественного заголовки - это заголовки, которые будут скопированы в .framework и могут быть импортированы теми, кто использует ваши фреймворк. Это отличается от заголовков "проекта", которые не будут распространяться вместе с каркасом. Это различие - это то, что позволяет вам иметь концепцию публичных и частных API.

Чтобы изменить файл [видимость целевого членства в XCode 4.4+] (Невозможно изменить видимость целевого членства в Xcode 4.5), вам нужно выбрать созданный объект статической библиотеки (Serenity), откройте вкладку "Фазы построения":

Xcode 4.X: Нажмите "Добавить фазу сборки" > "Добавить заголовки копий".

Xcode 5: Добавьте "Сформировать фазы" в меню. Нажмите "Редактор" > "Добавить фазу сборки" → "Добавить фазу сборки заголовков". Примечание. Если параметры меню выделены серым цветом, вам нужно щелкнуть пробелы ниже фаз сборки, чтобы восстановить фокус и повторить попытку.

Вы увидите 3 раздела для заголовков Public, Private и Project. Чтобы изменить область действия любого заголовка, перетащите файлы заголовков между разделами. Кроме того, вы можете открыть Навигатор проектов и выбрать заголовок. Затем разверните панель "Утилиты" для "Инспектор файлов". (Cmd + Option + 0).

Посмотрите на группу "Целевое членство" и убедитесь, что установлен флажок рядом с файлом .h. Измените область заголовка с "Project" на "Public". Возможно, вам нужно снять флажок и установить флажок, чтобы получить раскрывающийся список. Это обеспечит получение заголовка скопировано в нужное место на фазе заголовков копий.

Шаг 3: обновите расположение публичных заголовков

По умолчанию проект статической библиотеки копирует личные и публичные заголовки в одну и ту же папку: /usr/local/include. Чтобы избежать ошибочного копирования личных заголовков в наши рамки, мы хотим обеспечить что наши публичные заголовки копируются в отдельный каталог, например. $(PROJECT_NAME)Headers. Чтобы изменить этот параметр, выберите проект в Навигаторе проектов, а затем перейдите на вкладку "Настройки сборки". Поиск "общественности заголовки ", а затем установите для параметра" Путь к папке общих заголовков "значение" $(PROJECT_NAME) заголовков "для всех конфигураций. Если вы работаете с несколькими Framework, убедитесь, что эта папка уникальна.

Продолжающийся шаг: добавление новых источников в структуру

Всякий раз, когда вы добавляете новый источник в структуру, вы должны решить, следует ли публиковать .h публично или не. Чтобы изменить область заголовка, вы будете следовать тому же процессу, что и в шаге 2. По умолчанию заголовок scope будет "Project", то есть он не будет скопирован в общедоступные заголовки структуры.

Шаг 4: Отключить списание кода

Мы не хотим лишать код из библиотеки; мы оставляем это до приложения, которое связь с каркасом. Чтобы отключить удаление кода, мы должны изменить следующую конфигурацию Параметры:

"Dead Code Stripping" => No (for all settings)
"Strip Debug Symbols During Copy" => No (for all settings)
"Strip Style" => Non-Global Symbols (for all settings)

Шаг 5: Подготовьте основу для использования в качестве зависимой цели

Чтобы использовать статическую библиотеку, как если бы она была основой, мы собираемся создать базовую скелет рамки в статической библиотечной цели. Для этого мы включим простую пост-сборку script. Добавьте post-build script, выбрав свой проект в Навигаторе проектов, выбрав цель, а затем Вкладка "Сборка фаз".

Xcode 4.X: Нажмите "Добавить этап сборки" > "Добавить запуск" Script

Xcode 5: Выберите меню "Редактор" > "Добавить этап сборки" > "Добавить запуск" script Фаза сборки

Вставьте следующий script в исходную часть этапа сборки script. Вы можете переименовать фазу, щелкнув название фазы (я назвал его "Подготовить структуру", например).

prepare_framework.sh
set -e

mkdir -p "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Versions/A/Headers"

# Link the "Current" version to "A"
/bin/ln -sfh A "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Versions/Current"
/bin/ln -sfh Versions/Current/Headers "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Headers"
/bin/ln -sfh "Versions/Current/${PRODUCT_NAME}" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/${PRODUCT_NAME}"

# The -a ensures that the headers maintain the source modification date so that we don't constantly
# cause propagating rebuilds of files that import these headers.
/bin/cp -a "${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}/" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Versions/A/Headers"

Это создаст следующую структуру папок:

-- Note: "->" denotes a symbolic link --

Serenity.framework/
  Headers/ -> Versions/Current/Headers
  Serenity -> Versions/Current/Serenity
  Versions/
    A/
      Headers/
        Serenity.h
        Widget.h
    Current -> A

Попробуйте создать проект сейчас и посмотрите на каталог продуктов для сборки (обычно ~/Library/Developer/Xcode/DerivedData/<ProjectName>-<gibberish>/Build/Products/...). Вам следует см. статическую библиотеку libSerenity.a, папку Headers и папку Serenity.framework, которая содержит основной скелет вашей структуры.

Создать цель распространения инфраструктуры

При активной разработке рамок нам остается только строить платформу, на которой мы тестируем. Для Например, если мы тестируем симулятор iPhone, нам нужно только построить платформу i386.

Это изменяется, когда мы хотим распространять структуру сторонних разработчиков. Сторонний разработчики не имеют возможности перестраивать структуру для каждой платформы, поэтому мы должны предоставить что называется "жирной бинарной" версией статической библиотеки, которая состоит из возможного платформ. Эти платформы включают в себя: i386, armv6, armv7 и armv7s.

Для генерации этого живого бинарного файла мы собираемся создать цель статической библиотеки для каждой платформы.

Шаг 1: Создание целевой совокупности

Выберите "Файл" > "Новая цель" > "iOS" > "Другое" и создайте новую цель "Агрегат". Назовите его чем-то вроде "Framework".

Шаг 2: Добавить статическую библиотеку в качестве зависимой цели

Добавить цель статической библиотеки в "Целевые зависимости".

Шаг 3: постройте другую платформу

Чтобы создать другую платформу, мы будем использовать фазу "Запустить Script" для выполнения некоторых основных команд. Добавьте новую фазу сборки "Запустить Script" в свою совокупную цель и вставьте в нее следующий код.

build_framework.sh
set -e
set +u
# Avoid recursively calling this script.
if [[ $SF_MASTER_SCRIPT_RUNNING ]]
then
    exit 0
fi
set -u
export SF_MASTER_SCRIPT_RUNNING=1

SF_TARGET_NAME=${PROJECT_NAME}
SF_EXECUTABLE_PATH="lib${SF_TARGET_NAME}.a"
SF_WRAPPER_NAME="${SF_TARGET_NAME}.framework"

# The following conditionals come from
# https://github.com/kstenerud/iOS-Universal-Framework

if [[ "$SDK_NAME" =~ ([A-Za-z]+) ]]
then
    SF_SDK_PLATFORM=${BASH_REMATCH[1]}
else
    echo "Could not find platform name from SDK_NAME: $SDK_NAME"
    exit 1
fi

if [[ "$SDK_NAME" =~ ([0-9]+.*$) ]]
then
    SF_SDK_VERSION=${BASH_REMATCH[1]}
else
    echo "Could not find sdk version from SDK_NAME: $SDK_NAME"
    exit 1
fi

if [[ "$SF_SDK_PLATFORM" = "iphoneos" ]]
then
    SF_OTHER_PLATFORM=iphonesimulator
else
    SF_OTHER_PLATFORM=iphoneos
fi

if [[ "$BUILT_PRODUCTS_DIR" =~ (.*)$SF_SDK_PLATFORM$ ]]
then
    SF_OTHER_BUILT_PRODUCTS_DIR="${BASH_REMATCH[1]}${SF_OTHER_PLATFORM}"
else
    echo "Could not find platform name from build products directory: $BUILT_PRODUCTS_DIR"
    exit 1
fi

# Build the other platform.
xcrun xcodebuild -project "${PROJECT_FILE_PATH}" -target "${TARGET_NAME}" -configuration "${CONFIGURATION}" -sdk ${SF_OTHER_PLATFORM}${SF_SDK_VERSION} BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}" SYMROOT="${SYMROOT}" $ACTION

# Smash the two static libraries into one fat binary and store it in the .framework
xcrun lipo -create "${BUILT_PRODUCTS_DIR}/${SF_EXECUTABLE_PATH}" "${SF_OTHER_BUILT_PRODUCTS_DIR}/${SF_EXECUTABLE_PATH}" -output "${BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/A/${SF_TARGET_NAME}"

# Copy the binary to the other architecture folder to have a complete framework in both.
cp -a "${BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/A/${SF_TARGET_NAME}" "${SF_OTHER_BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/A/${SF_TARGET_NAME}"
Важная заметка

Вышеупомянутый script предполагает, что имя вашей библиотеки соответствует имени вашего проекта в следующей строке:

SF_TARGET_NAME=${PROJECT_NAME}

Если это не так (например, ваш проект xcode называется SerenityFramework, а целевое имя - Serenity), тогда вам нужно явно указать целевое имя в этой строке. Например:

SF_TARGET_NAME=Serenity

Шаг 4: Сборка и проверка

Теперь у вас есть все, чтобы создать распределяемую .framework для сторонних разработчиков. Пытаться создавая совокупную цель. После этого разверните папку "Продукты" в Xcode, щелкните правой кнопкой мыши статической библиотеки и нажмите "Показать в Finder". Если это не открывает Finder, где статическая библиотека существует, тогда попробуйте открыть ~/Library/Developer/Xcode/DerivedData/<project name>/Build/Products/Debug-iphonesimulator/.

В этой папке вы увидите свою папку .framework.

Теперь вы можете перетащить .framework в другое место, закрепить его, загрузить и распространить на свой сторонних разработчиков.

Ответ 3

Статические библиотеки не поддерживаются в Swift, поэтому для тех, кто придет сюда искать решение для Swift SDK, вот хороший статья, объясняющая, как это должно быть сделано.