这里输入引用文本本文记录一下,在SDK开发完成后,如何高效率制做framework。swift
##iOS关于静态库、动态库的一些基本概念和理解误区 ###1. 库 库是源代码通过编译,造成的二进制代码,别人项目中使用咱们的库的时候,库在参与编译的时候,直接link就OK了,按照link的方式,能够把库分为静态库和动态库 ###2. 静态库 静态库在编译的时候会被直接拷贝一份,复制到目标程序里,这段代码在目标程序里就不会再改变了。xcode
通常以**.a** 和 .framework为文件后缀名安全
这种作法是牺牲应用“体量”来节省编译时间。 ###3. 动态库 与静态库相反,动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向动态库的引用。等到程序运行时,动态库才会被真正加载进来。app
动态库的优势是,不须要拷贝到目标程序中,不会影响目标程序的体积,并且同一份库能够被多个程序使用(由于这个缘由,动态库也被称做共享库)。框架
同时,编译时才载入的特性,也可让咱们随时对库进行替换,而不须要从新编译代码。动态库带来的问题主要是,动态载入会带来一部分性能损失,使用动态库也会使得程序依赖于外部环境。若是环境缺乏动态库或者库的版本不正确,就会致使程序没法运行iphone
以**.tbd**(以前叫.dylib) 和** .framework** 为文件后缀名工具
苹果系统为咱们提供了不少动态连接库,咱们能够在咱们项目工程中查看一下性能
###4. Framework Framework 是一种打包方式,将库的二进制文件,头文件和有关的资源文件打包到一块儿,方便管理和分发。测试
Framework只是一种打包方式,其自己和静态、动态无关!ui
但Cocoa Touch Framework 的实际内容为 Header + 动态连接库 + 资源文件
###5. 对Framework认识的误区 误区①:.framework是动态库,.a是静态库,前面已经讲过,再也不赘述
误区②:有人说“自定义的动态库苹果审核不经过”,那我打的framework是否是通不过审核?
任何没有时间前提的结论都是耍流氓!!!
在 **iOS 8 / iOS6以前,**iOS 平台不支持使用动态 Framework,开发者可使用的 Framework 只有系统的framework,这种限制多是出于安全的考虑
换一个角度讲,由于 iOS 应用都是运行在沙盒当中,不一样的程序之间不能共享代码,同时动态下载代码又是被苹果明令禁止的,没办法发挥出动态库的优点,实际上动态库也就没有存在的必要了
可是,码农老是喜欢折腾的,一方面骨子里面有一种“你不让我作我偏要作的倔强”,另外一方面用framework确实比用.a加头文件的方式简单,因此这一时期的开发者用了不少**“奇淫技巧”来制做framework**,这就有了Fake Framework 和 Real Framework的区分
华丽的分割线------
在 **iOS 8 / iOS6后,iOS平台添加了动态库的支持,同时, Xcode 6 也原生自带了 Framework 支持,注意,先后两个维度的不一样是两件事,不要混淆。。。
那么,为何 iOS 8 要添加动态库的支持?
主要的理由大概就是 Extension 的出现。Extension 和 App 是两个分开的可执行文件,同时须要共享代码,这种状况下动态库的支持就是必不可少的了。可是这种动态 Framework 和系统的 UIKit.Framework 仍是有很大区别;还有就是为了支持swift
虽然一样是动态框架,可是和系统 framework 不一样,app 中的使用的 Cocoa Touch Framework 在打包和提交 app 时会被放到 app bundle 中(App 和 Extension 的 Bundle 是共享的),运行在沙盒里,而不是系统中。也就是说,不一样的 app 就算使用了一样的 framework,但仍是会有多份的框架被分别签名,打包和加载,所以苹果又把这种 Framework 称为** Embedded Framework**,也正是代码签名机制,经过AppStore发布的APP是没法经过替换服务端下发framework的方式来进行热更新!
##项目遇到的痛点 项目组原本是使用脚本结合xctool
(Facebook的一个开源项目)的方式来打包制做framework,但在升级xcode8以后,xctool
在xcode8下出现了bug,并且Facebook并无在第一时间维护这个项目,一时间一脸懵逼。。。
因为项目时间紧,无奈之下只能采用了一个临时解决方案,就是从新下载一个xcode7版本,让xctool在xcode7环境下打包,但这绝非长久之计!
大概一个月以后,虽然xctool
项目更新了对 xcode8 以及 xcode8.1 的支持,但仍是决定放弃原有的方案,缘由有二,首先,Facebook有着很好的开源精神,可是也是出了名的喜欢撒手无论的角儿,万一哪天中止对这个工具的维护,我怎么办!!!用一种简单、稳定、可靠的解决方案是咱们急需的;第二,xctool
有很强大的功能,但咱们在项目中只用了其中一小块,有点杀鸡用牛刀的意思,项目中不少冗余。 ##解决方案 替代方案就是用xcode提供的aggregate
结合脚原本制做framework ##制做过程 ###1. 用workspace管理SDK project 新建一个workspace,命名为TestSDKWorkspace
如今生成的workspace仍是一个空的什么都没有,接着往里面添加咱们的静态库project
点击左下角的**+**号
project类型选择cocoa touch framework,取名为TeskSDK
在SDK项目中添加测试源代码,写一个Test类,对外提供testMethod
方法,注意,这个类要添加到SDK target中去!
#import <Foundation/Foundation.h> @interface Test : NSObject - (void)testMethod; @end #import "Test.h" @implementation Test - (void)testMethod{ NSLog(@"--------"); NSLog(@"this is a test method"); NSLog(@"--------"); } @end
咱们决定对外暴露Test.h,将其添加至接口文件中
此时,咱们编码准备工做已经作好了,command+B
,咱们能够在product文件夹下面看到有一个TestSDK.framework从红变黑,这是否是意味着咱们须要的framework已经大功告成了呢?
no!!!咱们此时只是在特定平台下编译的,获得的也只是这个平台下的framework,咱们在文件夹中查看以下图
这就意味着咱们要打同平台的包,须要通过屡次编译,最后再去合成,这太麻烦了 ###2. 用“Aggregate+脚本”制做framework 选择TARGETS点击而后添加Aggregate
添加以下脚本到Aggregate target对应的build phases-->run script中
#!/bin/sh #要build的target名 TARGET_NAME=${PROJECT_NAME} if [[ $1 ]] then TARGET_NAME=$1 fi UNIVERSAL_OUTPUT_FOLDER="${SRCROOT}/${PROJECT_NAME}_Products/" #建立输出目录,并删除以前的framework文件 mkdir -p "${UNIVERSAL_OUTPUT_FOLDER}" rm -rf "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework" #分别编译模拟器和真机的Framework xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build #拷贝framework到univer目录 cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework" "${UNIVERSAL_OUTPUT_FOLDER}" #合并framework,输出最终的framework到build目录 lipo -create -output "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/${TARGET_NAME}" #删除编译以后生成的无关的配置文件 dir_path="${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/" for file in ls $dir_path do if [[ ${file} =~ ".xcconfig" ]] then rm -f "${dir_path}/${file}" fi done #判断build文件夹是否存在,存在则删除 if [ -d "${SRCROOT}/build" ] then rm -rf "${SRCROOT}/build" fi rm -rf "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator" "${BUILD_DIR}/${CONFIGURATION}-iphoneos" #打开合并后的文件夹 open "${UNIVERSAL_OUTPUT_FOLDER}"
###3. 生成framework 在target中选择TestAggregate,build device选择Generic Device,而后 command + B
因为脚本末尾添加了open命令,编译结束以后会打开framework所在的文件夹
至此,SDK生成完毕,咱们须要写个demo工程验证一把 ###4. 验证framework 在workspace中新建一个demo工程,而后把TestSDK.framework引入
在viewController中调用SDK方法
从控制台的输出能够看出,咱们已经成功的调起TestSDK中的方法。
个人另一篇文章解决引用百度地图sdk冲突问题,其中介绍了如何查看framework的内部结构,你能够用里面的方法来查看咱们打出来的framework是不是通平台的包 ##总结