制作静态库
- 动态库:
.dylib
.framework
- 静态库:
.a
.framework
两者区别*:动态库时在程序运行时动态链接的,且可以被多个程序链接,相当于以动态库为中心,系统只会加载动态库到内存一次,这样动态库就始终只占一份内存,而静态库是提前把需要编译的实现文件编译为二进制文件,每个程序都需要复制一份,这是在使用静态库就决定了的特性,我们需要把静态库复制到工程文件内,供我们程序使用,而在制作时静态库时,我们可以选择暴露哪些文件给使用者,当然大部分都只需暴露头文件,我们当然也可以暴露实现文件,供我们参考学习,了解其中原理,众使我们修改了该文件的内容也没关系,因为该文件已经在制作静态库时已经编译成二进制文件,我们使用时不会再次编译该文件,资源文件如图片等也是可以我们替换,因为编译时只是简单的COPY,所以我们可以替换SVProgressHUB
里的error或success成我们个性化的图片。苹果官方不允许我们App包含动态库。
.a
与.framework
的区别:
制作.a
都需要我们手动在Header Search Paths
加头文件搜索路径
制作 .framework
不需要
制作.framework
静态库
我们先说.framework
的制作过程,我们新建项目选择iOS的framwork / library ,建好后默认有一个头文件,这不是我们需要的,直接删掉,这里我们可以任意建文件夹和文件,把我们需要的功能库搭建好后,我们在Build phase > Headers > public 内添加我们需要暴露的文件,这样我们就建好了,然后我们分别选着模拟器 和 Generic iOS Device
来构建我们的product ,只有当我们构建完Generic iOS Device
才能看到product内的target由红色变为黑色,这说明文件存在,构建完毕,然后我们右键 show in finder
找到编译好的文件,当然,这个文件只包含armv7 和arm64 架构的。我们还需要在Mach-type
修改类型为Static Library
,当然我们也可以制作动态库,只是不能发布。如果你制作动态库就需要在Embedded Binaries
内添加库。
对于这几种CPU架构分类:
真机:
3gs ~ 4s :armv7
5 ~5c :armv7s
5s~ 6plus:arm64
模拟器:
4s~5 : i386
5s~6plus : x86_64
所以我们需要合并这几种包,并且都是debug包,我们一般发布给别人Release包,这需要我们Edit Scheme 选择Run > info >build configuration 为Release。Release包会比debug包要小一点,因为编译时作了代码优化,运行效率会高一点,但不会明显提高。
为了保证都能运行,我们还需要合并包,这里的包是.framework
文件里的同名的无扩展名的二进制文件,使用下面命令合并,更多使用方法( man lipo
)
lipo -create test1 test2 -output test3
然后替换之前任意一个同名的二进制文件,这里多次强调同名,因为系统就是根据根据静态库名在静态库内寻找二进制文件,不然会报找不到该文件的错误。
这样我们直接把替换二进制文件后的.framework
文件拖进我们其它工程直接使用。
当然如果我们还需要在静态库内使用资源文件,我们使用Bundle,在该项目内Add Target ,选择OSX 内的Bundle,我们需要删除一系列,修改sdk,修改product name等等。
制作.a
静态库
类似制作.framework
静态库,我们新建项目XHQ_StaticFramework
,选择Cocoa Touch Static Library
这时可以看到两个文件夹:XHQ_StaticFramework
和Product
, Xcode 为我们自动建好的XHQ_StaticFramework(.h/.m)
文件,一般我们只需要头文件,头文件写下我们所有需要公开的头文件,其它全部删掉,以便客户使用时只需引入这个头文件。Product存放我们生成的二进制文件。这里我们引入<UIKit/UiKit.h>框架,(网上多个版本都提到需要在Build Phrases >Link Binary With Libraries
内添加UIKit.framework
,但是作者没有添加也能正常使用,如果你知道原因请告诉我,谢谢!)
我们在XHQ_StaticFramework
文件夹下建好我们自己的代码库后,把需要公开的头文件加到Build Phases >Headers
,如果你没有这个目录,你需要手动Editor > Add Build Phases> Add Headers Build Phases
来添加。(提示:如果无法选择,你需要点击Build Phases 空白处后再重复上面的步骤。)
点开 Headers 默认是有三个文件目录: public&&private&&project
, 其中pulic和private都是放对外公开的文件,两者区别就是存储的路径可能不一样,我们可以在Packaging> Private/Public Headers Folder Path
设置路径。这里我们设置为include/$(PROJECT_NAME)
,project
存放我们私有的文件。
然后我们需要在Build Settings
设置一些值:
Dead Code Stripping > NO(去掉不会执行到的代码)
Strip Style > Debugging Symbols
Strip Debug Symbol During Copy > NO(去掉Debug相关符号)
Strip Linked Product > NO
这样做是为了后期产生bug时,我们能通过符号文件定位到我们需要的类的信息, 但是如果是iOS 或者 OSX则配置完全相反。相关文章
我们编译成功后就可以正常使用。使用时我们有两种方式
一种是在其它项目中拖进该项目,在新项目中添加依赖
Build Phases > Target Dependencies
添加.a
静态库,然后就是link library
内添加.a
静态库;
上面的方式适合我们自己内部使用,好处就是可以动态的修改静态库的文件,Xcode会根据是否需要重新编译来生成静态文件,而其实我们可以是直接使用生成的
.a
静态库和包涵头文件的include文件夹,只不过我们每次都需要配置Search Headers Paths,这种方式适合给外部使用。
使用脚本生成集成包
相信上面的这些分别生成支持不同架构的包已经让你精疲力竭,我们有更加方便的方法制作通用的包,那就是使用脚本来构建支持多个架构的包.首先我们在前面制作framework的基础上添加
Aggragate
target,然后在Build Phases
内添加 Run Script
把下面代码添加进去。直接运行,然后生成的包目录会自动打开。
FMK_NAME=${PROJECT_NAME}
# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework
# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework
# -configuration ${CONFIGURATION}
# Clean and Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos clean build
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator clean build
# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ];then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"
rm -r "${WRK_DIR}"
open "${INSTALL_DIR}"