iOS 项目结构与应用包瘦身实践

目录:

  • 000 - 苹果提供的 App Thinning (了解)
  • 001 - 项目结构介绍
  • 002 - 变更图片文件的导入方式
  • 003 - 快速删除项目中不用的图片资源
  • 004 - 图片无损压缩
  • 005 - 使用 fui 找到应用中未使用的类
  • 006 - LinkMap解析工具:检查每个类占用大小 (代码瘦身 )

前言:关于项目结构与应用包瘦身的学习

面对如今不断迭代的iOS APP,在产品需求以及功能模块的持续扩大下,应用包大小也会随之变得越来越大,当代码量达到一定程度后,对于一个持续性的大型项目来说应用包瘦身是一个迫在眉睫的问题。

当我们谈及应用包瘦身,无非就是从两个层面应对,一个是资源级别的优化,一个就是代码级别的优化,接下来我们就从这两个方面下手。

App包瘦身处理是为了减少包的大小,节约用户下载App流量。在App Store下载App,如果超过了150MB就必须在Wi-Fi环境下载或更新,这样如果``超过了150M,可能就会间接失去了大部分用户。如果我们的App要兼容iOS7和iOS 8,苹果官方规定:主二进制text段的大小不能超过60M,如果超过这个标准,就没办法向App Strore提交审核。

下面这张表格列举了当前国内外的部分常用App的包大小。


通过上面的表格可以看出目前包少于150M的只有网易云音乐,Instagram,Twitter。那么作为开发者可以通过哪些方法对自己的App包大小做优化处理呢?

内容:

000 - 苹果提供的 App Thinning

我们知道不同的设备的屏幕大小、分辨率、CPU、GPU、硬盘大小等都不相同。针对这种情况,苹果官方为开发者提供了 App Thinning技术,对于不同设备提供只适用当前设备的包为用户提供下载。如iPhone 5C只会下载适用于32位运行芯片的库和2x的图片资源的包,iPhone 8P则会下载适用于64位的库和3x的图片资源。



一、App Thinning 基本介绍

 App Thinning有三种方式: 
 1.  App Slicing
 2.  Bitcode
 3.  On-Demand Resources
  • App Slicing:
    iOS9之后苹果官方出的解决方案,在向iTunes Connect上传App包后,对App做切割处理,创建不同的变体包,这样就可以适用到不同的设备;

  • itcode:
    也是iOS9之后苹果给出的解决方案,针对特定的设备进行包大小优化。

  • On-Demand Resources:
    主要是为又下多关卡的情况服务的,On-Demand Resources会根据用户的关卡下载进度下载随后几个关卡的资源,并且已经过关的资源会被干掉,这样可以减少初始App包的大小。


二、那么如何在项目中适用App Thinning呢?

2.1 - Slicing的使用

在使用App Slicing的时候,大部分工作是由XcodeApp Store来完成的,开发者本身不需要做任何事情。在开发中只需要创建xcassets目录,然后将图片加入其中即可。在创建一个工程的时候Xcode会默认为开发者创建一个名为Assets.xcassets的目录,在开发过程中只要把图片资源加入其中即可。

当然也可以自己新建,选中工程目录New File--->Resources--->Asset Catalog即可新建一个。

我们在使用xcassets时,添加对应的2x分辨率和3x分辨率的图片,会在上传到App Store后被创建成不同安装包以减少App安装包的大小。同时苹果会自动根据的设备不同,在创建的安装包中自动加入当前设备需要的芯片指令集架构文件。


2.2 - Bitcode使用

Bitcode: Apple Developer Bitcode说明

bitcode是介于源码和机器码之间,在LLVM中的IR(Intermediate Representation)这层,由编译器前端clang生成,交给LLVM优化器优化后交给后端生成CPU相应指令。

一般情况下,在iOS9之后,新建一个工程,Xcode会默认设置Bitcode。由XcodeBitcode提供给Apple,由他们针对各种机型(包括新机型)的CPU对代码做二次优化,其本身不会增加包体积,上传的二进制文件会变大,但是不会影响用户的下载大小。

如果开启Bitcode,相应的,所有使用的pod都需要开启BitcodeBitcode必须是完整的,否则就是无效的,编译阶段就会报错。

开启Bitcode选项后,在debug模式下不会打进Bitcode,只有在Archive时才会。


2.3 - On-Demand Resources的使用

将图片、音频等资源文件分离出来,开发阶段将资源按照ResourceTag区分,存放在苹果的服务器上。App按需要发起请求,由操作系统来管理下载和存储,一般用于游戏资源或者内购。

优点:

 - 包体积更小,为设备省更多的存储控件
 - 懒加载(Game -> level -> download current resources)
 - 很少使用的资源可以放在服务器(Tutorial)

缺点:

 - 资源需要从苹果服务器下载
 - 资源需要按tag区分,制定相应的配置策略
 - 代码中管理何时下载,何时释放,增加了资源管理的复杂度

备注:

  1. On-Demand Resources官方文档

001 - 项目结构介绍

项目本身首先划分功能区以Page、Core、App划分
1、Page存储应用的模块,包含首页、个人中心等,每个模块下再以Controller、View、Model划分
2、Core 存储着一些与项目业务、界面无关的类,包括分类、宏定义、封装的请求基类等
3、App则存储着一些与项目相关的类,包括API、Base基类等

002 - 变更图片文件的导入方式

资源文件有很多种方案加入到工程项目中:

1. Assets.xcassets。

  • 只支持png格式的图片;
  • 图片只支持[UIImage imageNamed]的方式实例化,但是不能从Bundle中加载;
  • 在编译时,Images.xcassets中的所有文件会被打包为Assets.car的文件。

2. CreateGroup

  • 黄色文件夹图标;Xcode中分文件夹,Bundle中都在同一个文件夹下,因此,不能出现文件重名的情况;
  • 可以直接使用[NSBundle mainBundle]作为资源路径,效率高;
  • 可以使用[UIImage imageNamed:]加载图像。

3. CreateFolderRefences

  • 蓝色文件夹;Xcode中分文件夹,Bundle中同样分文件夹,因此,可以出现文件重名的情况;
  • 需要在[NSBundle mainBundle]的基础上拼接实际的路径,效率较差;
  • 不能使用[UIImage imageNamed:]加载图像。

【说明】:蓝色文件夹只是将文件单纯的创建了引用,这些文件不会被编译,所以在使用的时候需要加入其路径。

4. PDFs矢量图(Xcode6+)

5. Bundle(包)

对于上面这几种不同的导入方式,会对打出的包的大小有影响么?

经过测试得知:CreateGroup、CreateFolderRefences两种方式打出来的包,图片都会直接放在.app文件中,所以打包前后,图片的大小不会改变。而加入到Assets.xcassets中的方法则不同,打包后,在.app中会生成Assets.car文件来存储Assets.xcassets中的图片,并且文件大小也大大降低。


值得留意的是,在将图片资源移到Assets.xcassets管理的时候,一般情况下会自动生成与图片名称相同的,比如loading@2x.png和loading@3x.png会自动放置到一个同名的loading文件夹中。然而有一些不规则命名的图片,会出现一些奇怪的问题:

  • 图片名称为ios-f2-8-004的图片,放到Images.xcassets中,会自动生成调用的图片名是ios-f2-8-4,最后一位的004,被替换成4,然而在类文件中引用的是[UIImage imageNamed:@"ios-f2-8-004.png"],这样会找不到图片;

  • 图片名称为ios-f6-的图片,放到Images.xcassets中,会自动生成调用的图片名是ios-f6,这样也会找不到图片。
    因此在移动的时候,一定要细致对比。


备注

  • 通过CreateGroup、CreateFolderRefences两种方式打出来的包,图片资源不会做改动,直接放在.app包文件中,打包的前后图片资源大小不会改变。

  • 而加入到Assets.xcassets中的方式是在。app中生成Asset.car文件来存储放入的图片资源,是对图片资源进行了一次压缩,因此文件大小会降低,

综上所述,尽量使用Asset.xcassets的方式来导入资源文件能有效的控制APP包的大小。

003- 快速删除项目中不用的图片资源

开发中,由于不断地迭代,工程中必不可少的会有很多用不到的图片资源,使工程包的文件越来越大
如果一张张查询清理,这样很耗时,也很麻烦。推荐给大家一个方法,不到3分钟,就能清理所有的用不到的图片资源。

首先先去下载一个大牛写的mac应用,运行打开,传送门

操作页面如下

操作步骤详解:

 1.下载并打开应用就会显示如上图一个界面。
 2.点击Browse,选择工程所在目录。
 3.点击search按钮,一会所有工程中没有用到图片就被搜索出来了。
 4.选择需要删除的图片,点击Delete就可以删除了,这时候你再进入工程中查看,图片已经没有了。

备注 删除图片的时候,也要仔细些,不要把自己手动集成第三方中的图片删掉了,最好提前备份一份。

004 - 图片无损压缩

使用的工具是 ImageOptim ,点击链接下载

将项目图片拖入ImageOptim优化即可,详细的操作步骤在下载链接官网中有所描述

ImageOptim 主要作用是删除膨胀的元数据。通过压缩图像节省磁盘空间和带宽,而不会降低质量。

ImageOptim使用其优化版本覆盖文件。这是安全的,因为ImageOptim可以保持图像质量。如果您对此不满意,可以在将文件放入ImageOptim之前创建文件的副本。此外,作为预防措施,ImageOptim会将原始文件放入“废纸篓”中,因此您可以根据需要轻松恢复它们。


实验图例

1.无损压缩之前文件大小

没有无损压缩

2.正在进行无损压缩

正在进行无损压缩

3.无损压缩完毕

4.压缩之后的文件大小

压缩完成之后

005 - 使用 fui 找到应用中未使用的类

为了给APP提速,需要定期清理不用的类 fui(Find Unused Imports)是开源项目能很好的分析出不再使用的类,准确率非常高,唯一的问题是它处理不了动态库和静态库里提供的类,也处理不了C++的类模板。

使用方法是在Terminal中cd到项目所在的目录,然后执行fui find,然后等上那么几分钟(需要好几分钟甚至需要更长的时间),就可以得到一个列表了。 由于这个工具还不是100%靠谱,可根据这个列表,在Xcode中手动检查并删除不再用到的类。

fui的github链接 使用

 //安装 fui 工具 在终端中执行命令
 sudo gem install fui -n /usr/local/bin

 fui usage: https://github.com/dblock/fui

 到工程目录下,执行 fui find 命令,可以找出所有的没有用到的class文件

总体,感觉还有些类不准确,可以自己去仔细分辨。

006 - LinkMap解析工具:检查每个类占用大小 (代码瘦身 )

Link Map File中文直译为链接映射文件,它是在Xcode生成可执行文件的同时生成的链接信息文件,用于描述可执行文件的构造部分,包括了代码段和数据段的分布情况。


应用步骤:

1、打开LinkMap.xcodeproj,并运行,就可以看到工具界面


2、点击“选择文件”按钮,选择LinkMap文件(如何生成LinkMap详见下方的:如何获得LinkMap文件)



3、点击“开始”按钮,就可以看到每个类/静态库所占用的空间大小(如上图)

4、点击“输出文件”,可以将结果输出到文本文档中



如何获得LinkMap文件

1.Xcode在生成可执行文件的时候默认情况下不生成该文件,需要开发者手动设置Target --> Build Setting --> Write Link Map File为YES:


2.工程编译完成后,在编译目录里找到Link Map文件(txt类型)
默认的文件地址:

~/Library/Developer/Xcode/DerivedData/XXX-xxxxxxxxxxxxx/Build/Intermediates/XXX.build/Debug-iphoneos/XXX.build/ \n\

【扩展学习链接】

参考文章

推荐阅读更多精彩内容