ios开发app瘦身

来源:互联网 发布:一句话网络段子精选 编辑:程序博客网 时间:2024/05/23 19:18

缩减iOS安装包大小是很多中大型APP都要做的事,一般首先会对资源文件下手,压缩图片/音频,去除不必要的资源。这些资源优化做完后,我们还可以尝试对可执行文件进行瘦身,项目越大,可执行文件占用的体积越大,又因为AppStore会对可执行文件加密,导致可执行文件的压缩率低,压缩后可执行文件占整个APP安装包的体积比例大约有80%~90%,还是挺值得优化的。下面介绍一下在研究可执行文件过程中发现的可以优化的点。研究的过程使用了linkmap,linkmap的介绍跟生成可以参考另一篇文章—iOS可执行文件的组成。

编译选项

1.编译器优化级别

Build Settings->Optimization Level有几个编译优化选项,release版应该选择Fastest, Smalllest,这个选项会开启那些不增加代码大小的全部优化,并让可执行文件尽可能小。

2.去除符号信息

Strip Debug Symbols During Copy 和 Symbols Hidden by Default 在release版本应该设为yes,可以去除不必要的调试符号。Symbols Hidden by Default会把所有符号都定义成”private extern”,具体意思和作用我还不清楚,有待研究,但设了后会减小体积。这些选项目前都是XCode默认选项,但旧版XCode生成的项目可能不是,可以检查一下。

其他优化还可以参考苹果的官方文档—CodeFootprint.pdf

第三方库统计

项目里会引入很多第三方静态库,如果能知道这些第三方库在可执行文件里占用的大小,就可以评估是否值得去找替代方案去掉这个第三方库。我们可以从linkmap中统计出这个信息,我写了个node.js脚本,可以通过linkmap统计每个.o目标文件占用的体积和每个.a静态库占用的体积,并进行排序。详见这里(需翻墙)。

ARC->MRC

有人提出用ARC写的代码编译出来的可执行文件是会比用MRC大的,原因大致是ARC代码会在某些情况多出一些retain和release的指令,例如调用一个方法,它返回的对象会被retain,退出作用域后会被release,MRC就不需要,汇编指令变多,机器码变多,可执行文件就变大了。还有其他细节实现的区别,先不纠结了。

那用ARC究竟会增大多少体积?我觉得从汇编指令的增多减少去算是很难算准确的,这东西涉及细节太多,还是得从统计的角度计算。做了几个对比试验,统计了几个同时支持ARC/MRC的开源项目在开启/关闭ARC的情况下__TEXT代码段的大小对比。只对比__TEXT代码段是因为:

ARC对可执行文件大小的影响几乎都是在代码段

可执行文件会进行某种对齐,例如有些段在不足32K的时候填充0直到对齐32K,若用可执行文件大小对比结果可能是对齐后的,不准确。

实验数据:

360桌面截图20150202094249.jpg

结果是ARC大概会使代码段增加10%的size,考虑代码段占可执行文件大约有80%,估计对整个可执行文件的影响会是8%。

可以评估一下8%的体积下降是不是值得把项目里某些模块改成MRC,这样程序的维护成本上升了,一般不到特殊情况不建议这么做。

无用代码

在项目里新建一个类,给它添加几个方法,但不要在任何地方import它,build完项目后观察linkmap,你会发现这个类还是被编译进可执行文件了。

按C++的经验,没有被使用到的类和方法编译器都会优化掉,不会编进最终的可执行文件,但object-c不一样,因为object-c的动态特性,它可以通过类和方法名反射获得这个类和方法进行调用,所以就算在代码里某个类没被使用到,编译器也没法保证这个类不会在运行时通过反射去调用,所以只要是在项目里的文件,无论是否又被使用到都会被编译进可执行文件。

对此我们可以通过脚本,遍历整个项目的文件,找出所有没有被引用的类文件和没有被调用的方法,在保证没有其他地方动态调用的情况下把它们去掉。如果整个项目历时很长,历时代码遗留较多,这个清理对可执行文件省出的空间还是挺可观的。

类/方法名长度

观察linkmap可以发现每个类和方法名都在__cstring段里都存了相应的字符串值,所以类和方法名的长短也是对可执行文件大小是有影响的,原因还是object-c的动态特性,因为需要通过类/方法名反射找到这个类/方法进行调用,object-c对象模型会把类名,方法名列表都保存下来。

可以考虑在编译前把所有类和方法名进行混淆,把长名字替换成短名字,这样做的好处除了缩小体积外,还对安全性有很大提升,别人拿到可执行文件对它class-dump出来的结果都是混淆后的类和方法名,就无法从类和方法名中猜出某个方法是做什么的,就难以挂钩子进行hack。不过这样有个缺点就是crash堆栈反解出来的堆栈方法名会是混淆后的,需要再加一层混淆->原名的转换,实现和使用成本有点高。

实际上这部分占用的长度比较小,中型项目也就几百K,对安全性要求高的情况可以试试。

冗余字符串

代码上定义的所有静态字符串都会记录在在可执行文件的__cstring段,如果项目里Log非常多,这个空间占用也是可观的,也有几百K的大小,可以考虑清理所有冗余的字符串。另外如果有特别长的字符串,建议抽离保存成静态文件,因为AppStore对可执行文件加密导致压缩率低,特别长的字符串抽离成静态资源文件后压缩率会比在可执行文件里高很多。

CheckList

最后简单把缩减iOS安装包大小的各种方法列出来作为CheckList:

安装包大小优化.png

转载出处:http://www.cocoachina.com/ios/20150202/11084.html


从09年开始做iPhoneDev到现在刚好3年时间,那个时候还在北京的一家公司实习,从OC语法开始自学,你可以看到周围的人在用iPhone3GS,但没人懂OC、很少人用过Mac系统。一路过来有cocoachina、stackoverflow、iphonedevsdk等出名站点的帮助,收获不少。现在,自己正处在角色的转型,对自己这3年来的iPhone开发在不停的思考着,整理成文档,希望自己的经验能够对CC朋友有所帮助。有错误的地方和任何问题,请毫不犹豫的指出。

 

这个帖子整理App大小优化的经验。

之前看过阿里UED的一篇文章“App瘦身记”,是从UED的角度来看待减小App大小,前面3点是建议,后面2点是瘦身办法。

我来说一下我的经验。大致的思路是:分析Xcodebuild目录下xx.app的资源,按从大到小排序,重点优化大文件。这个方法效果最好,能够让app瘦身50%以上,也就是减小用户一半的下载时间。

查看生成的app大小

Debug和Release编译模式产生的文件大小是不一样的,Debug模式生成的xx.app要大些。建议用Release模式生成的xx.app来分析,这个是最接近提交审核的IAP。

产品上线后显示在AppStore上程序的大小是经过压缩的。可以手动压缩xx.app,查看生成的xx.zip的大小,这个是最接近产品上线后的大小。

产品上线后iTunes显示的大小: 

开始瘦身

右键点击xx.app查看包的内容,按大小排序。

 

可以看到最占用空间的那些文件,一般是png文件占用的空间比较大,特别是iPad3视网膜的启动画面,可以大到7MB!如果app支持横竖屏,那么启动画面文件的大小又增加1倍。

这里列出常见的大文件:

1、可执行文件

2、启动画面 (比如:iPad 3 Retina)

3、背景图片

4、阿里UED里提到的Workthrough (这个在国内app很常见)

5、第三方库的bundle包、说明文件

6、音效素材 (比如:wav格式文件)

优化方法有:

1、不需要透明的地方,使用jpg而不是png。比如:背景图片、Workthrough、bundle里面的png文件,jpg压缩比使用0.6左右,在不影响视觉效果的情况下尽可能的小;

2、不使用Default.png,使用Default.jpg。苹果限制启动画面只能是png格式,iPad3 Retina的png文件往往都很大。这种情况下可以在app启动时显示Default.jpg,等到载入完毕后再显示首页。该方式的缺点是启动时会有黑屏然后才显示Default.jpg;优点是大大减小app大小,以及可自定义启动画面。比如UC浏览器HD在伦敦奥运会期间更换的启动画面;

3、素材做成可拉伸,类似Android的.9。界面导航条背景、弹框背景、按钮等都可以考虑用拉伸素材;

4、去除不必要的文件。一般开发时都有统一的通用库,方便其它工程调用,节省开发时间。把常用的库集成到通用库里会造成通用库体积变大,应该注意不必要的资源不要添加进去。比如:在发布的时候,TestFlight可以不用编译;第三方库的说明文件不要引入工程,Flurry的txt、pdf文件;如果付费版本不需要广告,那么广告SDK不要集成到通用库,只在单独的工程里引用;

5、优化png, jpg素材。推荐使用ImageOptim,在准备提交审核前,使用该工具优化所有png, jpg素材。可以减小~20%左右的图片大小。但png素材在Xcode编译后体积跟优化前的差不多,这个应该跟Xcode的优化方式有关;

6、音视频素材最好使用经过压缩的格式。wav的音频格式生成的文件比较大,可以使用苹果推荐的caf格式代替。关于如何选择音频压缩格式可以参考这篇文章:Audio101 for iPhone Developers: File and Data Formats。

在第一次产品提交审核前,可以过一下上面提到的方法,减小App大小。我们的一个产品PhotoCool 1.2版本的大小是22.4MB,在1.3版本使用以上方法进行优化,优化后只有13.1MB,缩小了41.5%!下载速度快了,用户会更高兴的。

社区原帖:http://www.cocoachina.com/bbs/read.php?tid=113863

资源过多,容易导致APP的包太大,会加重上传和下载的负担,所以有的时候需要做一些优化

  1. 不透明的大图片压缩成JPG格式
  2. 大的背景图片如果一定要是png的,可以用photoshop 把它保存为web格式的图片,压完之后注意看一下,有没有太大的失真。
  3. 删除不必要的字体,如果一定要,可以考虑使用 ios api (未验证)http://blog.csdn.net/bingowxd/article/details/16848595
  4. 把product 里面的文件 使用“显示包内容”方式,按照文件大小排序,查看打完包后具体是哪些图片占用太多的空间,并针对性地优化


tips:

  1. photoshow 有动作录制回放功能,可以把相同的操作用快捷键完成,不会使用请百度谷歌
  2. png压缩成jpg,代码里面需要做一些特殊的更改。考虑到一般使用 [UIImage imagewithname:@"name.png"], 新建一个类,继承自UIImage,重写image named:方法,把name方法改成能够识别 jpg、JPG、png、PNG以及@2x,代码附在后面
  3. Xcode编译如果遇到重复的文件,报错,但不影响编译通过,解决办法就是把重复的文件删除就行了
  4. 我使用的软件 Dedupo:去掉重复的文件 EazyBatchPhoto: 图片格式转换,可 png 和 jpg 互转 photoshop:当EazyBatchPhoto压缩不理想,使用保存为web格式。

.h 文件
[objc] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #import <UIKit/UIKit.h>  
  2.   
  3. @interface DSImageForExtention : UIImage  
  4.   
  5. @end  
.m 文件
[objc] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #import "DSImageForExtention.h"  
  2.   
  3. @implementation DSImageForExtention  
  4.   
  5. + (UIImage *)imageNamed:(NSString *)name  
  6. {  
  7.     NSString *imgName = nil;  
  8.     if ([super imageNamed:name]) {  
  9.         return [super imageNamed:name];  
  10.     }  
  11.     else  
  12.     {  
  13.         imgName = name;  
  14.         if ([imgName hasSuffix:@"jpg"]) {  
  15.             imgName = [imgName stringByReplacingOccurrencesOfString:@"jpg" withString:@"png"];  
  16.             if (![super imageNamed:imgName]) {  
  17.                 imgName = [imgName stringByReplacingOccurrencesOfString:@".png" withString:@".@2x.png"];  
  18.             }  
  19.         }  
  20.         else if ([imgName hasSuffix:@"png"]) {  
  21.             imgName = [imgName stringByReplacingOccurrencesOfString:@"png" withString:@"jpg"];  
  22.             if (![super imageNamed:imgName]) {  
  23.                 imgName = [imgName stringByReplacingOccurrencesOfString:@".jpg" withString:@".@2x.jpg"];  
  24.             }  
  25.         }  
  26.     }  
  27.     return [super imageNamed:imgName];  
  28. }  
  29.   
  30. @end  
注:因为这个代码是根据自己的项目定制的,使用的时候请根据实际情况修改

使用方法
[objc] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. [[UIImageView alloc] initWithImage:[DSImageForExtention imageNamed:@"hello@2x.png"]];  



0 0
原创粉丝点击