手机APP安装包缩减方案_腾讯移动品质中心TMQ的博客-程序员秘密

技术标签: 测试分析  手机  流量  精准测试  迭代  安装包缩减  iOS测试  

安装包大小对于产品很重要

主要有如下几个原因:

1、手机APP安装包的大小会影响用户是否愿意花费流量来下载此APP;
2、包体越大下载过程越长,用户取消下载的可能性越大;
3、在手机空间不足,用户需要清理手机空间时,包体越大的软件被清理的可能性越大;
4、一些预装软件,合作厂商会限定软件大小;
5、APP经过多次版本迭代,产生不少冗余代码和无用资源,会带来更高的学习和维护成本,也更容易出错。

文章将分三大部分进行讲解

一、iOS安装包的构成
二、安装包缩减方案
三、相关工具和知识介绍

1.iOS安装包的构成

选择ipa安装包,右键打开压缩包可见,iOS安装包主要由三部分组成:二进制可执行文件、资源文件(图片和视频)和其他文件(sdb数据库、plist文件等)。

以腾讯手机管家iOS版本安装包为例:发布包解压缩后是39.6M,其中二进制可执行文件共25.54MB占比64%,资源文件8.63MB,占比22%,其他文件大小总和占比14%。

2.安装包缩减方案

从第一部分可以看出,二进制可执行文件和资源文件是缩包方案的重点,下面分别从资源文件瘦身和二进制可执行文件瘦身两个方面进行详述。

一、资源文件瘦身

去掉无用资源
①  无用图片

原理:扫描项目里面所有png和jpg图片,然后在二进制文件、plist、xib里面匹配文件名字符串,得出图片没被引用

具体方法:在项目工程中,一般使用到图片资源均会在代码中使用字符串常量来引入图片资源。那么通过otool命令逆向__TEXT__cstring段来获取二进制文件中所有的字符串常量,并检查这些字符串常量是否匹配安装包中任意图片资源名(去除文件后缀,如@3x.jpg)。之后,没有被匹配的安装包中的图片资源就标记为疑似无用图片,然后做进一步排查处理。

因为在代码中,通过一些拼接字符串引用的图片资源在此方法中会被标记为无用图片,而实际中是有被使用到,这部分需要开发排查。

 ②  删除/压缩无用的视频文件、字体文件等其它资源

 ③  删除曝光率低功能或者变成网页形式
压缩资源

imageOptim进行无损压缩(主要是如文件的EXIF标签、颜色配置文件、作者等信息)。
imageAlpha进行有损压缩。

二、可执行文件瘦身

删除无用类

随着代码工程越来越大和研发历史越来越长,在工程中会存在一些类并没有被使用,而Objective-C的动态性,编译器会把项目里所有OC源文件编进可执行文件里,那么删除这些无用类文件必定能减少二进制文件的大小。取全部类列表classlist和在工程中被引用的类classrefs之差,就是无用类。

具体方法为:

① 通过otool命令逆向__DATA.__objc_classlist段和__DATA.__objc_classrefs段来获取当前所有oc类和被引用的oc类,其结果中包含类的段地址。
② 通过脚本解析,抽取出如上两个结果文件的差,也就是所有无用类的段地址集合
③ “otool -o 二进制文件” 命令获得所有段的详细信息
④ 将步骤2中对应的段地址作为参数,在步骤3的结果中脚本解析出具体的类名

删除无用方法

由于Objective-C的动态性,它可以通过类名和方法名获取这个类和方法进行调用,所以编译器会把项目里所有OC源文件编进可执行文件里,哪怕该方法没有被使用到,删除这些无用方法必定能减少二进制文件的大小。取全部的类方法和被引用的类方法selrefs之差,就是无用方法。实践证明,这种方法会比较多,那么可以做个类方法大小排序,去处理大于一定阀值的无用类方法。

具体方法为:

① 用脚本从linkmap文件中解析二进制文件中所有的类方法(通过解析text代码段内容)
② 通过otool命令逆向__DATA.__objc_selrefs段获得被引用的类方法
③ 如上两个结果文件相减就是没有使用到的类方法
④ 步骤3结果结合linkmap文件,可以获取每个类方法的大小,并依据方法大小对类方法进行排序

监控可执行文件大小

对linkmap文件进行分析,根据序号累加每个obj文件在每个段的占用大小,从而计算出每个obj文件在可执行文件的占用大小,进而算出每个静态库、每个功能模块代码占用大小(__DATA.__bbs是代表未初始化的静态变量,Size表示应用运行时占用的堆大小,并不占用可执行文件,所以计算obj占用大小时,要排除这个段的Size)

具体方法为:

① 分别获得版本1和版本2中各个文件的大小
② 用脚本获取两个版本中文件大小的差值
③ 对步骤2中的结果进行排序和具体分析


3.相关工具和知识介绍

一、Otool命令介绍

Otool可以提取并显示ios下目标文件的相关信息,包括头部,加载命令,各个段,共享库,动态库等等。它拥有大量的命令选项,是一个功能强大的分析工具,当然还可以做反汇编的工具使用。

使用方法:将安装包中的二进制文件作为otool的命令参数

二、LinkMap简介

LinkMap文件是Xcode产生可执行文件的同时生成的链接信息,用来描述可执行文件的构造成分,包括代码段(__TEXT)和数据段(__DATA)的分布情况。

使用方法:只要设置Project->Build Settings->Write Link Map File为YES,并设置Path to Link Map File,build完后就可以在设置的路径看到LinkMap文件了

LinkMap文件内容详解

① Object files

第一部分列举可执行文件里所有.obj文件,以及每个文件的编号

② Sections

第二部分是可执行文件的段表,描述各个段在可执行文件中的偏移位置和大小。

③ Symbols

  第三部分详细描述每个obj文件在每个段的分布情况,按第二部分Sections顺序展示。

  #Address                 Size                    File Name
  0x100001114       0x00000708 [  1]  -[MQQXLoadingView initWithFrame:]

互动问答

1.你所负责测试的app安装包有多大,项目组是否对安装包大小有限制呢?

原文链接

http://tmq.qq.com/2016/11/mobileapp_reduceprogram-2/


TMQ(腾讯移动品质中心)是腾讯最早专注在移动APP测试的团队
我们专注于移动测试技术精华,饱含腾讯多款亿级APP的品质秘密,文章皆独家原创,我们不谈虚的,只谈干货!

扫码关注我们

扫一扫 关注TMQ
精彩分享不断
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/TMQ1225/article/details/53084091

智能推荐

2019已经很冷,2020年Android工作或更难找——进大厂面试必备基础技能_Android725的博客-程序员秘密

一、写在开头在互联网行业里,2019年来到今天你能听到的消息都是什么样的?“某D公司开始裁员了”“某A公司据说冻结社招了”“据说J公司今年没有年终奖““据说M公司要裁员50%”……2019全年从开头到结尾似乎就没多少好消息,而到了2020年市场行情也许会更加寒冷。这里我说的是整个互联网行业,并没有单单挑出某个公司或者某个细分领域。而对于广大Android开发者来说,找工作似乎也变得越来越难了。2019年1月,我在51job搜索了一下北京地区的Android岗位,只有2100多个,而几年前的时

黑马程序员_java基础之异常处理_陌陌谢谢有你的博客-程序员秘密

对于角标是整数不存在,可以用角标越界表示,对于负数为角标的情况,准备用负数角标异常来表示。负数角标这种异常在java中并没有定义过。那就按照java异常的创建思想,面向对象,将负数角标进行自定义描述。并封装成对象。这种自定义的问题描述成为自定义异常。 注意:如果让一个类称为异常类,必须要继承异常体系,因为只有称为异常体系的子类才有资格具备可抛性。才可以被两个关键

Java并发指南12:深度解读 java 线程池设计思想及源码实现_weixin_30877181的博客-程序员秘密

​深度解读 java 线程池设计思想及源码实现转自https://javadoop.com/2017/09/05/java-thread-pool/hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io我相信大家都看过很多的关于线程池的文章,基本上也是面试必问的,好像我写这篇文章其实是没有什么意义...

PHP学习笔记——数据类型之间转换和检测;_iheyu的博客-程序员秘密

/* 数据类型之间的转换 * 一.强制转换 * var_dump();(类型值) * getType(变量); * 1.setType(变量,变成什么类型);----将原变量转换了 * 2.在变量使用时,前面加上类型符号,转----是在赋值时给新变量一个新类型, * 原变量类型不变 ...

帆软报表——多源分片与冻结_qq_36950604的博客-程序员秘密_帆软冻结列

最终效果图如下:需要实现的效果:多列多源,不进行分页显示。数据来自地区、供应商、雇员三个数据源。 列冻结,行冻结其实,我最想总结的还是数据绑定,以及显示。我总感觉有点迷!数据表:类别表、产品表、订单表、订单明细表、供应商表三个数据源sql语句:ds1: 类别、产品id、产品名称、产品对应供应商IDds2:雇员ID、货主地区、产品ID、该订单明细对应的金额 (可按照雇员、地区进行分类展示)ds3: 产品ID、该产品在该项订单明细中对应的金额、产品对应供应...

随便推点

Cocos 2d-x 批处理创建新工程_COCO56(徐可可)的博客-程序员秘密

REM 关闭命显示rem echo offREM 获取工程名set /p projectName=Please input the name of your project:REM 合成创建工程的cocos命令set cocosCommand=cocos new %projectName% -l cpp -p xyz.coco56.%projectName%echo 正在创建"...

《VMware Virtual SAN权威指南(原书第2版)》一3.2 为VSAN服务的VMkernel网络_weixin_34206899的博客-程序员秘密

3.2 为VSAN服务的VMkernel网络所有参与VSAN网络的ESXi主机都需要相互通信。vSphere 5.5引入了一个新的VMkernel类型,叫做Virtual SAN Traff?ic(虚拟SAN流量)。只有当VSAN VMkernel端口在加入到VSAN群集的每一台ESXi主机上都存在的时候,VSAN群集才会成功构建起来。在构建VSAN群...

redux_这个名字好0.0的博客-程序员秘密

reduxredux 基本介绍redux 是一个状态机。这个是用来管理状态的。这里要澄清一点, redux 并非 Facebook 推出的,而是由一个个人作者 Dan Abramov 所推出。redux 和 react 的关系两者之间本来没有任何关系,我们可以将 redux 用于 react、vue、angular 等技术,都可以用 redux,只不过 redux 和 react 配合得最好,一起出现的频率最多,所以之后在开发 react 应用的时候,自然而然就会想到使用 redux 来管理 re

C / C++中的零(0)_kaffeel的博客-程序员秘密

零(0)是一个整数。由于各种标准转换,0可以被用于表示任意整数(布尔量:bool,字符型:char,整型数:int)、浮点类型、指针、还有指向成员的指针的量。0的类型将由上下文确定。 由于没有任何对象会被分配到地址0,因此,0也被当做一个指针常量,表明一个指针当时并没有指向任何对象。在C语言中非常流行的就是用NULL宏表示0指针。由于C++收紧的类型检查规则,采用普通的0表示空指针比NULL更好一些。如果你习惯了使用NULL来表示0指针,那么最好采用如下定义: const    int NULL = 0

个推集成步骤_qq_34024778的博客-程序员秘密

1.注册账号2.创建应用,填写相关信息获取3.集成添加依赖在项⽬根⽬录 build.gradle ⽂件的 allprojects.repositories 块中,添加个推 maven 库地址 maven { url "http://mvn.gt.igexin.com/nexus/content/repositories/releases/"}在 app/build.gradle ⽂件中的 android.defaultConfig 下指定所需的 CPU 架构,如下所示: .

推荐文章

热门文章

相关标签