最近项目末期, 我们团队为了ipa的大小使用不少的体积减小的方法, 除了一些常规的方法之外, 我分享一下自己研究出来的新思路。

首先我们来简单的介绍一下mach-O。

什么是mach-O?

Mach-O格式全称为Mach Object文件格式的缩写,是mac上可执行文件的格式,类似于windows上的PE格式 (Portable Executable ), linux上的elf格式 (Executable and Linking Format)。

上面第一个图是苹果给出的mach-O格式的示意图,而第二个图是我们使用machOView来分析某个可执行文件中的armv7的格式。可以看出他们两者的关系是对应的。

在machO这其中包含了很多的有效的信息,包括字符串,代码段,oc类,oc协议等各种的信息,利用这些信息我们也做到分析代码或者程序逻辑的作用,比如,下面这个数据就是我从这个machO文件里面导出来的,获取到了某个framework一个OC类中的所有基本元素。

那什么又是FatFile/FatBinary

简单来说,就是一个由不同的编译架构后的Mach-O产物所合成的集合体。例如上面我就只截取armv7的Mach-O格式座位示例, 而实际上常用的还有arm64/x86_64/i386等格式。

而实际上,包括我们使用的那些framework,大多数也是的。比如下图我们继续用machOView分析一下。

可以看到arm64/armv7架构的存在。

FrameWork跟最终可执行文件的区别在哪里?

这里我们先随便写一个简单的framework, 在这个framework中我们实现了两个oc类,如下图所示:

紧接着我们干净用machOView来看看这个新鲜出炉的framework,可以看到该FrameWork在armv7的格式下,里面存在多个.o文件。

如果我们选择其中一个继续看看的话,你就会看到一个完整的Mach-O格式的文件。

由此我们可以得知frameWork也是另外一种情况的Mach-O集合体,是由多个不同的子mach-O文件所组合而成的,他们可以单独的拆开,而可执行文件则把同一架构下的所有Mach-O文件都进行了合并,他们不能拆开,如果想要更加清晰的定义的话,可以去研究一下苹果的定义,这里不做过多的阐述。

我们能做什么?

可能到这里你还有点乱,没关系,我们直接来拆开一个framework给大家看看!

到了这一步,我们就已经知道了我们能把FrameWork中的各个子Mach-O文件拆开, 那么我们能不能把这些Mach-O文件中有效的部分重新组装一下, 生成新的一个FrameWork呢?

这必须是可以的,但是其实最重要的关键是在于怎么去确定这个Mach-O文件有没有被我们的程序使用到。

怎么确定一个Mach-O有没有被使用到?

我们直接再来一个简单的demo,尝试一下

此时进行编译

成功.....

然后拆分老的framework文件, 删掉拆分得到的MachOClassA, 并且用剩下的mach-O文件合并生成一个新的framework, 替换到工程中去并进行编译

你没看错, 他确实是失败了, 如果在程序中代码直接使用了某些类或者某些方法, 而其mach-O文件不存在的情况下, 会导致编译不过(找不到对应的方法), 这也就是说, 我们能够使用最简单粗暴的方法来判断这个machO文件是不是被需要的!

不过, 需要注意的是, category的实现方式是不一样的,故如果我们删除了category的方法, 但是直接把Mach-o删除的话, 编译时是不会报错的。有兴趣的同学可以自己去看看oc中关于category的实现。

另外还有在程序运行中动态使用的performselector方法(可以通过查询字符串列表排除)。

下面是相关的流程图。

怎么把Mach-O的删除工具应用到XCode中去

现在我们已经通过编译的手段获得了一堆mach-O文件, 但是很多都是pod中引进的, 这个时候我们需要在代码编译器执行删除.o文件的脚本 刚好Xcode确实有这么一个地方可以设置

成果

在debug模式下大概减少了0.5M, 实际二进制文件减小大概1.2M, 如果计算到最终提交到苹果并且经过DRM加密后, 预计可以减小1M左右。

PS

  1. category是需要过滤的, 这货有点特别
  2. 删除找出来的.o文件之后, 可能会引起一些特殊的情况, 当然一般是crash, 因为有一些特别的代码他们用法并不是直接引用某个方法, 而是通过NSString相关的方法来获得Sel或者Class
  3. 把查找.o文件的操作放在本地, 而在编译器上进行编译的时候就直接执行删除, 不占用编译器的时间(我们的项目要使用六个小时以上的时间来进行查找)
  4. 建议进行操作再跑一遍回归测试, 确保各个功能模块正常

其他实践与猜想以及做过的尝试

1、.o文件其实是可以直接引进到工程里面直接编译的, 也就是说其实可以把frameWork拆开, 然后加到工程中, 一样能够正常使用

2、一开始其实是想把.o文件中__text段中无用的函数进行删除, 但发现流程过于复杂, 而暂时放弃, 查找程序中无用函数的方法以后有机会再进行分享(如果这个成功的话, 估计会减小至少3~4M左右的ipa大小), 附上查找到的程序中无用方法结果的示例

3、其实看了上面那种方法之后, 我们紧接着又能想到, 暴力的将.m文件中的代码删除, 然后看看哪些工程中可见的代码是可以删除的(ps. 主要针对非framework, 另外也同样需要注意category以及performselector的问题, 需要配合查找字符串列表一起进行, 或者手工进行判断)。


作者:靖明@阿里移动安全 ,更多技术文章,请点击这里

减小ipa体积之删除frameWork中无用mach-O文件的更多相关文章

  1. 删除git中无用的大文件

    推荐阅读:为什么你的 Git 仓库变得如此臃肿 有时候我们不小心提交了一些大文件上去,后来删除了,但是已经于事无补了,整个git的提及已经蹭蹭上去了. 这个时候怎么办呢? 1. 查看有哪些大文件(to ...

  2. 超大批量删除redis中无用key+配置

    目前线上一个单实例redis中无用的key太多,决定删除一部分. 1.删除指定用户的key,使用redis的pipeline 根据一定条件把需要删除的用户统计出来,放到一个表里面,表为 del_use ...

  3. linux下rm命令删除文件名中包含特殊字符的文件【转】

    转自:http://blog.itpub.net/143526/viewspace-1060083/ 1. 删除带“-”的文件名的方法 2. 删除包含其它特殊字符的文件 3. 删除系统打不出的乱码文件 ...

  4. 怎么删除windows中无用的服务

    搜索cmd->以管理员身份打开 输入sc delete  服务名 回车即可

  5. 如何删除xcode 中过期的描述性文件

    1.使用终端 首先 打开终端 cd ~/Library/MobileDevice/Provisioning\ Profiles/再删除所有 rm *.mobileprovision 2.直接找到文件夹 ...

  6. 如何在使用eclipse的情况下,清理android项目中的冗余class文件和资源文件以及冗余图片

    在我们迭代项目的过程中,经常会启用某些功能,或者修改某些界面的问题,那么问题来了,这样很容易出现大量的冗余.java文件,冗余资源文件,一些冗余的界面文件等.那么问题既然出现了,那么如何去解决呢,这就 ...

  7. 最佳实践 —— 详细谈谈如何减小APK体积

    转载请注明出处: http://www.cnblogs.com/soaringEveryday/p/5254520.html 随着Android移动开发的需求越来越复杂,我们不可避免的遇到发布出去的a ...

  8. Entity Framework 教程——Entity Framework中的实体类型

    Entity Framework中的实体类型 : 在之前的章节中我们介绍过从已有的数据库中创建EDM,它包含数据库中每个表所对应的实体.在EF 5.0/6.0中,存在POCO 实体和动态代理实体两种. ...

  9. Spring Framework------>version4.3.5.RELAESE----->Reference Documentation学习心得----->关于spring framework中的beans

    Spring framework中的beans 1.概述 bean其实就是各个类实例化后的对象,即objects spring framework的IOC容器所管理的基本单元就是bean spring ...

随机推荐

  1. Duilib源码分析(一)整体框架

    Duilib界面库是一款由杭州月牙儿网络技术有限公司开发的界面开源库,以viksoe项目下的UiLib库的基础上开发(此后也将对UiLib库进行源码分析):通过XML布局界面,将用户界面和处理逻辑彻底 ...

  2. 如何在vim里删除空行?

    删除空行,进入底行模式 :g/^$/d ^代表首列 $代表尾列 d代表删除 g代表全局替换

  3. JS的双等和三等的区别

    在JS会碰到一个奇怪的运算符"===",之前学JAVA和C语言,只有"==",JS冒出个"===",挺奇怪的,遂google之... 在JS ...

  4. AndroidStudio导入项目出现Your project path contains non-ASCII characters错误

    Your project path contains non-ASCII characters. This will most likely cause the build to fail on Wi ...

  5. 第三十篇:SOUI模块结构图及SOUI框架图

    模块结构图: SOUI框架图:

  6. 第二十二篇:在SOUI中使用代码向窗口中插入子窗口

    使用SOUI开发客户端UI程序,通常也推荐使用XML代码来创建窗口,这样创建的窗口使用方便,当窗口大小改变时,内部的子窗口也更容易协同变化. 但是最近不断有网友咨询如何使用代码来创建SOUI子窗口,特 ...

  7. SQL 谜题(硬币的组合)

    问题:早在ITPUB中看过有个SQL高手,喜欢出谜题,以下是一个谜题.我试用SQL SERVER解决此问题. 用1分,5分,10分,25分,50分硬币凑成一元,总共有几种组合办法? SELECT'1* ...

  8. 基于.NET平台常用的框架整理

    自从学习.NET以来,优雅的编程风格,极度简单的可扩展性,足够强大开发工具,极小的学习曲线,让我对这个平台产生了浓厚的兴趣,在工作和学习中也积累了一些开源的组件,就目前想到的先整理于此,如果再想到,就 ...

  9. 基于Docker快速搭建多节点Hadoop集群--已验证

    Docker最核心的特性之一,就是能够将任何应用包括Hadoop打包到Docker镜像中.这篇教程介绍了利用Docker在单机上快速搭建多节点 Hadoop集群的详细步骤.作者在发现目前的Hadoop ...

  10. mysql查询练习题-2016.12.16

    >>>>>>>>>> 练习时间:2016.12.16 编辑时间:2016-12-20-->22:12:08 题: 涉及:多表查询.ex ...