修改于:2017.1.24

1.什么是库?

库是程序代码的集合,是共享程序代码的一种方式

2.根据源代码的公开情况,库可以分为2种类型

a.开源库

公开源代码,能看到具体实现 ,比如SDWebImage、AFNetworking

b.闭源库

不公开源代码,是经过编译后的二进制文件,看不到具体实现。主要分为:静态库、动态库

3.静态库和动态库的存在形式

静态库:以.a 和 .framework为文件后缀名。
动态库:以.tbd(之前叫.dylib) 和 .framework 为文件后缀名。

.a是纯二进制文件,.a文件不能单独使用,至少要有.h文件配合,而.framework除了二进制文件外,还包含一些资源文件(头文件,plist等),由于自身包含了头文件,所以.framework可以单独使用。

.a和.framework两种静态库,通常都是把需要用的到图片或者xib文件存放在一个bundle文件中,而该bundle文件的名字和.a或.framework的名字相同。

ios 8 以后苹果放开了动态库。

4.静态库和动态库在使用上的区别

静态库:链接时会被完整的复制到可执行文件中,被多次使用就有多份拷贝。
动态库:链接时不复制,程序运行时由系统动态加载到内存,系统只加载一次,多个程序共用(如系统的UIKit.framework等),节省内存。

5.创建静态库可能出于以下几个理由:

1.你想将工具类代码或者第三方插件快捷的分享给其他人而无需拷贝大量文件。

2.你想让一些通用代码处于自己的掌控之下,以便于修复和升级。

3.你想将库共享给其他人,但不想让他们看到你的源代码。

4.比如很老的框架使用的是MRC环境下面的框架,那么我们只需要将其打包成静态库就可以了,这样就不用担心是不是ARC环境了。

6、iOS设备架构

模拟器:
iPhone4s-iPnone5:i386
iPhone5s-iPhone7 Plus:x86_64

真机:
iPhone3gs-iPhone4s:     armv7
iPhone5-iPhone5c:        armv7s
iPhone5s-iPhone7 Plus: arm64

支持armv7的静态库可以在armv7s上正常运行。

Xcode创建静态库详解(Cocoa Touch Static Library)(本人使用的是Version 6.3)

一、创建静态库文件(.a 文件)

打开Xcode, 选择File ----> New ---> Project。 

选择iOS ----> Framework & Library ---> Cocoa Touch Static Library。

点击Next。按照流程一步一步的创建工程。

注意静态库文件的版本(4种)

1.真机-Debug版本

2.真机-Release版本

3.模拟器-Debug版本

4.模拟器-Release版本

就是在build configuration 里面进行调整一下debug和release,然后分别在真机和模拟器上面进行编译。

结果如下图:

调试版本(Debug版本) VS 发布版本(Release版本)

--------------------------------------------------------------------------------

- 调试版本会包含完整的符号信息,以方便调试

- 调试版本不会对代码进行优化

- 发布版本不会包含完整的符号信息

- 发布版本的执行代码是进行过优化的

- 发布版本的大小会比调试版本的略小

- 在执行速度方面,调试版本会更快些,但不意味着会有显著的提升

所以我们建议在产品即将上线的时候要进行如下图的调整:

二、应用静态库文件(.a 文件)

1.想让静态库文件給别人使用,需要将头文件暴露給别人。按着下面的步骤将头文件添加进来。

再点击libstatic.a右击show In Finder 就可以查看如下图:

2.然后将静态库拖进项目中。就能利用头文件了

 

3.因为无论是模拟器还是真机都有不同的架构。所以经常会出现如下找不到某个架构的错误

为了解决各个机型的模拟器都能用可以有2种方法:

1.合并各个静态库(在终端中执行如下操作)

$ cd /Users/XQ/Library/Developer/Xcode/DerivedData/static-bdsgvzfqigaspiaeivnhmmygrhgj/Build/Products/Release-iphonesimulator5s

$ lipo -info libstatic.a

Architectures in the fat file: libstatic.a are: i386 x86_64

$ cd /Users/XQ/Library/Developer/Xcode/DerivedData/static-bdsgvzfqigaspiaeivnhmmygrhgj/Build/Products/Release-iphonesimulator6

$ lipo -info libstatic.a

Architectures in the fat file: libstatic.a are: i386 x86_64

1》.我们可以cd到.a文件所在文件夹的当前目录

2》.再执行 lipo -info 静态库.a文件

这样就可以查询该静态库支持的架构是什么。

回到.a文件所在文件夹所在的文件夹目录:cd ..

$ cd ..

$ pwd

/Users/XQ/Library/Developer/Xcode/DerivedData/static-bdsgvzfqigaspiaeivnhmmygrhgj/Build/Products

合并2个静态库

$ cd ..

$ pwd

/Users/XQ/Library/Developer/Xcode/DerivedData/static-bdsgvzfqigaspiaeivnhmmygrhgj/Build/Products

$ lipo -create Release-iphonesimulator5s/libstatic.a  Release-iphonesimulator6/libstatic.a -output lib.a

fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: Release-iphonesimulator5s/libstatic.a and Release-iphonesimulator6/libstatic.a have the same architectures (i386) and can't be in the same fat output file

由于2个静态库都含有相同的架构,所以出现错误,因为我们合并的是Release-iphonesimulator6和Release-iphonesimulator5s之间的版本,都是模拟器的。其实我们在制作静态库的时候,无论是在模拟器还是真机的时候,设置Build Active Architecture Only为no的话,一次打包,如果是模拟器就会适用所有机型的模拟器,如果是真机就会适用所有机型的真机。实际上我们通常合并的是模拟器和真机的静态库。模拟器和真机版本合并完后,我们姑且称之为“合并版本”吧,那么分别会有debug合并版本和release合并版本,通常我们会在上线前将debug合并版本换成relaese合并版本(当然release合并版本会支持模拟器和真机)。目前还没找到release合并版本和debug合并版本合并的方法(估计有,但是不会是这么简单的合并)。

合并模拟器和真机的静态库,步骤如下:

合并前:

$ cd /Users/XQ/Library/Developer/Xcode/DerivedData/static-bdsgvzfqigaspiaeivnhmmygrhgj/Build/Products/Debug-iphonesimulator

$ lipo -info libstatic.a

input file libstatic.a is not a fat file

Non-fat file: libstatic.a is architecture: x86_64

$ cd /Users/XQ/Library/Developer/Xcode/DerivedData/static-bdsgvzfqigaspiaeivnhmmygrhgj/Build/Products/Debug-iphoneos

$ lipo -info libstatic.a

Architectures in the fat file: libstatic.a are: armv7 arm64

$ cd ..

$ pwd

/Users/XQ/Library/Developer/Xcode/DerivedData/static-bdsgvzfqigaspiaeivnhmmygrhgj/Build/Products

$ lipo -create Debug-iphonesimulator/libstatic.a Debug-iphoneos/libstatic.a -output lib.a

合并后:

合并后的lib.a同时支持:armv7 x86_64 arm64 架构。(可以看出在制作模拟器的静态库的时候并没有设置Build Active Architecture Only为no)

$ cd /Users/XQ/Library/Developer/Xcode/DerivedData/static-bdsgvzfqigaspiaeivnhmmygrhgj/Build/Products

$ pwd

/Users/XQ/Library/Developer/Xcode/DerivedData/static-bdsgvzfqigaspiaeivnhmmygrhgj/Build/Products

$ lipo -info lib.a

Architectures in the fat file: lib.a are: armv7 x86_64 arm64

2.可以通过配置

小结一下:

1.编译静态库:项目->Build Phases->Copy File->添加头文件

2.模拟器编译时,挑选高版本(向下兼容,低版本不能在高版本运行)

3.静态库分真机版本和模拟器版本(必须在对应的版本运行)

4.合并真机版本和模拟器版本(常用)

lipo -create 真机.a 模拟器.a -output 结果.a

合并版本更大,开始时使用方便(所以可以开发时使用合并版本,发布时,使用真机版本)

5.release版本和debug版本:

debug版本:调试版本,没有任何优化,也就是说各种错误信息,都将抛出和检测,相对来说性能低一点,但是方便调试

release版本:发布版本,进行了优化,执行效率更高

提醒:实际开发当中,项目完成后,在debug版本上没有问题了,一定要去release版本上调试一下,否则也许可能发生一些bug。

三、调试静态库文件(.a 文件)

因为静态库也是需要不断的开发,调试,最终才能完美,所以我们应该是不断的开发,不断的调试,那么像上面的那种方式直接建立一个静态库项目就很麻烦,所以我们应该是在某一个项目中添加一个静态库文件,那么就可以做到不断开发,不断调试。

1.添加静态库target:项目->General->左下角+->添加静态库(StaticLib)

2.在StaticLib文件夹内就可以就行开发静态库

3.项目引入静态库:项目->General->Linked Frameworks and Libraries->添加静态库

4.导出静态库:选择左上角房子->同之前导出方式(也就是分别在模拟器和真机上面进行编译)。

(注意:如果是动态库的话,上面的Embedded Binaries 也要导入相应的库 )

总体思路是我们在项目中新添加静态库target,然后在项目中导入静态库文件,这个时候scheme选中原本项目(注意是项目),进行编译看是否通过。所以我们可以通过这样的方法进行调试静态库,如果真的调试到没有错误的时候,可以将scheme处选择成小房子(静态库),然后编译就可以生成相应的静态库。这样我们就可以边开发边经行静态库的调试。

2017.1.24增加脚本打包方法如下:

建立一个Aggregate target  (使用Xcode Version 8.2.1 (8C1002))

从上面可以看出来,因为.a库是会生成模拟器和真机两个不同的包的,下面尝试利用脚本来合成。

1、我们先按照上面的步骤流程建立一个.a静态库(单独的静态库)yooweiSDKTest

2、建立一个Aggregate target,在Aggregate里面执行脚本。

3、新建一个运行脚本

4、接下来我们就可以在Run Script里写我们的脚本了

把下面的脚本复制到Run Script里面:

if [ "${ACTION}" = "build" ]
then #要build的target名
target_Name=${PROJECT_NAME}
echo "target_Name=${target_Name}" #build之后的文件夹路径
build_DIR=${SRCROOT}/build
echo "build_DIR=${build_DIR}" #真机build生成的头文件的文件夹路径
DEVICE_DIR_INCLUDE=${build_DIR}/Release-iphoneos/include/${PROJECT_NAME}
echo "DEVICE_DIR_INCLUDE=${DEVICE_DIR_INCLUDE}" #真机build生成的.a文件路径
DEVICE_DIR_A=${build_DIR}/Release-iphoneos/lib${PROJECT_NAME}.a
echo "DEVICE_DIR_A=${DEVICE_DIR_A}" #模拟器build生成的.a文件路径
SIMULATOR_DIR_A=${build_DIR}/Release-iphonesimulator/lib${PROJECT_NAME}.a
echo "SIMULATOR_DIR_A=${SIMULATOR_DIR_A}" #目标文件夹路径
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}
echo "INSTALL_DIR=${INSTALL_DIR}" #目标头文件文件夹路径
INSTALL_DIR_Headers=${SRCROOT}/Products/${PROJECT_NAME}/Headers
echo "INSTALL_DIR_Headers=${INSTALL_DIR_Headers}" #目标.a路径
INSTALL_DIR_A=${SRCROOT}/Products/${PROJECT_NAME}/lib${PROJECT_NAME}.a
echo "INSTALL_DIR_A=${INSTALL_DIR_A}" #判断build文件夹是否存在,存在则删除
if [ -d "${build_DIR}" ]
then
rm -rf "${build_DIR}"
fi #判断目标文件夹是否存在,存在则删除该文件夹
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
#创建目标文件夹
mkdir -p "${INSTALL_DIR}" #build之前clean一下
xcodebuild -target ${target_Name} clean #模拟器build
xcodebuild -target ${target_Name} -configuration Release -sdk iphonesimulator #真机build
xcodebuild -target ${target_Name} -configuration Release -sdk iphoneos #复制头文件到目标文件夹
cp -R "${DEVICE_DIR_INCLUDE}" "${INSTALL_DIR_Headers}" #合成模拟器和真机.a包
lipo -create "${DEVICE_DIR_A}" "${SIMULATOR_DIR_A}" -output "${INSTALL_DIR_A}" #打开目标文件夹
open "${INSTALL_DIR}" fi

5、运行程序

注意scheme选择yooweiShell,之后正常的run就行了。编译成功以后,如下:

我们这个脚本,将合成后的.a库和头文件都按照我们想要的方式放好了。其他工程要用这个SDK的话,既可以直接拉MySDK文件夹过去就可以了。如果你想要其他的放法,比如不要Headers文件夹,那就,改一下脚本就可以了。

6、验证

在终端使用命令 “lipo -info .a文件路径”查看

$ lipo -info /Users/galahad/Downloads/yooweiSDKTest/Products/yooweiSDKTest/libyooweiSDKTest.a

Architectures in the fat file: /Users/galahad/Downloads/yooweiSDKTest/Products/yooweiSDKTest/libyooweiSDKTest.a are: armv7 i386 x86_64 arm64

说明成功了

7、脚本解释

本代码中用到的核心命令:xcodebuild  ,主要用来编译Xcode的工程。可以在终端中输入xcodebuild -h来查看命令的详情

介绍一下本脚本中用到的几个参数:

    • clean
      clean一下工程
    • -configuration Release
      使用Release方式编译,还可以使用Debug
    • -sdk iphoneos
      真机编译,还可以使用-sdk iphonesimulator模拟器编译
    • cp "源文件路径" "目标文件路径"
      复制"源文件路径"的文件到 "目标文件路径"
    • lipo -create "模拟器.a文件路径" "真机.a文件路径" -output "目标.a文件路径"
      将模拟器和真机的.a包合成。

用到的一些shell脚本基础命令:

(1)echo "想要查看的日志或重要东西" ,echo相当于OC中的NSLog。运行脚本后,可以在这里找到log

(2)变量名=变量值  

赋值命令。比如将"CrazyStone"赋值给MyName变量

MyName=CrazyStone

(3)${变量名}  

取出变量名的内容。比如:取出变量MyName中的内容

${MyName}

(4)判断语句

if [ 条件语句 ]then
...
fi

条件语句为真就执行then后面的语句,不成立就结束判断语句
本脚本中用到的判断语句:
[ -d "文件夹路径" ] :判断是否为文件夹

脚本结构解释

看完上面,我想你再看一下代码应该就能理解脚本,然后可以做一些简单的改动了。下面再介绍一下脚本的结构。

if [ "${ACTION}" = "build" ]
then
#我们的大部分脚本代码
fi

执行脚本的时候做个判断,在Xcode里面build这个工程的时候就执行then后面的脚本

#要build的target名
target_Name=${PROJECT_NAME}
echo "target_Name=${target_Name}"

变量target_Name是我们要编译的target的名字,在这里指的是工程的名字${PROJECT_NAME},也就是yooweiSDKTest
顺便说一下,ACTIONPROJECT_NAME都是Xcode里面定义的,这是在Xcode里面写脚本的一个好处。

#build之后的文件夹路径
build_DIR=${SRCROOT}/build
echo "build_DIR=${build_DIR}" #真机build生成的头文件的文件夹路径
DEVICE_DIR_INCLUDE=${build_DIR}/Release-iphoneos/include/${PROJECT_NAME}
echo "DEVICE_DIR_INCLUDE=${DEVICE_DIR_INCLUDE}" #真机build生成的.a文件路径
DEVICE_DIR_A=${build_DIR}/Release-iphoneos/lib${PROJECT_NAME}.a
echo "DEVICE_DIR_A=${DEVICE_DIR_A}" #模拟器build生成的.a文件路径
SIMULATOR_DIR_A=${build_DIR}/Release-iphonesimulator/lib${PROJECT_NAME}.a
echo "SIMULATOR_DIR_A=${SIMULATOR_DIR_A}"

这里是定义的build之后各个文件的路径。我们执行了xcodebuild命令之后,会在工程目录生成一个build文件夹,里面有build之后生成的文件。打开Finder看看就知道各个文件的路径了。

build目录的位置
#目标文件夹路径
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}
echo "INSTALL_DIR=${INSTALL_DIR}" #目标头文件文件夹路径
INSTALL_DIR_Headers=${SRCROOT}/Products/${PROJECT_NAME}/Headers
echo "INSTALL_DIR_Headers=${INSTALL_DIR_Headers}" #目标.a路径
INSTALL_DIR_A=${SRCROOT}/Products/${PROJECT_NAME}/lib${PROJECT_NAME}.a
echo "INSTALL_DIR_A=${INSTALL_DIR_A}"

这里就是定义目标变量的路径了。你想把文件放在哪里?在这里定义咯。${SRCROOT}表示工程的根目录。用了这么久的Xcode,这个有用过吧(全局头文件配置过吧?)?

#判断build文件夹是否存在,存在则删除
if [ -d "${build_DIR}" ]
then
rm -rf "${build_DIR}"
fi #判断目标文件夹是否存在,存在则删除该文件夹
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
#创建目标文件夹
mkdir -p "${INSTALL_DIR}"

这里就是文件的操作了。如果有这两个文件夹,就删除掉。为什么?为了保证我们工程的纯净啊。

#build之前clean一下
xcodebuild -target ${target_Name} clean #模拟器build
xcodebuild -target ${target_Name} -configuration Release -sdk iphonesimulator #真机build
xcodebuild -target ${target_Name} -configuration Release -sdk iphoneos

这里就跟平常操作一样了。先clean一下工程,然后模拟器编译一次,真机编译一次。

#复制头文件到目标文件夹
cp -R "${DEVICE_DIR_INCLUDE}" "${INSTALL_DIR_Headers}" #合成模拟器和真机.a包
lipo -create "${DEVICE_DIR_A}" "${SIMULATOR_DIR_A}" -output "${INSTALL_DIR_A}"

关键代码。拷贝头文件到我们的目标位置去。合成.a包。大功告成。

#打开目标文件夹
open "${INSTALL_DIR}"

最后,打开文件夹。检查一下文件是否真正生成了。

参考文章:http://www.jianshu.com/p/9cf90b9537fd

iOS静态库.a总结(2017.1.24增加脚本打包方法)的更多相关文章

  1. iOS - 静态库的创建与使用

    在日常项目开发中,不论是为了两个公司项目上的业务交流还是为了减少项目的编译时间,有的时候我们会把项目中的私密内容打包成静态库,或者是把项目中变动较少一部分打包成静态库以便提高编译效率,那么下面我们就来 ...

  2. IOS静态库

    如何在Xcode中创建C++静态库 http://jingyan.baidu.com/article/03b2f78c111fca5ea237ae26.html iOS 如何创建和使用静态库 http ...

  3. ios 静态库冲突的解决办法

    最近在做一个 iOS 的 cocos2d-x 项目接入新浪微博 SDK 的时候被“坑”了,最后终于顺利的解决了.发现网上也有不少人遇到一样的问题,但是能找到的数量有限的解决办法写得都不详细,很难让人理 ...

  4. [IOS 静态库]

    http://www.2cto.com/kf/201402/276718.html 一.什么是库? 库是共享程序代码的方式,一般分为静态库和动态库. 二.静态库与动态库的区别? 静态库:链接时完整地拷 ...

  5. iOS静态库.a文件制作和导入使用

    iOS静态库.a文件制作: 1.新建Cocoa Touch Static Library工程 新建工程 - 选择iOS-FrameWork&Libary,选择 Cocoa Touch Stat ...

  6. 【转】iOS静态库 【.a 和framework】【超详细】

    原文网址:https://my.oschina.net/kaqijiang/blog/649632 一.什么是库? 库是共享程序代码的方式. 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存 ...

  7. IOS静态库和Framework区别

    一.什么是库? 库是共享程序代码的方式,一般分为静态库和动态库. 二.静态库与动态库的区别? 静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝. 动态库:链接时不复制,程序运行时由系 ...

  8. iOS 静态库,动态库与 Framework 浅析

    静态库与动态库的区别 首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用. 什么时候我们会用到库呢?一种情况是某些代码需要给别人使用,但是我们不希望别人 ...

  9. iOS静态库 ---iOS-Apple苹果官方文档翻译

    iOS静态库 ---iOS-Apple苹果官方文档翻译 •什么是库? 库是共享程序代码的方式,一般分为静态库和动态库.静态库与动态库的区别? 静态库:链接时完整地拷贝至可执行文件中,被多次使⽤用就为什 ...

随机推荐

  1. Python自动化之迭代器不能在迭代的时候更改值

    除列表外的其他序列都是不可变的, 所以危险就发生在这里. 一个序列的迭代器只是记录你当前到达第多少个元素, 所以如果你在迭代时改变了元素, 更新会立即反映到你所迭代的条目上.在迭代字典的 key 时, ...

  2. 使用.Net Core MVC创建Web API

    创建.Net Core MVC 打开appsettings.json文件,添加数据库连接 { "Logging": { "LogLevel": { " ...

  3. #leetcode刷题之路44-通配符匹配

    给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配.'?' 可以匹配任何单个字符.'*' 可以匹配任意字符串(包括空字符串).两个字符串完全匹配才算匹配成 ...

  4. PHP中const,static,public,private,protected的区别

    原文地址:http://small.aiweimeng.top/index.php/archives/54.html const: 定义常量,一般定义后不可改变static: 静态,类名可以访问pub ...

  5. C语言——常用标准输入输出函数 scanf(), printf(), gets(), puts(), getchar(), putchar(); 字符串拷贝函数 strcpy(), strncpy(), strchr(), strstr()函数用法特点

    1 首先介绍几个常用到的转义符 (1)     换行符“\n”, ASCII值为10: (2)     回车符“\r”, ASCII值为13: (3)     水平制表符“\t”, ASCII值为 9 ...

  6. C++快速开发样本工程的建立--简介

    背景 在开发项目过程中,一些功能库能反复被写被用,可以写成库被重用: 但是行业业务也随着换项目,每次重新写一次,如果把一些功能业务和框架绑定,配置绑定,只需要添加,修改,增加业务功能,就可以搭建C++ ...

  7. Scala_修饰符

    Scala访问修饰符和Java基本一样,分别有private.protected.public.默认缺省情况下,Scala对象的访问级别是public. 私有成员:用private关键字修饰的成员仅在 ...

  8. 用NI的数据采集卡实现简单电子测试之4——半导体温度传感器

    本文从本人的163博客搬迁至此. 为了展示NImax(Measurement & Automation explorer)的强大配置功能,做了一个半导体温度传感器测试的示例. 一.半导体温度传 ...

  9. Java的自动拆/装箱

    作者:Alvin 关键字:语法糖 类 对象 参考 Java 中的语法糖 语法糖--这一篇全了解 浅谈 Integer 类 什么是Java中的自动拆装箱 深入剖析Java中的装箱和拆箱 前言 我们知道, ...

  10. Eclipse启动Tomcat错误:Several ports (8080, 8009) required by Tomcat v6.0 Server at localhost are already

    Eclipse启动Tomcat错误: Several ports (8080, 8009) required by Tomcat v6.0 Server at localhost are alread ...