iOS静态库开发基础

一、为什么用库

1、为了方便共享源代码,在分享的同时又不愿意暴露源代码及具体实现

2、实现iOS程序组件化,可以把固定的业务模块化成库文件,方便多个工程使用,节省编译时间

3、开发第三方SDK的需要(企业级业务)

二、库的简介

2.1、什么是库?

库是一段编译好的二进制代码,附加上公开的头文件,代码就可以供其他开发者使用。在使用库的时候,编译时只需要链接就好。根据库的链接方式,分为静态库和动态库两类。

2.2、静态库与动态库的区别?

静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。

动态库:链接时不复制到可执行文件中,程序运行时由系统动态加载到内存,程序中只存储指向动态库的引用。系统只加载一次,多个程序共用,节约了内存。

针对iOS项目,可以以下面的方式来简单区分:

以==Embedded Binaries==方式导入为动态库;

以==Link Binary With Libraries== 方式导入为静态库。

2.3、iOS中静态库

.a和.framework。

主流的SDK开发方式,腾讯、百度等大厂的SDK主要采用静态开发方式。

静态库不能嵌套(见iOS中Framework Library嵌套使用),这样可以减少库与其他库之间的耦合。

但是在使用静态库的时候,需要导入所依赖的其他库文件,这样会比较麻烦。因此,当SDK需要引用其他SDK,且不希望将内部实现暴露给用户时,那么就会采用动态库形式,这种一般是系统级的库文件。

2.4、iOS中动态库

.dylib,.tbd和.framework,主要是系统组件。

若SDK和项目中用到相同的三方库(如:AFNetworking),在使用动态库时,工程和项目中可以存在2份AFNetworking,因此开发相对方便一些。而静态库只会存在一份,因此开发相对复杂,但是可以减少代码的冗余。

注意:

在导入自定制的动态库时,要在Embedded Binaries中导入,不然会报错:image not found。

2.5、framework为什么既是静态库又是动态库?

.framework本质上并不是一个库,它是苹果为了方便开发者提供了一种库的打包方式,Framework会将Mach-O文件、头文件和资源包全都包含进来,不需要你再手动整理,我们也可以通过Xcode来制作framework动态库使用。

系统的.framework是动态库形式。

开发者所创建的.framework大部分是静态库,因此需要拷贝到目标程序中。

所以说.framework既可以是静态库也可以是动态库,这取决于编译成的Mach-O(就是那个二进制文件)是以动态库还是静态库形式编译。

综上: .framework是iOS开发中库的一种打包形式,既可以是动态库也是静态库。

2.6、a与.framework有什么区别?

.a是一个纯二进制文件,.framework中除了有二进制文件外还有资源文件,一个比较简单的描述即.a + .h + sourceFile = .framework。

所以.a文件不能直接使用,需要添加对应的.h文件,而.framework文件可以直接供开发者使用。

2.7、静态库开发的注意事项:

1、无论是.a静态库还.framework静态库,需要的都是二进制文件+.h+其它资源文件的形式。不同的是,.a本身就是二进制文件,需要我们手动加上.h和其它资源文件,而.framework本身已经包含了.h和其它文件。

2、图片资源的处理:在.a和.framewok两种静态库文件,一般都是把图片资源拿出,相应放在一个.bundle、.bundle的名字可以和.a或.framework的名字相同。一种方式是:可直接创建一个文件夹,后缀名为.bundle,在显示包内容时,添加图片资源文件。另一种方式是:在Xcode的工程中添加bundle target,添加图片资源文件。

3、Category在实际开发项目中会经常用到的。将Category打包成静态库,不会有什么问题的。但是在应用该静态库的工程中,会遇到调用Category的方法,找不到该方法的运行时错误(Selector not recognized)。这是因为链接标志所造成的,需要在应用静态库的工程配置,在==Other linker flags==处,添加『-ObjC』。

4、如果一个静态库较为复杂,必须暴露的.h文件过多,可在静态库的内部创建一个专门的.h文件(一般这个.h文件的名字和静态库名相同),然后把所有需要暴露的.h文件集中到此.h文件,再把这个.h文件暴露即可。

三、静态SDK开发流程

3.1、静态SDK的创建和配置

1、创建空白Xcode Workspace

2、创建SDK工程

(1)创建SDK

在当前workspace中创建SDK工程,如图1所示,并将SDK工程与workspace关联,如图2所示。

图1.png

图2.png

配置SDK为静态库。

配置==Deployment Target==iOS 9.0

Mach-O Type ==Static Library==

Enable Bitcode ==No==

Edit Scheme - Run - Info - Build Configuration ==Release==

(2)创建Bundle

因为在静态库中,SDK中的图片资源及xib等,需要添加到对应的Bundle中。所以在步骤(1)中的工程添加『target』,如图3所示,并配置如下:

图3.png

Build Settings - Base SDK - ==iOS==

Deployment Target -9.0

Enable Bitcode ==NO==

清除Build settings - Installation Directory路径信息

COMBINE_HIDPI_IMAGES设置为==NO==

Edit Scheme - Run - Info - Build Configuration ==Release==

(3)配置生成脚本

在iOS开发中,模拟器运行平台为PC,架构为i386和x86_64等,而真机的架构为arm7和arm64等。所以,为了使SDK在模拟器及真机上都可运行,则需编译生成两个在不同平台的SDK,然后再用工具合二为一。

在SDK工程中,添加对应的Aggregate工程。

图4.png

在设置Build Phrase中设置Target Dependices关联SDK工程,另外为Run Script添加下列代码,如图5所示。

#  This is a modified script and it will ask the target to build separate libraries for simulator and device etc   
# On project folder it will be found under Generated-Frameworks folder  
# As per the documentations for XCode 10 Apple does not allow building FAT librares  
# Go ahead and check https://forums.developer.apple.com/thread/66978 and https://forums.developer.apple.com/thread/109583  
# Enjoy NicoX :)  

set -e  
# If we're already inside this script then die  
if [ -n "$MULTIPLATFORM_BUILD_IN_PROGRESS" ]; then  
exit 0  
fi  
export MULTIPLATFORM_BUILD_IN_PROGRESS=1  

############################################  
# Options  
############################################  
REVEAL_ARCHIVE_IN_FINDER=true  
OUTPUT_DIR_NAME="Generated-Frameworks" 

FRAMEWORK_NAME="${PROJECT_NAME}"  

OUTPUT_DIR="${PROJECT_DIR}/${OUTPUT_DIR_NAME}/${FRAMEWORK_NAME}-${CONFIGURATION}-framework"  
SIMULATOR_LIBRARY_OUT_DIR="${OUTPUT_DIR}/Simulator/"  
GENERATED_LIBRARY_DIR="${BUILD_DIR}/${CONFIGURATION}-iphoneuniversal"  
SIMULATOR_FRAMEWORK_OUT_DIR="${GENERATED_LIBRARY_DIR}/Simulator"  
FRAMEWORK="${SIMULATOR_FRAMEWORK_OUT_DIR}/${FRAMEWORK_NAME}.framework"  

########################################################################  
# Build Frameworks  
########################################################################  
xcodebuild -scheme ${PROJECT_NAME} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator OBJROOT="${OBJROOT}/DependantBuilds"   

########################################################################  
# Create directory for general  
########################################################################  
rm -rf "${GENERATED_LIBRARY_DIR}"  
mkdir "${GENERATED_LIBRARY_DIR}"  
mkdir "${SIMULATOR_FRAMEWORK_OUT_DIR}"  
mkdir "${FRAMEWORK}"  

########################################################################  
# Copy files Framework  
########################################################################  
SIMULATOR_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework"  

########################################################################  
# Make a binary for simulaotr ie. x86_64 ot i386 file system  
########################################################################  
# For Swift framework, Swiftmodule needs to be copied in the universal framework   
if [ -d "${SIMULATOR_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/" ]; then  
cp -f "${SIMULATOR_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/"* "${FRAMEWORK}/Modules/${FRAMEWORK_NAME}.swiftmodule/" | echo  
fi  
cp -r "${SIMULATOR_LIBRARY_PATH}/." "${FRAMEWORK}"  

########################################################################  
# Copy simulator build library in output folder  
########################################################################  
rm -rf "$OUTPUT_DIR"  
mkdir -p "$OUTPUT_DIR"  
mkdir -p ${SIMULATOR_LIBRARY_OUT_DIR}  

cp -r "${FRAMEWORK}" "$SIMULATOR_LIBRARY_OUT_DIR"  
#########################################################################  

echo "Simulator Lib Path ---->" "${SIMULATOR_LIBRARY_PATH}" "<----"  

##########################################################################  
# Now lets build for device; shall we?  
##########################################################################  
DEVICE_LIBRARY_OUT_DIR="${OUTPUT_DIR}/Device/"  
DEVICE_FRAMEWORK_OUT_DIR="${GENERATED_LIBRARY_DIR}/Device"  
FRAMEWORK="${DEVICE_FRAMEWORK_OUT_DIR}/${FRAMEWORK_NAME}.framework"  

########################################################################  
# Build Device Frameworks  
########################################################################  
xcodebuild -scheme ${PROJECT_NAME} -sdk iphoneos ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos OBJROOT="${OBJROOT}/DependantBuilds"   

########################################################################  
# Create directory for general  
########################################################################  
rm -rf "${GENERATED_LIBRARY_DIR}"  
mkdir "${GENERATED_LIBRARY_DIR}"  
mkdir "${DEVICE_FRAMEWORK_OUT_DIR}"  
mkdir "${FRAMEWORK}"  

########################################################################  
# Copy files Framework  
########################################################################  
DEVICE_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework"  

########################################################################  
# Make a binary for device ie. arm7, arm7v, arm8 file system  
########################################################################  
# For Swift framework, Swiftmodule needs to be copied in the universal framework   
if [ -d "${DEVICE_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/" ]; then  
cp -f "${DEVICE_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/"* "${FRAMEWORK}/Modules/${FRAMEWORK_NAME}.swiftmodule/" | echo  
fi  
cp -r "${DEVICE_LIBRARY_PATH}/." "${FRAMEWORK}"  
########################################################################  
# Copy device build library in output folder  
########################################################################  
mkdir -p ${DEVICE_LIBRARY_OUT_DIR}  
cp -r "${FRAMEWORK}" "$DEVICE_LIBRARY_OUT_DIR" 

echo "Device Lib Path ---->" "${DEVICE_LIBRARY_PATH}" "<----"  

# Copy device build library in output folder  
# Create Cross Platform Output
########################################################################  
cp -r  "${DEVICE_LIBRARY_OUT_DIR}/" "${OUTPUT_DIR}/"
lipo -create "${DEVICE_LIBRARY_OUT_DIR}${PROJECT_NAME}.framework/${PROJECT_NAME}" "${SIMULATOR_LIBRARY_OUT_DIR}${PROJECT_NAME}.framework/${PROJECT_NAME}" -output "${OUTPUT_DIR}/${PROJECT_NAME}.framework/${PROJECT_NAME}"

if [ ${REVEAL_ARCHIVE_IN_FINDER} = true ]; then  
    open "${OUTPUT_DIR}//"  
fi  


图5.png

同上面的步骤,修改工程中的Target配置

Enable Bitcode 设置为==NO==

Edit Scheme - Run - Info - Build Configuration ==Release==

3.2、Demo工程的创建与配置

1、创建Demo工程

创建一个空白iOS工程,关联到当前workspace。

2、关联SDK工程

在Demo工程设置==Link Binary With Libraries==,加入SDK工程编译生成的framework,如图6所示。

图6.png

3.3、SDK开发

1、SDK功能开发

在DemoSDK中添加源码文件,开发对应的功能。本例中添加一个简单的VC作为示例,

图7.png

添加测试用的图片资源,

图8.png

将新添加的代码头文件添加到SDK的Public Header中,

图9.png

在SDK头文件中,引用新建的源码头文件

图10.png

将SDK中Building Phases中的Copy Bundle Resources中的图片资源或者xib等移除掉,后续会加入到SDK专属的Bundle文件中。

图11.png

在修改SDK工程的源码之后,清理并重新编译工程。

2、SDK Bundle生成

在SDK中的Bundle Target中,Copy Bundle Resources处添加对应的资源,

图12.png

编译Bundle Target,在SDK工程目录中的Products目录下找到相应的.bundle文件,将其复制到SDK Demo工程所对应的文件中。然后在SDK Demo中的Copy Bundle Resouces里面添加刚才的.bundle文件。

图13.png

3.3、SDK调试

此时在SDK Demo工程当中,引用SDK 头文件,测试SDK提供的功能和视图。

图14.png

在模拟器中Run工程,在SDK源码中添加断点,然后在模拟器中查看实际效果。

图15.gif

四、手动应用SDK

4.1 生成Framework

选择SDK工程的Cross Target,编译运行Target,执行配置好的生成脚本,就打包好可以在模拟器与真机上都可成功运行的.framework文件。

4.2 使用SDK

类似于步骤3.2,将SDK的文件添加到目标工程中。

4.3 开发工程

参考

一、包含 Bundle 资源的 framework 的正确打包方式

二、iOS SDK开发(静态SDK)

三、iOS静态库SDK制作(包含第三方静态库)

四、Xcode中的 workspace, project, target, scheme

五、Fat Framework Script for Xcode 10?

六、iOS 静态库,动态库与 Framework

七、iOS中Framework Library嵌套使用

八、jverkoey/iOS-Framework

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容