/*一、创建.a库*/
1.创建静态库工程 > 删除自动创建的.m实现文件及头文件里的信息 > 导入可能用到的系统库
2.目标工程 > Build Phases > Editor > add build Phases(是否公开头文件选项) > 设置公开访问的头文件(或在Target Membership中直接设置)
或
目标工程 > Build Phases > 点击左侧加号 > add build Phases(是否公开头文件选项) > 设置公开访问的头文件(或在Target Membership中直接设置)
3.将公开头文件导入到总的公用头文件中
4.选择sdk支持的系统版本
5.参数配置
Build Settings > Dead Code Stripping设置为NO
Build Settings > Strip Debug Symbol During Copy 全部设置为NO
Build Settings > Strip Style设置为Non-Global Symbols
Build Settings > Base SDK > Latest iOS(iOS 选择最新的)
6.设备 和 模拟器 下分别按下command + B进行编译, 编译成功后 > 在Product目录下 Show in Finder 查看
7.debug模式下运行生成 Debug-iphoneos Debug-iphonesimulator两个文件夹
release模式下运行生成 Release-iphoneos Release-iphonesimulator文件夹
区别
Debug和Release,在我看来主要是针对其面向的目标不同的而进行区分的。
Debug通常称为调试版本,通过一系列编译选项的配合,编译的结果通常包含调试信息,而且不做任何优化,以为开发人员提供强大的应用程序调试能力。
Release通常称为发布版本,是为用户使用的,一般客户不允许在发布版本上进行调试。所以不保存调试信息,同时,它往往进行了各种优化,以期达到代码最小和速度最优。为用户的使用提供便利
8.为了能在真机和模拟器上都能运行需要使用终端合并
cd到你想要保存合并后文件的目录下
合并 lipo -create 模拟器.a(路径) 真机.a(路径) -output 重命名.a
9.使用时,直接导入usr下的头文件和合并的.a文件
10.查看架构模式 lipo -info XXX.a i386 armv7 x86_64 arm64(下面有介绍)
arm7: 在最老的支持iOS7的设备上使用
arm7s: 在iPhone5和5C上使用
arm64: 运行于iPhone5S的64位 ARM 处理器 上
i386: 32位模拟器上使用
x86_64: 64为模拟器上使用
注意:向下兼容,arm7版本可以做arm7s上运行
需要在对应架构设备上运行,才能生成对应架构的包
11.建立工程验证
12.如果架构报错 Build Settings > BuildActiveArchitecture Only Debug改为NO
/*二、创建.framework库*/
Framework是资源的集合,将静态库和其头文件包含到一个结构中,让Xcode可以方便地把它纳入到你的项目中。本质也是一个bundle文件
//(1)使用bundle文件创建framework框架
1.创建一个Bundle工程
2.目标工程 > Build Phases > Editor > add build Phases(是否公开头文件选项) > 设置公开访问的头文件(或在Target Membership中直接设置)
或
目标工程 > Build Phases > 点击左侧加号 > add build Phases(是否公开头文件选项) > 设置公开访问的头文件(或在Target Membership中直接设置)
3.创建一个总的公共头文件 > 导入需要编译成库的文件 > 设置公开头文件 > 将公开头文件导入总的头文件中
4.选择framework支持的系统版本
5.配置参数更改
Build Settings > public header > /usr/$(PROJECT_NAME) (公共头文件在工程目录下)
Build Settings > Dead Code Stripping设置为NO
Build Settings > Strip Debug Symbol During Copy 全部设置为NO
Build Settings > Strip Style设置为Non-Global Symbols
Build Settings > Base SDK > Latest iOS(iOS 选择最新的)
Build Settings > Link With Standard Libraries = NO
Build Settings > Packaging > Wrapper Extension = framework.
Build Settings > Mach-O Type(frame 分静态库和动态库) = Static Library
对于Mach-O Type可能有两种情况:(1)选择 Static Library 打出来的是静态库;(2)选择 Relocatable Object File 打出来是动态库。
点击plist文件 > Bundle OS Type code改为FMWK
6.为了方便找到运行后生成的framework,我们提前在项目目录下创建一个目录 build,用来存放运行后生成的文件;
Build Settings > Per-configuration Build Products Path = $(SRCROOT)/build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7、模拟器和真机分别编译 > 合并
8.合并的是framework下的二进制文件
cd到你想要保存合并后文件的目录下
合并命令 lipo -create xxx.framework/xxx ooo.framework/ooo -output ooo。
9.将合并成功的二进制文件替换为framework中的二进制文件,如果没有用到info.plist文件,可以删除,避免在工程中发生冲突
10.验证 查看架构模式 lipo -info XXX.a
//(2)直接创建framework库
1、使用xcode直接创建frame工程
2、把需要编译的库导入到工程中
3、设置需要公开的头文件
Build Phases > Headers > 把文件拖动到指定位置(或在Target Membership选择)公开还是私有(Project为真正私有)
4.选择framework支持的系统版本
5、配置参数
Build Settings > public header > /usr/$(PROJECT_NAME) (公共头文件在工程目录下)
Build Settings > Dead Code Stripping设置为NO
Build Settings > Strip Debug Symbol During Copy 全部设置为NO
Build Settings > Strip Style设置为Non-Global Symbols
Build Settings > Base SDK > Latest iOS(iOS 选择最新的)
Build Settings > Link With Standard Libraries = NO
Build Settings > Mach-O Type(frame 分静态库和动态库) = Static Library
对于Mach-O Type可能有两种情况:(1)选择 Static Library 打出来的是静态库;(2)选择 Relocatable Object File 打出来是动态库。
6.为了方便找到运行后生成的framework,我们提前在项目目录下创建一个目录 build,用来存放运行后生成的文件
Build Settings > Per-configuration Build Products Path = $(SRCROOT)/build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7、模拟器和真机分别编译 > 合并
8.合并的是framework下的二进制文件
cd到你想要保存合并后文件的目录下
合并命令 lipo -create xxx.framework/xxx ooo.framework/ooo -output ooo。
9.将合并成功的二进制文件替换为framework中的二进制文件,如果没有用到info.plist文件,可以删除,避免在工程中发生冲突
10.验证
//(3)直接在工程中创建framework库
1.点击目标工程 > 点击下面左下角加号 > 创建framework
2.参数配置和合并流程同上(直接创建framework)
区别
为避免原工程编译错误
点击工程的目标文件 General > Embedded Binaries > 删除你创建的framework
/*注意事项*/
category的处理
category是项目开发中经常用到的,把category打包成静态库是没有问题的,但是在使用这个静态库时,
调用category中的方法时会发生找不到该方法的运行时错误(selector not recognized),
解决的办法是在使用静态库的工程中配置other linker flags的值为 -ObjC -all_load
对图片资源和UI界面xib或nib文件的处理
.a和.framework两种静态库,通常都是把需要用的到图片或者xib文件存放在一个bundle文件中,而该bundle文件的名字和.a或.framework的名字相同。
.a文件中无法存放图片或xib文件,很容易理解,但是.framework从本质上说也是一个bundle文件,为什么不把图片或者xib文件直接放在.framework中而单独再创建个bundle文件呢?
那是因为iOS系统不会去扫描.framework下的图片等资源文件,也不会在项目中显示,也就是说即使放在 .framework目录下,系统根本就不会去扫描,因此也无法发现使用。
/*开发UI控件库*/
在无法看到真实效果的情况下为iOS开发一个UI控件库是极其困难的
1.创建库工程,流程同上(第一节创建.a工程)也可创建framework (存在图片放入bundel中)
2.创建依赖库工程
3.关闭库工程
4.添加依赖库,将你的库工程xxxx.xcodeproj从Finder中拖到Xcode中依赖工程组下。
/*注意*/
你无法将同一工程在两个Xcode窗口中同时打开,如果你发现你无法在你的工程中导航到库工程的话,检查一下是否库工程在其他Xcode窗口中打开了。
5.连接到静态库
Build Phases > Link Binary With Libraries > 点击 “+” > Workspace组中选你的.a > 点击add
Build Phases > Target Dependencies > 选择你的库
6.导入库的头文件(头文件路径)编译库,编译依赖工程
7.报错问题解决
①删除添加的库,重新编译后导入
②确保编译路径相同
Build Settings > Per-configuration Build Products Path >
$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
像这样使用嵌套工程的好处是你可以对库本身做出修改,而不用离开示例工程,即使你同时改变两个地方的代码也一样。每次你编译工程,你都要检查是否将头文件的public/project关系设置正确。如果实例工程中缺失了任何需要的头文件,它都不能被编译。
/*在xcode中直接使用脚本生成framework*/
静态库构建过程中添加脚本来创建文件结构
1.打开静态库工程 > Build Phases > 左侧 “+” 按钮 > New Run Script Phases
这一步在build phases部分添加了一个新的面板,这允许你在构建时运行一个Bash脚本。你希望让脚本在build的过程中何时执行,就把这个面板拖动到列表中相对应的那一位置。对于该framework工程来说,脚本最后执行,因此你可以让它保留在默认的位置即可。
2.双击面板标题栏Run Script,重命名为Build Framework。
根据frame文件结构构件Framework,此时不包含二进制文件
#set –e确保脚本的任何地方执行失败,则整个脚本都执行失败。
set -e
#导出的文件路径
export FRAMEWORK_LOCN="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework"
# 创建真是文件路径
mkdir -p "${FRAMEWORK_LOCN}/Headers"
# 拷贝公共头文件到framework中
/bin/cp -a "${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}/" \
"${FRAMEWORK_LOCN}/Headers"
3.多架构(Multi-Architecture)编译
①点击目标工程 > 添加新目标 > Cross-Platform > Aggregate > next > 命名为Framework
为什么使用集合(Aggregate)目标来创建一个framework呢?为什么这么不直接?因为OS X对库的支持更好一些,事实上,Xcode直接为每一个OS X工程提供一个Cocoa Framework编译目标。基于此,你将使用集合编译目标,作为Bash脚本的连接串来创建神奇的framework目录结构。
你是不是开始觉得这里的方法有些愚蠢了?
为了确保每当这个新的framework目标被创建时,静态链接库都会被编译,你需要往静态库目标中添加依赖
②选择Framework目标 > Build Phases > Target Dependencies > 点击 + > 加入你的库
在库工程中选择Framework目标,在Build Phases中添加一个依赖。展开Target Dependencies面板,点击 + 按钮选择RWUIControls静态库。
③选择Framework目标 > Build Phases > 左侧 “+” 按钮 > New Run Script Phases > 命名MultiPlatform Build
④写入编译文件
#set –e确保脚本的任何地方执行失败,则整个脚本都执行失败。
set -e
#标示 如果已经插入脚本 退出
if [ -n "$IYQ_MULTIPLATFORM_BUILD_IN_PROGRESS" ]; then
exit 0
fi
export IYQ_MULTIPLATFORM_BUILD_IN_PROGRESS=1
# 自定义变量
IYQ_FRAMEWORK_NAME=${PROJECT_NAME}
IYQ_INPUT_STATIC_LIB="lib${PROJECT_NAME}.a"
IYQ_FRAMEWORK_LOCATION="${BUILT_PRODUCTS_DIR}/${IYQ_FRAMEWORK_NAME}.framework"
#构建静态库 传参 "${1}"
function build_static_library {
# 重新构建库
xcrun xcodebuild -project "${PROJECT_FILE_PATH}" \
-target "${TARGET_NAME}" \
-configuration "${CONFIGURATION}" \
-sdk "${1}" \
ONLY_ACTIVE_ARCH=NO \
BUILD_DIR="${BUILD_DIR}" \
OBJROOT="${OBJROOT}" \
BUILD_ROOT="${BUILD_ROOT}" \
SYMROOT="${SYMROOT}" $ACTION
}
#合并
function make_fat_library {
xcrun lipo -create "${1}" "${2}" -output "${3}"
}
# 1 正则判断 真机还是模拟器 (iphoneos/iphonesimulator)
if [[ "$SDK_NAME" =~ ([A-Za-z]+) ]]; then
IYQ_SDK_PLATFORM=${BASH_REMATCH[1]}
else
echo "Could not find platform name from SDK_NAME: $SDK_NAME"
exit 1
fi
# 2 SDK版本
if [[ "$SDK_NAME" =~ ([0-9]+.*$) ]]; then
IYQ_SDK_VERSION=${BASH_REMATCH[1]}
else
echo "Could not find sdk version from SDK_NAME: $SDK_NAME"
exit 1
fi
# 3 其他平台判断 如果 则 否则
if [ "$IYQ_SDK_PLATFORM" == "iphoneos" ]; then
IYQ_OTHER_PLATFORM=iphonesimulator
else
IYQ_OTHER_PLATFORM=iphoneos
fi
# 4 其他平台路径
if [[ "$BUILT_PRODUCTS_DIR" =~ (.*)$IYQ_SDK_PLATFORM$ ]]; then
IYQ_OTHER_BUILT_PRODUCTS_DIR="${BASH_REMATCH[1]}${IYQ_OTHER_PLATFORM}"
else
echo "Could not find other platform build directory."
exit 1
fi
#调用上面构建函数 如果当前运行的是真机则构建模拟器
build_static_library "${IYQ_OTHER_PLATFORM}${IYQ_SDK_VERSION}"
# 如果你现在正在为模拟器编译,那么Xcode会默认只在该系统对应的结构下编译,例如i386 或 x86_64。为了在这两个结构下都进行编译,这里调用了build_static_library,基于iphonesimulator SDK重新编译,确保这两个结构都进行了编译。
if [ "$RW_SDK_PLATFORM" == "iphonesimulator" ]; then
build_static_library "${SDK_NAME}"
fi
# 合并库
make_fat_library "${BUILT_PRODUCTS_DIR}/${IYQ_INPUT_STATIC_LIB}" \
"${IYQ_OTHER_BUILT_PRODUCTS_DIR}/${IYQ_INPUT_STATIC_LIB}" \
"${IYQ_FRAMEWORK_LOCATION}/${IYQ_FRAMEWORK_NAME}"
# 确保文件存在 相当于-dpR,保持文件的连接(d),保持原文件的属性(p)并作递归处理(R)
cp -a "${IYQ_FRAMEWORK_LOCATION}/${IYQ_FRAMEWORK_NAME}" \
"${IYQ_OTHER_BUILT_PRODUCTS_DIR}/${IYQ_FRAMEWORK_NAME}.framework/${IYQ_FRAMEWORK_NAME}"
# 拷贝到指定目录下
ditto "${IYQ_FRAMEWORK_LOCATION}" "${SRCROOT}/BuildFramework/${IYQ_FRAMEWORK_NAME}.framework"
⑤show in Finder 查看编译的库 > 打开终端验证 > 创建工程验证
$ cd XXXX.framework
$ XXX.framework xcrun lipo -info XXXX
iOS app需要在许多不同的CPU架构下运行:
arm7: 在最老的支持iOS7的设备上使用
arm7s: 在iPhone5和5C上使用
arm64: 运行于iPhone5S的64位 ARM 处理器 上
i386: 32位模拟器上使用
x86_64: 64为模拟器上使用
每个CPU架构都需要不同的二进制数据,当你编译一个应用时,无论你目前正在使用那种架构,Xcode都会正确地依照对应的架构编译。例如,如果你想跑在虚拟机上,Xcode只会编译i386版本(或者是64位机的x86_64版本)。
/*sdk存在图片等资源文件的情况*/
使用bundle文件封装图片、xib等资源,以下流程是使用多目标编译,单独创建bundle文件类似
1.选择库工程目标文件 > 左下角 + > maxOS > Bundle > 自定义命名IYQResources
2.配置几个编译设置,因为你正在创建一个在iOS上使用的bundle,这与默认的OS X不同。
选择Bundle目标文件 > Build Settings > Base SDK > Latest iOS (iOS 10.2选择最新)
Build Settings > Product Name > ${TARGET_NAME}替换为你的工程名XXXX(直接写工程名就好)
3.选择Framework目标 > Build Phases > Target Dependencies > 点击 + > 加入你的Bundle
4.默认情况下,有两种resolutions(分辨率)的图片可以产生一些有趣的现象。
例如,当你导入一个retina@2x版本的图片时,普通版的和Retina版的将会合并成一个多resolution的TIFF(标签图像文件格式,Tagged Image File Format)。
Build Settings > COMBINE_HIDPI_IMAGES设置为NO
5.如何添加资源文件
①直接拖入
②选择图片或其他资源文件 > Target Membership > 选择bundle目标
6.如果想把你的编译包copy到指定位置,在脚本后面加入如下代码
# 拷贝bundle到指定目录下
ditto "${BUILT_PRODUCTS_DIR}/${IYQ_FRAMEWORK_NAME}.bundle" \
"${SRCROOT}/BuildFramework/${IYQ_FRAMEWORK_NAME}.bundle"
7.如何引用:UIImage *image = [UIImage imageNamed:@"XXXX.bundle/图片名"];
创建自己的sdk(含编译脚本)
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 总览 一、创建自己的SDK - .a静态库 这篇教程将只使用一小部分Objective-C代码,本文主要讲解从开始...