关于xcode8的建立依赖其他第三方库(cocoapods管理)的静态库framework

我们在编写 SDK 的时候, 有时候会用到一些常用组件, 比如 AFNetworking.
如果直接将AFNetworking编译进 SDK ,那么如果用户在使用你写的 SDK 的同时也使用了 AFNetworking,那么会出现”duplicate symbol OBJC_CLASS$_xxx”的问题.
如果自己重新写一个功能类似 AFNetworking 的组件,一来是很麻烦,二来像这种成熟的第三方库, 都是经过很多人测试过,多次修改 bug的,自己写的话,未必比得上,而且重复造轮子也是没有多大意义的.
接下来我们就来开始写一个简单的 SDK,并且使用 AFNetworking

*1. 创建工程*

选Cocoa Touch Framework,
创建静态库framework的第一步:
至于为何不选择 Cocoa Touch Static Library 是因为虽然后者也能建立静态库,但是最后得到的是一堆头文件加上一个 .a 文件,不容易部署, 而 Framework 则是把头文件和编译好的二进制文件打包为一个. framwork ,容易部署.
这里写图片描述

*2. 加入 AFNetworking*

既然要使用 AFNetworking ,自然要先引入, 这里我用 CocoaPods 来管理。
首先,你需要安装一个CocoaPods 插件,然后在终端操作。
终端打开工程,开始编辑下载AFNetworking
编辑下载的第三方内容

然后pod install,下载AFNetworking.

* 3. 编写 SDK*

拖入需要生成静态库的文件

拖入需要生成静态库的文件

在与工程同名文件内部将需要暴漏出来的头文件

编辑需要暴漏出的文件头部

*4. 配置*

在Targets->Build Phases ->Headers里面把需要暴漏的头文件拖拽到Public里面
这里写图片描述

接下来到 General 中设置需要支持的版本, Build Setting 中加入 armv7s

(注:此处为什么添加armv7s?
首先了解一下什么是ARM,ARM是微处理器,而armv6, armv7, armv7s是ARM CPU的不同指令集,

armv6设备:iPhone, iPhone2, iPhone 3G,第一代、第二代iPod Touch

armv7设备:iPhone 3GS,iPhone 4,iPhone 4S,iPad ,iPad 2,iPod Touch 3G,iPod Touch 4

armv7s设备:iPhone 5,iPad4

arm64设备:iPhone 5S,iPad Air,iphone6,iphone6plus,iPhone6s,iPhone6s Plus等

Xcode6更新后,默认不支持armv7s,也就是默认不会编译armv7s架构,虽然其处理器架构会向下兼容,但是无法进行相关优化操作。如果你提供的Framework默认不支持armv7s架构,但是使用者要支持armv7s架构,这时就会有冲突,Xcode无法构建代码原因是丢失某架构(armv7s架构)链接库的错误,所以为了避免冲突,Framework默认支持armv7s架构,使用过程中由使用者自行决定是否支持。)

这里写图片描述
将Build Active Architecture Only选项设为YES,导致其编译时只生成当前机器的框架,将其设置为NO,不知生成当前的机器框架,所有的都有。
这里写图片描述
1.选择工程文件>target第一项>Build Setting>搜索linking,然后几个需要设置的选项都显现出来,首先是Dead Code Stripping设置为NO,
2.然后将Link With Standard Libraries关闭,
3.最后将Mach-O Type设为Static Library,framework可以是动态库也可以是静态库,对于系统的framework是动态库,而用户制作的framework只能是静态库。动态库,上传appstore是不允许的。
这里写图片描述

Architectures:包含哪些架构指令,这里我们需要添加armv7s架构

Build Active Architecture Only:是否只为当前架构编译

Dead Code Stripping:是否从framework中删除未使用的代码

Link With Standard Libraries:是否链接苹果标准库

Mach-O Type:这里有好几种类型,我们需要选中static library

Other Linker Flags(本文没有用到,提醒):链接参数,如果framework中使用了category,最好加上ObjC、all_load,确保运行时系统会加载其中的category

Other C Flags(本文没有用到,提醒):额外的C语言链接参数,如果需要支持bitcode,需要加上-fembed-bitcode

接下来可以编译试试有没有什么错误和警告
如果没有,就可以进行下一步了

*5. 增加合并模拟器和真机的 Aggregate Target*

由于编译的时候,只会编译当前选中设备的版本,为了编译一份同时能够运行于真机和模拟器的 SDK ,我们再增加一个 target
这里写图片描述
在这个 Target 里面选择 Build Phase, 新建一个 Run Script
然后添加脚本代码:
这里写图片描述
脚本代码:

#!/bin/sh
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
WORKSPACE_NAME=${PROJECT_NAME}.xcworkspace
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 1. Build Device and Simulator versions
xcodebuild -workspace "${WORKSPACE_NAME}" -scheme "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphoneos ONLY_ACTIVE_ARCH=NO   BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -workspace "${WORKSPACE_NAME}" -scheme "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
fi
# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"

这里写图片描述

设置这个 Target 为 Release
这里写图片描述

然后编辑运行,这里选择真机运行会比较好。运行完成后会弹出合成好的framework文件夹路径,然后就可以拖入项目使用了。
运行完成自动打开的界面
也可以使用终端,对分别build生成的模拟器和真机的framework进行合并。

(终端代码:lipo -create 模拟器的二进制文件 真机的二进制文件 -output 生成新二进制文件的路径),然后再把真机的framework里面的二进制文件替换掉,接下来这个真机的framework就是合成的最终静态库文件。

*6. 试用。*

拖入的项目工程。
这里写图片描述
添加配置头文件路径
这里写图片描述这里写图片描述
这里,在使用终端将我们这个工程里面加入AFNetworking(这里不再赘述)。
运行,就可以使用了。
(之前自己碰到我的项目里面调用拖进去的framework,想要继承里面的一个类,在新建的时候subclass of竟然找不到里面的那个类。以为是哪里配置出现问题了。后来发现是项目编辑运行的时候就没有调用framework的那个类,可以在appdelegate里面讲我们的framework的写入所有的暴漏头文件的那个.h文件导入,那么工程就会预编译到,在新建的时候就会找得到你的framework里买呢所有的暴漏类的头文件了)。

*7. 总结*

架构

对于模拟器来说4s和5的模架构是i386的32位架构,5s至今是x86_64的64位架构。对于真机来说3GS~4s是armv7架构,5和5c是armv7s架构,5s至今是arm64架构

静态库

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

动态库

动态库:链接时不会拷贝至可执行文件中,运行时动态加载进内存,供程序调用,只加载一次,多个程序可以共用。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值