二进制库有编译快,保密源码的特性,在有些场景非常适用。
本文介绍了在组件化过程中需要对组件转换成二进制库的方法,是通过 xcodebuild
命令进行制作的。
下篇则介绍适用 pod package
进行制作的方法。
测试环境:
- Xcode 10
- CocoaPods 1.6.0
- iOS 12
Demo
一、制作 framework
1.创建 Target (名称为 Binary_framework)
2.修改 Podfile 添加依赖
注意:
- Podfile 文件中不能没有制作 .a 静态库的限制,可以直接给 target Binary_framework 添加 pod 依赖。以下写法是允许的。
# 该写法是允许的 target 'Binary_framework' do pod 'AFNetworking' end
3.在 .xcodeproj 目录下创建脚本
4.运行脚本
说明:
看起来脚本很长,核心只有两行
xcodebuild -workspace "${WORKSPACE}" -scheme "${SCHEME}"
功能等同于 xcode 选择相应 scheme(就是 target)点击编辑,此外的都是编译相关的参数lipo -create "${IPHONEOS_PATH}" "${SIMULATOR_PATH}" -output "${OUTPUT_PATH}"
功能是合并真机和模拟器的 framework 为一个通用的
注意:
- 脚本中 PROJECT_NAME 和 TARGET_NAME 按照项目实际情况填写
- 因为 target 可能有多个,不是固定的,可以在执行脚本的是传入参数指定需要编译的 target。如
./build_framework.sh targetName
,那么就会编译叫做 targetName 的 target
#要build的target名
TARGET_NAME="Binary_framework"
if [[ $1 ]]
then
TARGET_NAME=$1
fi
# 项目名
PROJECT_NAME="Binary"
# 模拟器支持架构,i386 x86_64
SIMULATOR_ARCHS="x86_64"
# 真机支持架构,armv7 armv7s arm64
IPHONEOS_ARCHS="arm64"
CONFIGURATION="Release"
#构建一个xcode工作空间,你必须通过-workspace和-scheme定义这个构建。scheme参数控制哪一个targets被构建如何被构建
WORKSPACE="${PROJECT_NAME}.xcworkspace"
SCHEME="${TARGET_NAME}"
# 编译真机的Framework
xcodebuild -workspace "${WORKSPACE}" -scheme "${SCHEME}" ARCHS="${IPHONEOS_ARCHS}" -configuration "${CONFIGURATION}" -sdk "iphoneos" clean build CONFIGURATION_BUILD_DIR="build/${CONFIGURATION}-iphoneos" LIBRARY_SEARCH_PATHS="./Pods/build/${CONFIGURATION}-iphoneos"
#编译模拟器的Framework
xcodebuild -workspace "${WORKSPACE}" -scheme "${SCHEME}" ARCHS="${SIMULATOR_ARCHS}" -configuration "${CONFIGURATION}" -sdk "iphonesimulator" clean build CONFIGURATION_BUILD_DIR="build/${CONFIGURATION}-iphonesimulator" LIBRARY_SEARCH_PATHS="./Pods/build/${CONFIGURATION}-iphonesimulator"
# 创建输出目录,并删除之前的framework文件
OUTPUT_DIR="output"
mkdir -p "${OUTPUT_DIR}"
# 执行 xcodebuild 会在该目录下生成 framework
BUILD_DIR="build"
#拷贝framework到 output 目录
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework" "${OUTPUT_DIR}"
#真机静态库路径
IPHONEOS_PATH="${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/${TARGET_NAME}"
#模拟器静态库路径
SIMULATOR_PATH="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}"
#输出路径
OUTPUT_PATH="${OUTPUT_DIR}/${TARGET_NAME}.framework/${TARGET_NAME}"
#合并framework,输出最终的framework到output目录
lipo -create "${IPHONEOS_PATH}" "${SIMULATOR_PATH}" -output "${OUTPUT_PATH}"
# 删除 build 文件夹
# rm -rf "${BUILD_DIR}"
#打开合并后的文件夹
# open "${OUTPUT_DIR}"
5.结果
二、制作 .a 静态库
1.创建 Target (名称为 Binary_lib)
2.修改 Podfile 添加依赖
注意:
- Podfile 文件中不能以 Binary_lib 为 target pod 依赖库,否则会造成目录改变打包失败,暂时不知道原因。但是若通过 Aggregate 创建脚本打包则没有这个问题。如下注释
```ruby
target ‘Binary_Example’ do
pod ‘Binary’, :path => ‘../’
⚠️⚠️⚠️ 可以在这添加
pod ‘AFNetworking’
target ‘Binary_Tests’ do inherit! :search_paths
end end
⚠️⚠️⚠️ Binary_lib 不能作为 target 使用,要 pod 依赖库可以在上面的 Binary_Example 添加或者新建一个 Test 的 target 添加。
#target ‘Binary_lib’ do
pod ‘AFNetworking’
#end
#### 3.在 .xcodeproj 目录下创建脚本
![5.png](../images/2018-12-25-组件化-静态库-1/5.png)
#### 4.运行脚本
##### 注意:
* 脚本中 PROJECT_NAME 和 TARGET_NAME 按照项目实际情况填写
* xcodebuild 命令中的参数 `CONFIGURATION_BUILD_DIR`、`LIBRARY_SEARCH_PATHS`、`HEADER_SEARCH_PATHS` 不是必须的,正常的 `pod install` 命令会在 Build Settings 中的将这些参数设置好。但是有时候若 Build Settings 没有设置,xcodebuild 命令中加上以上参数可以保证不会找不到 pod 的依赖库。
##### 脚本:
```bash
#要build的target名
TARGET_NAME="Binary_lib"
if [[ $1 ]]
then
TARGET_NAME=$1
fi
# 项目名
PROJECT_NAME="Binary"
# 模拟器支持架构,i386 x86_64
SIMULATOR_ARCHS="x86_64"
#
# 真机支持架构,armv7 armv7s arm64
IPHONEOS_ARCHS="arm64"
CONFIGURATION="Release"
PROJECT=${PROJECT_NAME}.xcodeproj
TARGET="${TARGET_NAME}"
# 制作的静态库在根目录的 build 文件夹下,一下命令中 CONFIGURATION_BUILD_DIR、LIBRARY_SEARCH_PATHS、HEADER_SEARCH_PATHS 不是必须
# 制作真机的静态库
xcodebuild -project $PROJECT -target $TARGET -sdk "iphoneos" -configuration $CONFIGURATION ARCHS="${IPHONEOS_ARCHS}" build CONFIGURATION_BUILD_DIR="build/${CONFIGURATION}-iphoneos" LIBRARY_SEARCH_PATHS="./Pods/build/${CONFIGURATION}-iphoneos" HEADER_SEARCH_PATHS="./Pods/Headers/Public"
# 制作模拟器的静态库
xcodebuild -project $PROJECT -target $TARGET -sdk "iphonesimulator" -configuration $CONFIGURATION ARCHS="${SIMULATOR_ARCHS}" build CONFIGURATION_BUILD_DIR="build/${CONFIGURATION}-iphonesimulator" LIBRARY_SEARCH_PATHS="./Pods/build/${CONFIGURATION}-iphonesimulator" HEADER_SEARCH_PATHS="./Pods/Headers/Public"
#静态库名
LIB_NAME="lib${TARGET}.a"
#真机静态库路径
IPHONEOS_PATH="build/${CONFIGURATION}-iphoneos/${LIB_NAME}"
#模拟器静态库路径
SIMULATOR_PATH="build/${CONFIGURATION}-iphonesimulator/${LIB_NAME}"
#include 路径
INCLUDE_PATH="build/${CONFIGURATION}-iphoneos/include"
#输出文件夹
OUTPUT_DIR="output"
#创建输出文件夹
mkdir -p "${OUTPUT_DIR}"
#复制 include 移至输出文件夹
cp -rp "${INCLUDE_PATH}" "${OUTPUT_DIR}"
#输出路径
OUTPUT_PATH="${OUTPUT_DIR}/${LIB_NAME}"
#合并真机、模拟器静态库为一个,-create 输入两个静态库的路径,-output 输出静态库路径
lipo -create "${IPHONEOS_PATH}" "${SIMULATOR_PATH}" -output "${OUTPUT_PATH}"
5.结果
三、制作 .a 静态库后合并成 framework
因为 framework 是 iOS 8 之后的产物,想要将支持 iOS 7 的代码制作成 framework,可以先生成 .a 静态库后合并成 framework
运行脚本
注意:
- 脚本基本和制作 .a 相同,只是在结尾处将 .a 文件转换成 framework 文件
#要build的target名
TARGET_NAME="Binary_lib"
if [[ $1 ]]
then
TARGET_NAME=$1
fi
# 项目名
PROJECT_NAME="Binary"
# 模拟器支持架构,i386 x86_64
SIMULATOR_ARCHS="x86_64"
#
# 真机支持架构,armv7 armv7s arm64
IPHONEOS_ARCHS="arm64"
CONFIGURATION="Release"
PROJECT=${PROJECT_NAME}.xcodeproj
TARGET="${TARGET_NAME}"
# 制作的静态库在根目录的 build 文件夹下
# 制作真机的静态库
xcodebuild -project $PROJECT -target $TARGET -sdk "iphoneos" -configuration $CONFIGURATION ARCHS="${IPHONEOS_ARCHS}" build CONFIGURATION_BUILD_DIR="build/${CONFIGURATION}-iphoneos" LIBRARY_SEARCH_PATHS="./Pods/build/${CONFIGURATION}-iphoneos" HEADER_SEARCH_PATHS="./Pods/Headers/Public"
# 制作模拟器的静态库
xcodebuild -project $PROJECT -target $TARGET -sdk "iphonesimulator" -configuration $CONFIGURATION ARCHS="${SIMULATOR_ARCHS}" build CONFIGURATION_BUILD_DIR="build/${CONFIGURATION}-iphonesimulator" LIBRARY_SEARCH_PATHS="./Pods/build/${CONFIGURATION}-iphonesimulator" HEADER_SEARCH_PATHS="./Pods/Headers/Public"
#静态库名
LIB_NAME="lib${TARGET}.a"
#真机静态库路径
IPHONEOS_PATH="build/${CONFIGURATION}-iphoneos/${LIB_NAME}"
#模拟器静态库路径
SIMULATOR_PATH="build/${CONFIGURATION}-iphonesimulator/${LIB_NAME}"
#include 路径
INCLUDE_PATH="build/${CONFIGURATION}-iphoneos/include"
#输出文件夹
OUTPUT_DIR="output"
#创建输出文件夹
mkdir -p "${OUTPUT_DIR}"
# *************************************
# .a 静态库合并成 framework 静态库所做操作
# *************************************
mkdir -p "${OUTPUT_DIR}/${TARGET}.framework/Versions/A/Headers"
ln -sfh "A" "${OUTPUT_DIR}/${TARGET}.framework/Versions/Current"
ln -sfh "Versions/Current/Headers" "${OUTPUT_DIR}/${TARGET}.framework/Headers"
ln -sfh "Versions/Current/${TARGET}" "${OUTPUT_DIR}/${TARGET}.framework/${TARGET}"
cp -a "build/${CONFIGURATION}-iphoneos/include/${TARGET}/" "${OUTPUT_DIR}/${TARGET}.framework/Versions/A/Headers"
#输出路径
OUTPUT_PATH="${OUTPUT_DIR}/${TARGET}.framework/Versions/A/${TARGET}"
#合并真机、模拟器静态库为一个,-create 输入两个静态库的路径,-output 输出静态库路径
lipo -create "${IPHONEOS_PATH}" "${SIMULATOR_PATH}" -output "${OUTPUT_PATH}"
四.编译多个 Target
一个工程可以有多个 target,生成多个 framework。在实际应用中,如果一个组件 CocoaPods 发布时需要多个 subspec
,那么可以通过编译多个 target 实现。
build_all.sh
./build_framework.sh Binary_framework
#./build_framework.sh Binary_framework2
#./build_framework.sh Binary_framework3
#..... 省略