2014-09-22 12:41:17 BenNiao110 阅读数 40

网上流传了太多关于合并lib库的方法,自己也尝试过,但大多失败。有感于这种急于解决问题,经过百般尝试后依旧无果的无奈心情,小翁在这里用一个实例来完整阐述如何在mac中合并lib静态库。

这里以移动广告平台多盟的三个lib库为例子,之所以以此为例子,是因为我也遇到了库冲突的问题,所以才有了本文的内容。

本文的目标:合并libDomobOfferWallSDK.a、libDomobAdWallCoreSDK+UI.a、libDomobAdSDK.a

Let`s begin!

1.依次查看所有需要合并的lib库所支持的框架类型。i386表示支持iphone模拟器,armv6应用在iphone 3gs上,armv7应用在iphone4,armv7s应用在iphone4s以及iphone5,arm64应用在最新的iphone5s上。

1
lipo -info libDomobOfferWallSDK.a<br><br>输出是:Architectures in the fat file: libDomobOfferWallSDK.a are: armv7 armv7s i386
1
其他同理

看到红色粗体的fat了吗,fat file表示这个库里面合并了多于1个框架。

 

2.将lib库拆分出armv7、armv7s、i386类型的.a:

1
lipo -extract_family armv7 -output libDomobOfferWallSDK_arm.a libDomobOfferWallSDK.a

很多人会以为上面这条命令就可以一步到位分离出armv7版本,因为你显式地指出armv7了。但是,你错了。libDomobOfferWallSDK_arm.a仍旧是fat file,也就是里面含有了arm所有版本,这也是网上很多版本的教程错误的原因。如果误以为libDomobOfferWallSDK_arm.a只含armv7一个版本,则下一步的解.o操作就会失败,会提示"is a fat file"。小翁认为,最保险的做法是每次lib变化时都用lipo -info查看一下。现在我们查看一下libDomobOfferWallSDK_arm.a库:

1
2
lipo -info libDomobOfferWallSDK_arm.a
打印出:Architectures in the fat file: libDomobOfferWallSDK_arm.a are: armv7 armv7s

 

接着用如下命令进一步分离出单独的armv7、armv7s版本:(非常重要的步骤)

1
lipo libDomobOfferWallSDK_arm.a -thin armv7 -output libDomobOfferWallSDK_armv7_final.a
1
lipo libDomobOfferWallSDK_arm.a -thin armv7s -output libDomobOfferWallSDK_armv7s_final.a

而对于i386则不用上述那么麻烦,直接用第一句-extract_family指令就能分离出只含i386版本的库:

1
lipo -extract_family i386 -output libDomobOfferWallSDK_i386.a libDomobOfferWallSDK.a

经过上面操作后,我们得到了第一个待合并库libDomobOfferWallSDK.a 的armv7、armv7s、i386三个版本的库。剩下的两个待合并库同理。

 

3.分离出目标文件(.o)

进行实质上的合并。xcode里提示duplicate symbol都是说***.o与***.o冲突。注意,只有非fat file,也就是只含有单种版本的lib库才能分离出.o文件

1
2
3
ar -x ../libDomobOfferWallSDK_armv7_final.a
ar -x ../libDomobAdWallCoreSDK+UI_armv7_final.a
ar -x ../libDomobAdSDK_armv7_final.a

这一步最好是在lib*_final.a的同级目录下新建一个文件夹,专门用来接收解压出来的.o文件。同种版本(如armv7)的都解压到这个文件夹中,相同的.o文件他会自己覆盖掉。

 

4.从.o文件中合并成静态库:

1
libtool -static -o ../libDomobUniversal-armv7.a *.o

armv7s、i386版本同理。

 

5.合并成最终的通用静态库:

1
lipo -create -output libDomobUniversal.a libDomobUniversal-i386.a libDomobUniversal-armv7.a libDomobUniversal-armv7s.a

  

2016-10-10 14:56:10 HX_lei 阅读数 3509

最近一个人在做一个即时通讯SDK的项目,所以就用到了静态库的打包,开始遇到一些困难和莫名的bug,不过现在已经基本完成。现在,浅谈一下个人经验。首先,概述一些最基本的名词概念,也是为了大家能更好的理解我们究竟在做什么 为什么要这样做  有了这些基本的逻辑思维  那么其他什么就都不是事哈 (不要拦我 我要开始发功了)哈哈哈

一、概念篇

什么是库?
库是程序代码的集合,是共享程序代码的一种方式
根据源代码的公开情况,库可以分为2种类型
开源库
公开源代码,能看到具体实现
比如SDWebImage、AFNetworking
闭源库
不公开源代码,是经过编译后的二进制文件,看不到具体实现
主要分为:静态库、动态库
静态库和动态库的存在形式
静态库:.a 和.framework
动态库:.dylib 和.framework
静态库和动态库在使用上的区别
静态库:链接时,静态库会被完整地复制到可执行文件中,被多次使用就有多份冗余拷贝
动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存
需要注意的是:

动态库,不能被上传到AppStore(逼格太高 大苹果可是不允许的哈  哈哈)

总结:个人觉得 .a静态库的 本身就是一个对代码或者一个功能的封装,只不过是不开源的。

二、制作流程(如下均是Xcode7展示的操作)

新建一个纯净的项目-> 选择 “Cocoa Touch Static Library”

输入想要打包的静态库的名称

把库需要包含的源代码拖入此项目中 


此处有一些注意点见下图

选择需要暴露出来的.h文件,.m文件会自动编译到.a文件中



分别选择模拟器和真机(并不需要真正的手机),依然Command+B ,模拟器和真机环境下用的.a文件是分开的



这一步,如果看到.a文件由红变黑说明编译等都没有问题  已经完成一半了

右击“ShowInFinder”,查看制作好的.a文件

n
Debug-iphoneos文件夹里面的东西是用在真机上的
Debug-iphonesimulator文件夹里面的东西是用在模拟器上的



如果想让一个.a文件能同时用在真机和模拟器上,需要进行合并

在终端输入指令
首先文件切换到 Products文件夹  

然后输入

lipo -createDebug-iphoneos/libXXX.a Debug-iphonesimulator/libXXX.a  -output  libXXX.a

蓝色部分是固定指令
红色、紫色是真机和模拟器.a文件的路径
绿色是所合成.a文件的路径
.a文件的体积(一般情况下)
真机用的.a> 模拟器用的.a
所合成.a== 真机用的.a+ 模拟器用的.a





使用.a 静态库

现在.a静态库和头文件都有了就可以把它们拖到项目中使用了

使用时直接#import"xxx.h"就可以直接导入调用使用了

至此,静态库算是制作完了,但是有以下几点需要说明

无论是 .a 静态库还是.framework 静态库,最终需要的都是:
二进制文件 +.h+ 其它资源文件

倘若自己所需要打包的静态库代码中用到了别人的三方框架比如“AFNetworking”等,此时只需要把用到的三方库文件的头文件在选择暴露头文件时都给暴露出去,然后导入的项目中如果也用到了相同的三方框架,此时此项目就不需要拖入这个三方库代码直接,需要使用时直接把你所提供的.a静态库和头文件导入 然后#import你所提供的相关头文件即可使用(注意:一定是以你的打包的为准)比如 直接#import"xxx.h"

若是自己的静态库原代码中使用了分类  比如NSString+xxxx,此时一定需要更改下项目的环境配置
添加一个“-ObjC”(注意"O""C"是大写的)



2015-03-25 15:56:29 sxn4245608 阅读数 719

在ios开发集成中,各种三方库冲突不可避免。

解决办法:

1.删除冲突的.h文件或.h+.m同时删除。比如:SBJSON,很多三方sdk中都包含,只需要保留一个就可以。

2.重命名。列子如上。

3.拆解.a包,删除掉冲突的库文件。


一般的.a静态库冲突都会提示相关文件名,但是如果不知道冲突文件或相关代码在何处该怎么办?

1.在终端下,运行匹配命令查找包含相关代码 或 字符串的文件。

2.拆解.a静态库,跟踪到相应.o文件。

3.合并.a静态库。 


匹配查找命令有两种:

1. grep 命令    grep -r(递归匹配) "匹配string" .(路径) (.表示匹配当前路径下)

2. find命令    (下文有例子)



下文转自:http://www.yeeann.com/archives/260.html

在引用第三方库时,不时的会碰到诸如库冲突、库包含了某些禁用的API等问题,而这些库往往都被打包成了静态库文件(即 .a文件)来使用。这时就需要我们能够去对Object file进行一些必要的处理调整。如检索信息,移除冲突的库等。以下是一些常用的方法:

一、 查找.a文件中是否包含相关信息,如苹果禁用的unique Identifier。

find  .  -name *.a |xargs grep uniqueIdentifier 

查看object file文件信息:
nm  xxx.a | grep ".o:" | sed "s/.(//g" | sed "s/).//g" | uniq

二、去除不同的.a文件之间内含冲突的库,如openUDID库的冲突。

1. 查看architectures
lipo  -info  libx.a

2. 如果是fat file,处理成non-fat
lipo  libx.a  -thin armv7  -output  libx-armv7.a

3. 解压出object file
ar  xv  libx-armv7.a

4. 打包object file
ar  rcs   libx.a   *.o

5. 生成Fat file
lipo  -create  Libarmv7.a  -output  libx.a

6. 合并.a文件
lipo  -create  Libarmv6.a  Libarmv7.a  -output  Lib.a

2018-11-08 15:27:20 hx853318463 阅读数 320
  • 本文档包含的所有内容:
  1. iOS SDK预备知识;
  2. .a or .framework,该如何选择?
  3. 最基本,但完整的SDK开发流程;
  4. 文档使用静态库(.a)文件说明开发流程(.a应该是初学者最先接触到,且应用比较广泛的一种静态库,如果你还没有决定用那种库来开发,使用a库永远不是个错误的选择);
  5. 入门案例,所以文档中包含较多(详细)截图。
  • 本文档不包含的内容:
  1. 不包含Android SDK开发知识;
  2. 不包含SDK打包的知识(SDK打包相关知识,在下一个文档分享);
  3. 不包含.framework开发知识的讲解(.framework考虑在下一个文档详细分享);
  4. 不包含长篇大论,作者的已知经验,直接给出见解。

1. SDK预备知识

1.1 什么是SDK开发?

不管是百度、谷歌,还是找到它的缩写的来源,还是听大神们侃侃而谈;简单实用的说明就是:封装业务,供接入方使用。你懂的。

1.2 SDK开发的应用场景,即SDK是为了解决什么问题?

较常见的应用场景是:

  1. 游戏SDK:游戏开发人员是不可能花费大量精力做各个平台的开发(Andriod、iOS、WP)的,所以需要各个平台的SDK,来帮助游戏更快的接入各个平台;这里面又包含渠道SDK、融合SDK等说法。
  2. 各种功能性SDK:比如你要使用别人公司的某个业务,或者功能,使用别人提供的SDK就实现了这个功能。
  • 总结:想让别人使用你公司或个人代码实现的功能,但是又不想人家看到你代码的实现逻辑,那就开发一个SDK吧!

1.3 SDK开发需要的工具?

  • 一台Mac电脑:推荐MBP,其实一台8G内存的Mac是足够满足一般性的SDK开发工作的,SSD等都属于是有了更好,没有影响并不大。
  • Xcode :使用较新版的Xcode即可,该文档演示的demo是基于Xcode9.4.1
  • 语言:游戏行业一般会选OC;根据团队或者业务需求,OC或者swift;该文档演示demo使用的OC。

2. a or framework ?

看到这里的读者,大概都是真正的已经有SDK开发需求的饿汉了。

  • 直接谈见解:
  1. 游戏SDK开发?or 有代码混淆需求?or 马甲包?(业务不变,代码却要求变动):使用.a库;推荐使用顺序:a > framework静态库 > framework动态库 ;(不懂这里说什么的读者,可忽略这些内容);

  2. 只是给别人使用,没有以上奇怪的需求:a or framework都可以,比较推荐.framework动态库,因为接入方接入会简单许多;推荐使用顺序:framework动态库 > framework静态库 > a;

  3. 如果你对公司的业务流程还并不是很清楚,使用.a;

  4. 如果公司的业务需求还并不是很清楚流畅,使用.a;

  • 总结:如果真的不知道怎么选,那就选a吧!永远不会是错误的选择。

附注:.a和.framework的特点比较(个人经验,如有错误,望指正~)
1) .a 是静态库,参与iOS项目编译,接入方等于是使用了你的代码库,会让接入方的宿主APP在体积上,有明显的增大。
2).framework可以是静态库,也可以是动态库,但是默认是动态库;动态库的好处是:不会明显增加宿主app的体积;但是在加载速度上会低于静态库。
3)framework动态库是苹果审核大概iOS8.0之后才接受的,之前使用framework是不允许上架的;a是一直都被苹果商店接受的。
4)framework开发方便,接入也很方便;但是a是最安全稳妥的策略(对任何业务需求来说)

3. 入门案例:静态库HelloWorld.a的开发

3.1 新建静态库项目

从头开始创建项目
选择a的target
标题、语言、next
看看项目
头文件

3.2 编写代码

需求:实现最简单的hello world
直接上代码:(代码很短,不用快进)

// HelloWorld.h
@interface HelloWorld : NSObject

/**
 say hello
 */
+ (void)sayHello;

@end
// HelloWorld.m
@implementation HelloWorld

/**
 say hello
 */
+ (void)sayHello {
    
    NSLog(@"Hello, world");
}

@end

好了,所有SDK的代码写完啦,开始编译成.a文件:图片说明
编译并说明

至此,一个静态库开发到编译的流程就完毕了!
恭喜你,你已经入门了!

那么,缓口气!下面的内容就都是更简单的内容了!(但是同样重要,这是每个sdk开发里面都必须要经历的环节)

4. 静态库的测试Demo

sdk开发中,一个测试SDK完整功能的测试demo,是必不可少的。
这里讲解一个最简单demo的编写。

测试方案分析:
方案1:直接新建一个普通的App项目,把刚才打包的好的.a文件及其头文件拖进去,编写功能测试代码,搞定!简单直接,但不推荐(确实有开发者是这么用的),因为需要新建一个project,需要在2个project之间来回切换,麻烦!
方案2:在该静态库项目中,新建一个target,使用这个target来测试静态库的功能。该案例使用这种方式来说明。
方案3:有些开发者的思路,跟这个文档的流程正好相反:创建一个测试demo项目,然后在测试项目中,添加一个静态库的target,然后也可以使用测试demo,来测试静态库的target;这种方式也有不少人用;但个人比较推荐方案2,以静态库的target为first target,目标导向更加清晰。

4.1 新建测试target

直接上图:
新建测试的target

设置测试target的name

测试target文件浏览

4.2 集成静态库

直接上图:
测试target添加静态库

选择刚才的静态库

添加后的静态库

附注:也可以这样添加静态库哦

静态库正确被价值链!

4.3 编写测试静态库的代码

测试代码

输出结果:

HelloDemo[21696:2764086] Hello, world
  • 因为这是一个app的测试demo,所以会吊起模拟器或者真机,但是因为是一个简单的demo,并没有节目展示,所以,这里只有Xcode的Command Line Tool(就是命令行)会打印出"Hello, world"。

至此,一个SDK完整的开发流程就此结束了!

5. 小总结

让我们总结一下,你学会了:
1、创建并编译一个静态库;
2、设置静态库对外可见的头文件;
3、用一个测试demo的target来测试编写的静态库的功能。

有读者肯定会觉得这个案例太简单了,而且毫无用处!
但是,该文档给入门者提供一个快速入门,并作为开发流程参考的作用,该是能达到的吧~

后续,你可能想了解的内容包括:
1、如何把你自己打包的SDK,给到别人用呢?
2、如何编译静态库的真机版,和模拟器版?
3、.framework的开发流程?
4、SDK开发过程中有哪些坑?

以上内容,纯属个人经验分享。
如有不明之处,可留言;如有错误之处,欢迎指正!
转载注明出处。

2017-07-05 12:36:18 zhouxiangyu666666 阅读数 2007

       以前在制作静态库.a的时候也有导入其他静态库,但导入的都是.a形式的静态库,没有什么问题可以将其它的.a 静态库打入自己的.a静态库,然后直接给用户提供自己的.a就行了,关于在我的.a静态库中引用了其它的静态库,用户是并不知道的。但是依赖的系统动态库是无法打入到自己的.a中的,需要用户导入2个静态库.a依赖的所有动态库。今天需要在.a中引入.framework形式的静态库,发现并没有办法打入到.a中,还需要用户自己再导入一次这个.framework形式的静态库。

       先说下静态库和动态库:

       库(Library)其实是一段编译好的二进制代码,加上头文件就可以供其他人使用了,自己封装库有很多好处,比如:某些代码需要给别人使用,但是我们不想让别人看到我的代码,就需要用库封装上,纸提供头文件。还有就是项目中不会进行改动的代码,封装成库的形式可以节约编译时间管理也非常方便。静态库:可以是.a形式,也可以是.framework形式,项目每次编译都会拷贝一份到项目中,你的app二进制也会变大。基本上我们用到的第三方SDK都是静态库,在使用的时候需要导入所有的依赖库。动态库:比如UIKit.framework和Foundation,framework都是系统动态库,存在于iOS 系统之中(可以是.framework形式,可以是.dylib形式,也可以是.tbd形式),在你打包应用程序的时候不会拷贝到你的ipa中,当需要使用的时候会动态从iOS系统中加载它们,所以动态库也被称为共享库。framework是静态库还是动态库需要看build settings中Mach-O文件怎么选择,选择Static Library就是静态库,选择Dynamic Library就是动态库,framework形式的静态库不需要再额外提供.h和.bundle。但是苹果为了安全考虑是不允许不同应用程序共享代码的,所以自己制作的动态库也还是需要拷贝到应用中(感觉失去了动态库的意义),

.framework形式的静态库=.a形式的静态库+.h+.bundle。

      .a形式的静态库可以导入其他.a形式的静态库,但是不能导入.framework形式的静态库,需要用户自己从新导入。新建个.framework静态库的工程试了下,.framework形式的静态库既不能导入.a形式的静态库,也不能导入.framework形式的静态库。都需要用户自己再次导入依赖的静态库动态库。

iOS的framework动态库

阅读数 127

iOS 合并多个数组

阅读数 7642

【iOS】Workspace使用

阅读数 1813

没有更多推荐了,返回首页