xcode 8 /iOS10下静态库和动态库的区别 && framework的制做

这里输入引用文本本文记录一下,在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是不是通平台的包 ##总结

  1. 开发是一个不断踩坑和填坑的过程,制做framework在iOS开发中是一个比较小众的需求,我会持续的把我遇到的蛋疼的事儿记录下来,以供来着参考,有更好的方法也欢迎讨论
  2. 在SDK制做过程当中用workspace的方法管理project是一个颇有效率的方法,这是咱们团队的adams总结使用的,经过这种方法能够源码project和demo project放在一块儿,能够同时在一个地方搞定两件事:SDK开发和framework集成
  3. 学会制做framework仅仅是万里长征第一步,framework给到第三方集成过程当中会遇到各类麻烦,这就须要不断的总结和沉淀
  4. 本文目前为止制做的是动态的framework,若是你的需求是作一个静态的framework,变化很简单,你只须要改变building settings -- > Mach-o type为static便可
  5. 默认的iOS develop target是当前最新版本的,你的framework须要兼容低版本的话就须要在build settings --> development --> iOS develop target中设置你的目标版本
相关文章
相关标签/搜索