最近项目末期, 我们团队为了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. [Java 8] (10) 使用Lambda完成函数组合,Map-Reduce以及并行化

    好文推荐!!!!! 原文见:http://blog.csdn.net/dm_vincent/article/details/40856569 Java 8中同时存在面向对象编程(OOP)和函数式编程( ...

  2. 学习EXT.JS5时的重点载图

    组件实例化的五种方式,最后一种不建议了 MVVM的图示,及controller的生存周期和MVC的不一样. VIEWCONTROLLER如何得到VIEW的实例呢,注意LOOKUPREFERENCE的使 ...

  3. 公众号第三方平台开发 获取 component_verify_ticket 2015-07-05 10:16 59人阅读 评论(0) 收藏

    8.推送component_verify_ticket协议 在公众号第三方平台创建审核通过后,微信服务器会向其"授权事件接收URL"每隔10分钟定时推送component_veri ...

  4. WebAPI图片上传

    public Task<HttpResponseMessage> PostFormData() { // Check if the request contains multipart/f ...

  5. linux下tar安装mysql

    >>>>>>>>>>>>>>>>>>>> 到官网下载 mysql-5.6.12- ...

  6. Sublime Text 3 快捷键

    选择类Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本.Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑.举个栗子:快速选中并更改所有相同的变量名.函数名等 ...

  7. c程序对于文件的处理

    C 文件读写 上一章我们讲解了 C 语言处理的标准输入和输出设备.本章我们将介绍 C 程序员如何创建.打开.关闭文本文件或二进制文件. 一个文件,无论它是文本文件还是二进制文件,都是代表了一系列的字节 ...

  8. <转>Unity3D研究院之C#使用Socket与HTTP连接服务器传输数据包

    最近项目中需要使用HTTP与Socket,把自己这段时间学习的资料整理一下.有关Socket与HTTP的基础知识MOMO就不赘述拉,不懂得朋友自己谷歌吧.我们项目的需求是在登录的时候使用HTTP请求, ...

  9. Leetcode Delete Node in a Linked List

    Write a function to delete a node (except the tail) in a singly linked list, given only access to th ...

  10. 【ORACLE】MD5加密

        今天乌干达充值卡入库时,发现有资源已经存在的异常, 异常原因经过核实是由于卡资源密码在库中已经存在, 为进一步查找存在的原因, 因此需要对导入文件密码的MD5 加密, 通过MD5加密后的字符串 ...