Xcode 发布预编译的CocoaPods

Xcode 发布预编译的CocoaPods,xcode,cocoapods,Xcode,Cocoapods,我们目前正在为使用CocoaPods的客户构建SDK 我们面临的主要问题是,我们的老板希望SDK成为一个黑盒子。他希望我们预先编译代码以保护我们的源代码 为了保护我们的代码,我们在Podspec中可以做些什么?您可以通过创建一个静态框架,并将其包含在Podspec的spec.vendored_frameworks属性中来做到这一点 按照下面的教程学习如何创建自己的静态框架 如何为iOS创建静态框架 在构建.framework时,我们需要满足几个约束条件: 开发框架时快速迭代构建。我们可能有

我们目前正在为使用CocoaPods的客户构建SDK

我们面临的主要问题是,我们的老板希望SDK成为一个黑盒子。他希望我们预先编译代码以保护我们的源代码


为了保护我们的代码,我们在Podspec中可以做些什么?

您可以通过创建一个
静态框架
,并将其包含在Podspec的
spec.vendored_frameworks
属性中来做到这一点

按照下面的教程学习如何创建自己的静态框架

如何为iOS创建静态框架 在构建.framework时,我们需要满足几个约束条件:

  • 开发框架时快速迭代构建。我们可能有一个简单的应用程序 .framework作为依赖项,我们希望快速迭代.framework的开发
  • .framework的不常见发行版本
  • 资源分配应该是直观的,而不是膨胀的应用程序
  • 使用.framework为第三方开发人员进行设置应该很容易
我相信我将在下面概述的解决方案满足这些约束条件。我将概述 如何从头开始构建.framework项目,以便可以将这些步骤应用于现有项目 如果你愿意的话,可以设计。我还将包括项目模板,以便轻松创建 .框架

概述 在
sample/Serenity
目录

在这个项目中,我们将有三个目标:静态库、捆绑包和聚合

静态库目标将源构建到静态库(.a)中,并指定哪些标头 将是“公共的”,这意味着当我们分发它时,可以从.framework访问它们

bundle目标将包含我们的所有资源,并且可以从框架中加载

聚合目标将为i386/armv6/armv7/armv7s构建静态库,生成fat框架 二进制文件,还可以构建包。您将在计划分发时运行此目标 .框架

当您在框架上工作时,可能会有一个内部应用程序链接到 框架此应用程序将像通常一样链接到静态库目标并复制 复制资源阶段中的.bundle。这样做的好处是只构建框架代码 对于您正在积极工作的平台,显著缩短了构建时间。我们将做一个测试 在框架项目中做一些工作,以确保您可以在应用程序中使用您的框架 与第三方开发人员的工作方式相同(即导入) 如预期的那样)。跳转到相关项目演练

创建静态库目标 步骤1:创建一个新的“Cocoa Touch静态库”项目

产品名称将是框架的名称。例如,
Serenity
将生成
Serenity.framework
一旦我们设置了项目

步骤2:创建主框架头 开发人员希望能够通过导入
标题。确保您的项目有这样一个标题(如果您创建了一个新的静态库,那么就在那里) 应该已经是Serenity.h和Serenity.m文件;您可以删除.m)

在此标题中,您将导入框架的所有公共标题。对于 例如,假设我们有一些带有.h和.m的
小部件。我们的Serenity.h文件看起来
像这样:

#import <Foundation/Foundation.h>
#import <Serenity/Widget.h>
步骤5:准备用作依赖目标的框架 为了像使用框架一样使用静态库,我们将生成基本 静态库目标中框架的骨架。为此,我们将包括一个简单的后期构建 剧本通过在项目导航器中选择项目、选择目标,然后选择 “构建阶段”选项卡

Xcode 4.X:单击添加构建阶段>添加运行脚本

Xcode 5:选择编辑器菜单>添加构建阶段>添加运行脚本构建阶段

在运行脚本生成阶段的源部分粘贴以下脚本。可以通过单击重命名阶段 阶段的标题(例如,我将其命名为“准备框架”)

准备_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
现在尝试构建您的项目,并查看buildproducts目录(通常是
~/Library/Developer/Xcode/DerivedData/-/Build/Products/..
)。你应该 请参阅
libSerenity.a
静态库、
Headers
文件夹和
Serenity.framework
文件夹 包含框架的基本框架

创建框架分发目标 在积极开发框架时,我们只关心构建我们正在测试的平台。对于 例如,如果我们在iPhone模拟器上进行测试,那么我们只需要构建i386平台

当我们想要将框架分发给第三方开发人员时,这种情况会发生变化。第三方 开发人员没有为每个平台重建框架的选项,因此我们必须提供 所谓的静态库的“胖二进制”版本,由可能的 平台。这些平台包括:i386、armv6、armv7和armv7s

为了生成这个胖二进制文件,我们将为每个平台构建静态库目标

步骤1:创建聚合目标 单击文件>新目标>iOS>其他并创建新的聚合目标。将其命名为“框架”

步骤2:将静态库添加为从属目标 将静态库目标添加到“目标依赖项”

步骤3:构建另一个平台 为了构建另一个平台,我们将使用“运行脚本”ph
-- Note: "->" denotes a symbolic link --

Serenity.framework/
  Headers/ -> Versions/Current/Headers
  Serenity -> Versions/Current/Serenity
  Versions/
    A/
      Headers/
        Serenity.h
        Widget.h
    Current -> A
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}"
SF_TARGET_NAME=${PROJECT_NAME}
SF_TARGET_NAME=Serenity
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" => "contact@estimote.com" }
  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