闲谈
最近忙着研发产品,研究技术的时间愁呐,挤了半天也是因为需要这块才能静下心整理一下...
上面下了一个要求:新版本安装包体积要比之前的小。哎,优化之,记录之…
探讨
我们向苹果商店提交进行审核的文件是ipa文件,因此我们有必要研究一下ipa文件的构成。
IPA是 Apple 程序应用文件 iPhoneApplication 的缩写,
IPA文件实质上是一个ZIP压缩包, 包含三个部分:
- Payload
Payload文件夹下是对应程序的 .app目录,是程序的主程序。里面包含程序的全部资源和可执行文件。
- iTunesArtwork
实质上是一个无后缀名的png图片,用来在iTunes中显示图标。可以添加后缀.png查看相关图片。
- iTunesMetadata.plist
记录程序在苹果商店上的信息。
由上文我们可以得出可优化的地方必然在Payload中的程序.app中。
通过查看.app文件,可以发现:
- 字体、音频等文件存在.app中,大小没有任何改变(打包前后)
- 非Assets.xcassets图片也保存在.app中,大小没有改变(打包前后)
- Asserts.xcassets图片被保存在Assets.car中,资源体积变小
- 代码等文件转化为可执行文件
处理方式
+ 资源文件
- 删除无用资源
- 资源压缩
对于png图片,PC上使用pngout进行有损压缩,Mac上使用imageOptim无损压缩;对于声音文件压缩 Mac OS $ afconvert -f AIFC -d ima4 sound.cf);对于其它文件可使用压缩包,第一次安装解压缩
- 不常用资源改为下载
+ 可执行文件
- 删除无用代码
- 删除默认方法(如UIView默认为透明,不需要设置clearColor)
- 删除重复代码
- C函数进行类封装
- 减少冗余字符串
- 混淆类/方法
- ARC -> MRC
+ 优化编译选项
- BuildSettings->Optimization Level,Xcode默认设置为“Fastest ,Smallest”,保持默认即可。
- Build Settings-> Linking->Dead Code Stripping 设置成 YES
- Deployment Postprocessing 设置成YES
- Strip Linked Product 设置成YES
- 工程的Enable C++ Exceptions和Enable Objective-C Exceptions选项都设置为NO。手动管理异常。
- symbols hidden by default选项设置为YES。
- 所有没有使用C++动态特性的lib库(搜索工程没有使用dynamic_cast关键字) Enable C++ Runtime Types 选项设置为NO。
- 若最低适配 iOS8.0 可直接抛弃32位
+ 其它方式
- JSPatch插件化(TPatch)
有一些是看似有理,但还想不通的地方,找些资料大家一起分享一下:
- 无用代码
在项目里新建一个类,给它添加几个方法,但不要在任何地方import它,build完项目后观察linkmap,你会发现这个类还是被编译进可执行文件了。
按C++的经验,没有被使用到的类和方法编译器都会优化掉,不会编进最终的可执行文件,但Objective-C不一样,因为Objective-C的动态特性,它可以通过类和方法名反射获得这个类和方法进行调用,所以就算在代码里某个类没被使用到,编译器也没法保证这个类不会在运行时通过反射去调用,所以只要是在项目里的文件,无论是否又被使用到都会被编译进可执行文件。
- 类/方法名长度
观察linkmap可以发现每个类和方法名都在__cstring段里都存了相应的字符串值,所以类和方法名的长短也是对可执行文件大小是有影响的,原因还是Objective-C的动态特性,因为需要通过类/方法名反射找到这个类/方法进行调用,Objective-C对象模型会把类/方法名字符串都保存下来。
对此我们可以考虑在编译前把所有类和方法名进行混淆,跟压缩js一样,把长名字替换成短名字,这样做的好处除了缩小体积外,还对安全性有很大提升,别人拿到可执行文件对它class-dump出来的结果都是混淆后的类和方法名,就无法从类和方法名中猜出某个方法是做什么的,就难以挂钩子进行hack。不过这样做有个缺点,就是crash堆栈反解出来的堆栈方法名会是混淆后的,需要再加一层混淆->原名的转换,实现和使用成本有点高。
实际上这部分占用的长度比较小,中型项目也就几百K,对安全性要求高的情况可以试试。
- 冗余字符串
代码上定义的所有静态字符串都会记录在在可执行文件的__cstring段,如果项目里Log非常多,这个空间占用也是可观的,也有几百K的大小,可以考虑清理所有冗余的字符串。另外如果有特别长的字符串,建议抽离保存成静态文件,因为AppStore对可执行文件加密导致压缩率低,特别长的字符串抽离成静态资源文件后压缩率会比在可执行文件里高很多。
参考资料
- http://www.cocoachina.com/ios/20150202/11084.html
- http://blog.csdn.net/zhengyanfeng1989/article/details/52537360
- http://baike.baidu.com/item/IPA/4653516#viewPageContent