写在前面

 

  • 最近公司需求不多,正好研究一下 App 瘦身的办法,写了点小总结。

  • 如果你不知道下面几个问题,不妨可以看看文章。

    • 使用 .xcassets 有什么好处?

    • @1x 、@2x 和 @3x 会一起内置到安装包中吗?

    • PDF 和 @1x 、@2x 和 @3x 有什么区别?

    • 如果我有一个 10 x 10 的控件和一个 50 x 50 的控件,美工需要制作几张 PDF?

    • Iconfont 是什么?PDF 和 Iconfont 有什么区别?

    • 启动图的正确打开方式?

    • 使用 Swift 或者 混编会增大多少的包体积?

    • Install Smallest or Coding Fastest ?

分析

 

  • 在瘦身之前,首先需要分析一下,我们可以从哪几个方面入手。(以 Yep 为例)

Yep是一款很优秀的 Swift 开源软件。

https://github.com/CatchChat/Yep

目录划分

  • App 的瘦身主要是针对于安装包,而在 iOS 中安装包就是一个以 .ipa 结尾的压缩包。我们可以通过 iTunes 下载获取这个 .ipa 来分析。

稍微整理一下,大致可以分为以下几类。

  • 资源层面:

    • Assets.car:项目中所有 .xcassets 的压缩包

    • image: 图片资源文件

    • Video && Audio :音频 或者 视频。

  • 代码层面:

    • 国际化:国际化适配的 String ===> 89K

    • Xib && Storyboard:Xib 和 Storyboard 编译后的文件。

    • Yep :项目可执行文件。

    • Frameworks:Embedded Frameworks,项目中使用的动态库

  • 其他:

    • other:配置文件

    • PlugIns:YepShare,一个共享的插件。

整理后的目录

  • 虽然 Yep 不能代表所有的 App,但是在对于 Yep 的 ipa 分析之后,大致可以总结出,对一个 App 的安装包瘦身,可以从资源层面和代码层面两个层面入手。

资源层面

  • 在讲资源层面之前,希望我们能达到一个共识,那就是所谓的资源文件指的是 图片、视频、音频。

  • Remote : 将资源文件放在服务器上,当用户下载完 App 后根据需要再下载。

  • Local : 将资源文件集成到安装包中的。

Remote

    • 对于 Remote 的方式,如果做好策略(比如缓存),那么理论上,我们可以把 非必须的资源文件 都放到服务器上,这样对资源压缩率达到了 100%。也就是说安装包 没有任何非必须资源文件 。

      • 必须资源文件:例如应用图标、启动图的这种配置图片。

    • 苹果的 On-Demand Resources(http://benbeng.leanote.com/post/On-Demand-Resources-Guide) 也是通过这种按需加载资源的思路给我们提供了一种阶段性加载资源的途径,具体的不展开描述,你可以点前面的链接进行查看。但是虽然以关卡、tag这种方式来按需加载资源,但是苹果的服务器对于中国用户来说实在是慢的不行,所以暂时不建议采取这种方式。你们可以在自己服务器上实现这种策略方式来加载图片。

ODR 模式

ODR 缓存策略

Local

  • 当然全部将非必须资源文件放到服务器上明显是不现实的,对于一些必用资源文件,还是需要将资源文件 集成到安装包中的。

    • 必用资源文件:安装了 App 肯定会用到。

Local 集成方式
  • Create group 和 Create folder references

    • 这两种其实就是直接把资源文件 拖 进去,在 Xcode 打包之后,所有图片都在可执行文件的相同目录下面。这也是很多老的 App 或者目前部分 App 的使用方式。

  • .xcassets

    • 这是苹果在 Xcode 5 出来之后,推荐我们使用的图片管理方式,提供了图片渲染、拉伸模式模式、机型适配等功能。在 Xcode 打包之后所有的.xcassets 文件都会放入一个Assets.car文件中。

Local 开发使用方式列举分析。
    • 一般 App 的图片内置方式

      • 采用拖的方式,图片包含@1x、@2x 和 @3x。

      • 采用拖的方式,图片只包含 @2x 和 @3x。

      • 采用拖的方式,图片只包含 @2x 或 @3x。

      • 采用.xcassets的方式,图片包含@1x、@2x 和 @3x。

      • 采用.xcassets的方式,图片只包含@2x 和 @3x。

      • 采用.xcassets的方式,图片只 包含@2x 或 @3x。

      • 采用.xcassets的方式,图片使用 PDF。
        (可能还有其他方式,希望你能告诉我。)

    • 拖的方式

      • 首先@1x、@2x 和 @3x主要是为了适配不同 ppi 的机子而做了一种策略。@1x主要是为了适配 iPhone 4 之前的 非 Retina 屏幕,@2x 主要是为了适配 非 plus的 iPhone 设备, @3x 是为了适配一个点的 3 * 3 个像素的手机。

      • 因为 iPhone 4 之前的机子基本没有什么 App 会去适配,所以一般来说都会删除,所以就有了 『采用拖的方式,图片只包含@2x 和 @3x』 的方式。但是假如你只提供一张图片,例如你只提供了一张 @3x 的图片,iOS 系统在 iPhone 7 上无法找到 @2x 的图片,会去查找 @3x 或者 @1x 等,再根据实际分辨率进行拉伸,最后把像素铺到屏幕上。所以在能够接受查找和拉伸造成的性能消耗的前提下,我们可以只用一张通用的图片,所以就有了 『采用拖的方式,图片包含@2x 或 @3x』 的方式。

      • 以一个 14M 的图片资源(包含@1x 、@2x、@3x)来说,如果所有的图片去除掉 @1x 能减少 1M 左右,去除掉@2x能去掉 4M 左右。因此采用『采用拖的方式,图片包含@2x 或 @3x』的方式虽然损失了一点性能,单大概图片资源大概减少了35%左右,。

    • 采用.xcassets的方式

      • 我们都知道了,采用『采用拖的方式,图片包含@2x 或 @3x』的方式大概图片资源大概减少了35%左右,但是稍微损失了一点性能。有什么方式可以减少掉这点性能消耗呢?

      • “很幸运” ,苹果在 iOS 9 终于意识到了这个问题,然后提供了一个叫做 App Slicing(如下图所示)的东西。App Slicing大致就是App Store会根据不同的设备准备不同的安装包(App Variant),每个安装包(App Variant)都只有相应尺寸的图片,比如 iPhone 6 去下载时,只会下载到 @2x 的图片的安装包(App Variant)。但能实现这个功能的前提是图片需要放置在.xcassets去管理。

APP Slicing

  • 所以,目前许多 App 采用 『.xcassets的方式,图片只 包含@2x 或 @3x』 其实是没意义的,特别是在你不适配 iOS 8 的时候,你这么做是强行降低了 App 的性能。当然你要觉得为了 8% 的非 iOS 9 用户 减少 App 安装包大小 而去降低另外 92% 的用户的 App 运行性能 没什么问题,那么你可以采取上面这种方式。

  • 关于 PDF

    • 我最早是在这一篇博客(http://martiancraft.com/blog/2014/09/vector-images-xcode6/)中看到的,当然 Yep 也是这种方式。大致是删掉 @2x 和 @3x 的图片,然后替换成 矢量图 PDF,最后放入.xcassets中去。

    • 而 Xcode 在打包的过程中,根据你的矢量PDF图的大小,生成@1x、@2x和@3x的图。例如你的PDF图是4545px,那么Xcode会在编译时生成下面3个png:4545px 、9090px、135135px,最后再放入Assets.car中。所以采用@1x、@2x 和 @3x 和 PDF 两种方式本质上是一样的。

    • 在这里有很多人会有一个误解,例如在 App 中有一个 10 10 pt 和 一个 50 50 pt 的 imageView 都用了一个相同的图标。很多人会以为做一个就够了,因为 pdf 是矢量图。但是其实是需要一个 10 10 px 和 50 50 px 的两张 pdf 才可以,因为只用一张的话,另外一张用的其实就是 10 * 10px 的 PDF 的产物。

    • 关于压缩问题。

      • 我是用tinypng 来压缩的,应该是以最小的占用量达到了最适合的效果。但是其实.xcassets 也会为你做一部分的压缩。如下图所示:

压缩过程

  • .xcassets 的压缩应该还对图片进行了处理这也就是为什么 840KB 压缩了 81.5%,Assets.car却没有减少那么多。

  • 同时也有人在试验中发现,用一些压缩工具似乎没有很么实际效果,这也有可能是因为 Xcode 在打包的时候做了一定的处理。

启动图

  • 启动图在一个项目资源中占比其实蛮大的,之前见过一个项目 6 张启动图大概有5M 左右,最大的是2M。

    • iPad 2 and iPad mini (@1x): 768 x 1024

    • iPad and iPad mini (retina @2x): 1536 x 2048

    • iPhone 4s (retina @2x) 640 x 960

    • iPhone 5 (@2x): 640 x 1136

    • iPhone 6 (@2x): 750 x 1334

    • iPhone 6 Plus (@3x): 1242 x 2208

  • 但是自从LaunchScreen.storyboard出来一后完全没必要做这么多张了。只需要将启动图设置为LaunchScreen.storyboard 然后在LaunchScreen.storyboard上设置一张 imageView 。最后再弄一张启动图的 pdf 就可以了。

iconfont

  • 首先这个东西估计很多人不知道,我也是在@桌同学的提醒下才知道原来 iOS 也是可以用 iconfont 的。最早这个东西是为 Web 设计的,主要是因为 网页的 大小直接影响了加载速度,所以在压缩上连小 icon 都不放过,当然还有一个最主要的目的就是减少请求次数,因为如果是图片的话,一个图片就是一次请求。

  • 具体的效果可以看一下,使用IconFont减小iOS应用体积(http://johnwong.github.io/mobile/2015/04/03/using-icon-font-in-ios.html)这篇文章。

  • 虽然看上去效果不多,但对于一些比较追求精致的公司可以尝试一下这种方式。

期中,PDF 和 iconfont 两个都是矢量的概念,但是 iconfont 在整个 App 中不管多少种尺寸只需要一个 iconf,但是 PDF 可能需要多个。

HTML 5

一些 APP 的一些功能可以用 HTML5 + WebView 的方式来实现。而 HTML 5 这个可以通过下面几种方式一步步优化:

  • 让做前端的给一个最小的包内置到 App,去除无用代码、代码混淆压缩等。

  • 将所有图片 Remote 化。

  • 将所有页面 Remote 化。

其他

  • 当然,还要注意资源文件重复的问题。而资源文件重复问题主要有几种:名字相同、名字不同内容相同/相似。

    • 对于名字相同的问题,你可以把原来的拖的方式改为.xcassets,他会自动管理相同名字的图片。然后把多余的去掉

    • 名字不同内容相同/相似:你可以使用Duplicate Photos工具

  • 还有一个问题就是资源文件没有用,却占了空间,可以使用LSUnusedResources将代码中没用到的文件删除。当然可能存在误删,比如用数组加载的图片,这个工具无法识别。


代码层面

Install Smallest VS. Coding Fastest

语言选择

  • 虽然说我本人更喜欢用 Swift 来写 App。但从 App 瘦身的角度,不推荐使用 Swift,不论纯 Swift 还是 混编。原因很简单。看一下下面的图:

  • 这是任何一个包含有 Swift 代码的 App 都有的一个为了支持 Swift 的动态库集合,在10M 左右。如果你使用 Objective – C 完全不用这个东西。

  • 当然,我是可以接受安装包大10M 来用 Swift 写的。

数据库选择

    • 这个问题也是我在分析 Yep 的第三方库的时候发现的问题,因为 Yep 使用的是 Realm,据说是目前是性能最好的移动端数据库。但是在三方库中可以看到,Realm 的支持占了很大的比重,大约在 8M 左右。但是如果使用 FMDB 话只需要192KB,而 CoreData 几乎可以忽略不计。下面是部分截图。

FMDB

Realm

RealmSwift

MRC VS. ARC

  • 最开始是在Bang的这篇文章中看到用ARC比用 MRC 会导致可执行文件大10%。起初我是不相信的,但是在我用 SDWebImage 的1.0 版测试之后,ARC 比 MRC 的可执行程序增加了14% +。所以MRC 比 ARC 编译成可执行文件之后更小,具体的测试方法可以去他的博客看,这里就不重复了。

总结

  • 先分析一下前面几个问题造成的原因:

    • Swift && Realm : 首先 Swift 是因为不稳定,所以支持的动态库没有集成到系统的”dyld的共享缓存”中去。而 Realm 因为不是苹果自己开发的,所以支持的动态库也没有集成到系统的”dyld的共享缓存”中去。所以都内置在了 App 中,而且这两个功能需要写很多代码来实现,因此容量又很大,导致看起来这两个东西占了很大的“无用”的容量。(ps.关于iOS 中库的问题,你可以去我的笔记中查看~)

    • ARC:因为 ARC 叫做自动引用计数,他的实现方式其实就是 Xcode 在编译的时候自动给你加内存管的代码,但是机器毕竟没人聪明,Xcode 会在很多情况下增加很多没用的代码,这也是为什么 ARC 的底层实现比 MRC 更快,但是实际运行性能上在有些时候却不及 MRC 的原因,而正因为增加了很多没用的代码,ARC 最终编译包会比 MRC 大。

  • 总结前面的几个问题,归根结底于一个问题,那就是Install Smallest VS. Coding Fastest。很多时候为了追求更快的编码速度,总会有所损失,但是在我看来这些事值得的,不然为什么我们不用 C 来代替 objective-c 或者用汇编来代替 C 呢?

Bitcode

  • bitcode 是被编译程序的一种中间形式的代码。包含 bitcode 配置的程序将会在 App Store 上被编译和链接。 bitcode 允许苹果在后期重新优化我们程序的二进制文件,而不需要我们重新提交一个新的版本到 App Store 上。

  • 当我们提交程序到 App Store上时, Xcode 会将程序编译为一个中间表现形式( bitcode )。然后 App store 会再将这个 bitcode 编译为可执行的64位或32位程序。

  • 所以,通过这个方式,我们可以做到架构级别的App Slicing。


Tips

结合上面的内容,再加上Bang大神写的博客(http://blog.cnbang.net/tech/2544/),我总结了几条 Tips。排名越往前的我觉得越需要去优化。

Tip 1:去除重复、无用资源文件,解决名字重复问题。

Tip 2:图片使用.xcassets管理且无须考虑@1x\@2x\@3x 问题。万不得已再用拖的办法,同时结合一定策略方案进行包瘦身。

Tip 3:图片使用PDF 优先级高于 PNG,因为 Xcode 会帮你完成剩下的任务。

Tip 4:使用tinypng压缩PNG图片。视频可以通过 Final cut 等软件进行分辨率压缩。音频则降低码率即可。

Tip 5:icon 使用 iconfont

Tip 6:非必须资源文件可以放到自己服务器上, 但必用资源文件需要内置到安装包中。

Tip 7:HTML 5 需要将图片 Remote 化 或者将整个HTML 5 的页面 Remote化。

Tip 8:Build Settings->Optimization Leve release版应该选择Fastest, Smalllest

Tip 9:开启 BitCode

以下是几乎不可能去做的优化 Tips

Tip 10:尽可能的去除无用的代码、控制类名、方法名长度、冗余字符串

Tip 11:如果你想的话,不使用 Swift、不使用 Realm更甚至于尽量不使用 OC

Tip 12:MRC 比 ARC 编译成可执行文件之后更小。


更多:工作之余,写了点笔记,如果需要可以在我的 GitHub 看。

https://github.com/Damonvvong/iOSDevNotes


参考文章

  • App Thinning

    http://t.cn/RVJ8kNd

  • Confirmed: Objective-C ARC is slow. Don’t use it! (sarcasm off)

    http://t.cn/zYkzifW

  • 4 XCODE ASSET CATALOG SECRETS YOU NEED TO KNOW

    http://t.cn/RVJR2c0

  • 使用IconFont减小iOS应用体积

    http://t.cn/RVU7B3h

  • iOS可执行文件瘦身方法

    http://t.cn/RZgnVL3

减肥App计划的更多相关文章

  1. Sprint评分表

    组名:第七班                                             姓名:王炳午 1.Cs 小分队: 项目: 游戏与办公的集合一些小的程序的整合有2048,倒计时,记 ...

  2. 重新想象 Windows 8 Store Apps (35) - 通知: Toast 详解

    [源码下载] 重新想象 Windows 8 Store Apps (35) - 通知: Toast 详解 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 通知 Toa ...

  3. 重新想象 Windows 8 Store Apps (36) - 通知: Tile 详解

    [源码下载] 重新想象 Windows 8 Store Apps (36) - 通知: Tile 详解 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 通知 Tile ...

  4. 英语口语练习系列-C26-广告-人际关系-辨别物体-如果

    词汇-广告 advertisement noun [ C ] UK /ədˈvɜː.tɪs.mənt/ US /æd.vɝːˈtaɪz.mənt/ informal ad, uk also infor ...

  5. [转帖]软件的变革与 AOT

    软件的变革与 AOT https://www.colabug.com/851475.html 文章写的很牛B .. 前言 AOT 即 Ahead of Time Compilation,即运行前编,与 ...

  6. App创意项目助跑计划

    APP创意项目助跑计划 该计划旨在帮助同学们将各种脑中稀奇古怪的想法借助互联网/移动互联网 相关的技术变成真实的项目. 谱写你的故事,从此刻开始! 我们帮助你提高编程(Java.C++.Objecti ...

  7. 备份服务器数据(IIS配置备份还原、任务计划、服务列表和APP)

    该脚本可以用来导出IIS配置.任务计划.服务列表和APP,同时支持Windows 2003和2008. #定义备份位置 $iisfolder = "d:\Backup_all\IIS&quo ...

  8. “数学口袋精灵”App的第三个Sprint计划----开发日记(第十一天12.17)

    项目进度: 基本完成一个小游戏,游戏具有:随机产生算式,判断对错功能.通过轻快的背景音乐,音效,给玩家提供一个良好的氛围.  任务分配: 冯美欣:设计"数学口袋精灵"App图标.整 ...

  9. “数学口袋精灵”App的第三个Sprint计划----开发日记(第一天12.7~第十天12.16)

    “数学口袋精灵”第三个Sprint计划----第一天 项目进度: 基本完成一个小游戏,游戏具有:随机产生算式,判断对错功能.通过轻快的背景音乐,音效,给玩家提供一个良好的氛围.  任务分配: 冯美欣: ...

随机推荐

  1. MVC中使用AuthorizeAttribute做身份验证操作

    代码顺序为:OnAuthorization-->AuthorizeCore-->HandleUnauthorizedRequest 如果AuthorizeCore返回false时,才会走H ...

  2. 各种less开发工具

    less是前端开发CSS的神器,但如何让less代码语法高亮,智能提示,快速编译及格式化,这不是一般的IDE的less插件能做到.下面是我搜刮到的一些工具 Codekit - incident57又一 ...

  3. mac电脑Coding显示/隐藏文件

    苹果Mac OS X操作系统下,隐藏文件是否显示有很多种设置方法,最简单的要算在Mac终端输入命令.显示/隐藏Mac隐藏文件命令如下(注意其中的空格并且区分大小写): 显示Mac隐藏文件的命令:def ...

  4. eclipse查看 rt.jar 源码

    源码位置: %JAVA_HOME%/src.zip step1: step2: step3:

  5. Eclipse 安装对 Java 8 的支持

    Java 8 正式版今天已经发布了(详情),但最常用的 Java 开发工具 Eclipse 还没有正式发布对 Java 8 的支持.不过目前可以通过更新 JDT 来支持 Java 8.步骤如下: 菜单 ...

  6. C语言的struct/union字节对齐

    C语言的一大优势就是对内存空间的控制,当然,一般情况下对于开发人员来说都是透明的.看一个始终困扰初学者的问题:字节对齐! 先看四个重要的基本概念:1.数据类型自身的对齐值:对于char型数据,其自身对 ...

  7. 修改SVN账户密码的方法

        Case1:     在Eclipse 使用SVN 的过程中大多数人往往习惯把访问SVN 的用户名密码自动保存起来以便下次自动使用,不要再次手工输入,但是有些时候需要变更密码或者用户名,这时候 ...

  8. xhtml和css概述

    Xhtml和css概述 1.html的过渡到xhtml html与xhtml不是两种语言,它们是一种语言的不同阶段,有点类似于文言文和白话文之间的关系.因为网络技术的日新月异,html的不断改进,所以 ...

  9. sc7731 Android 5.1 LCD驱动简明笔记之二

    此篇笔记基于sc7731 - android 5.1,对lcd的framebuffer做一个简明笔记. 一共分为两大部分:第一部分,关于LCD的硬件方面的:第二部分,关于lcd核心处理(framebu ...

  10. 从零开始学android开发-项目打包发布

    右键项目 选择[android tools]-[export signed application package] 点击[next] 如果没有keystore可以选择[create new keys ...