1.framework开始前的 理论
1).初衷
开始的理由千千万,但殊途同归.
(1) 提供给公司外部的人员使用, 不希望暴露内部"高大上"的实现
(2) 公司内部多个项目公用资源, 使用方便
(3) 模块化、分工合作, 架构组完成基础的实现, 功能开发工程师只需要关注功能实现, 不需要关注底层实现
(4) 提高编译速度,减少少量的改动引起的大量重复的编译
......
2).动态库,静态库
动态库存在形式: .framework, .dylib, .tbd
动态库是引用关系,编译时不会被拷贝到程序中,程序运行时 由系统动态加载
静态库存在形式: .a 和 .framework
静态库编译时会被完整拷贝一份到目标程序中
动态库与静态库详细的区别 参考:
https://my.oschina.net/shoutan/blog/786636
2.创建framework
1).创建工程
模板选择Cocoa Touch Framework
2).编写自定义代码
对需要共享的内容分模块添加
!建库时不得不注意的就是 swift的访问级别
Swift 提供了三种访问级别。这些访问级别相对于源文件中定义的实体,同时也相对于这些源文件所属的模块。
其中,函数的访问级别需要根据该函数的参数类型访问级别、返回类型访问级别得出。如果根据参数类型和返回类型得出的函数访问级别不符合上下文,那么就需要明确的申明该函数的访问级别。
代码中的所有实体,如果你不明确的定义其访问级别,那么它们默认为internal级别, 所以, 只是在一个工程中使用, 可以不用声明访问类型, 该工程 均可访问。
swift 三个等级的访问控制权限,可以简单的通过下面的规则来进行选择:
- Public: 对 App 或其他 framework 可见。
- Internal: 对该 framework 可见
- Fileprivate: 对该编译文件可以见
- Private: 对该类可见
具体参考文档: http://wiki.jikexueyuan.com/project/swift/
3.编译 真机 / 模拟器 的 包
1).编译
对工程进行编译(command + B)
, 找到project->products->选中EKWBaseUIKit.framework->Show In Finder
, 如下图:
2).查看库文件
可以看到生成的 真机和模拟器下的两个包文件(当前设置的模式为release模式, 所以为release模式下的两个包文件), 如下图:
3). 查看库文件支持框架
在终端通过lipo -info 静态库名字
可以查看动态库支持的架构, 如下:
可以看到当前支持的框架包含: 有armv7
和arm64
目前iOS设备包含的架构:
模拟器:iPhone4s-iPnone5:i386; iPhone5s-iPhone7 Plus:x86_64
真机: iPhone3gs-iPhone4s:armv7; iPhone5-iPhone5c:armv7s; iPhone5s-iPhone7Plus:arm64
我们需要把对应的framework引入工程中即可使用, 但是我们平时可能用到真机调试,也可能使用模拟器调试,来回切换framework会很繁琐,所以一般使用终端把支持真机和模拟器的framework合并成一个framework(fat版)
命令格式:lipo -create 第一个.framewor下的esec文件的绝对路径 第二个.framework下的esec文件的绝对路径 -output 最终的.framework文件路径
操作如下:
4.使用脚本编译
如上的单调频繁的操作可能会让你感觉累觉不爱,xcode目前支持的脚本编译,包治百病
1).创建Aggregate
targets点击左下角 “+”, 添加Aggregate
2). 添加脚本文件
Run Script 中可以放入待执行的脚本文件, 也可以放入待执行的脚本, 但是放入待执行脚本时, 遇到过文件权限的问题(涉及pod管理的framework), 所以此处推荐使用脚本文件的路径代替脚本
3).使用到的脚本如下:
#!/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}"
4). 脚本以及生成的framework位置
5).检测 framework支持的类型
使用lipo -info ...
查看合成的framework支持的类型 包含:i386, Plus:x86_64, armv7, arm64
6.framework制作过程中的坑
1. Module
在工程中, 我们可以通过桥接文件引入需要使用的OC或者C相关的, 但是swift动态库中, 是不能使用桥接文件的,比如: 需要使用CommonCrypto
里面的内容, 在工程中可以直接导入CommonCrypto
使用, 在库中则不能使用
这个问题可以使用模块化解决:
1).创建一个模块化文件, 并加入对应模块
module CCommonCrypto [system] {
header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/CommonCrypto/CommonCrypto.h"
export *
}
2). 模块化的使用
在需要使用的文件中 输入 import CCommonCrypto
即可使用相关内容
3)参考文档
https://spin.atomicobject.com/2015/02/23/c-libraries-swift/ 英文原文
http://blog.csdn.net/quentingui/article/details/44115285 翻译
http://www.ethanwhy.com/2016/12/17/swift-framework-call-objective-c-c-language/
https://stackoverflow.com/questions/25248598/importing-commoncrypto-in-a-swift-framework/37125785#37125785
https://github.com/onmyway133/arcane
更新(2018-10-12):
xcode10中, swift增加了对 CommonCrypto
的支持,在需要使用的 CommonCrypto
的swift库中,不需要Module的方式,直接添加使用即可,如下:
import CommonCrypto
自己封装的库也可能使用了pod管理,基于workspace的库的制作将在接下来的文章中谈到...
以上仅是个人使用总结,欢迎批评指正补充~~~~~~~