我们在用数据网络下载APP的时候,若是APP体积大于150MB,AppStore便会提示“此项目大于150MB,除非此项目支持增量下载,否则您必须连接至WiFi才能下载”。可见如果IPA安装包过大,是极不利于App推广的,那么我们今天的Topic:如何减少App体积?
最近我们产品由于运营需要接入了三方库,上线后App体积徒增,组内的同学关于IPA瘦身有一些实践和思考, 常规的方法如下图,不是本文重点讨论的内容,如需了解自行百度。
关于APP Architecture
由于历史原因我们APP Architecture设置一般都是arm64,armv7,arm7s,使用MochOView可以查看我们可执行文件支持的架构如图,其实我们的动态库也是Fat Header比如一个30M的MachO ,那么15Mb是64-bit,另外15Mb是32-bit:
通过整理可知armv7|armv7s|arm64都是ARM处理器的指令集,i386|x86_64 是Mac处理器的指令集表格如下:
通过上表可知32位设备离我们最近的已经是6年前的设备iPhone5了,如果不是超级APP完全有理由放弃支持armv7,armv7s架构,没必要让99%的用户为1%的用户浪费流量,这样我们的动态库和二进制可执行文件会减少50%的体积,另外在Xcode 9.0 release note里边有这样的描述,如果你支持到iOS 11则自动不支持32-bit,可见Apple也已经建议不支持32位。(Apps with a deployment target of iOS 11 no longer build a 32-bit slice. To build and include a 32-bit slice, set the deployment target to an earlier version of iOS.)另外如果使用pod管理依赖库,可以看到在Pods-covermedia-frameworks脚本中会通过strip_invalid_archs移除不需要支持的architectures,比如我们提交Appstore时如果动态库包含模拟器库会报错,再比如主MochO不支持32-bit那么pod库也会通过lipo -remove 32-bit slice。
Tips:放弃支持32-bit我们的IPA至少减小1/3
关于Swift
我们分别以Swift和ObjC新建一个空的Project然后Archive打包,发现Swift会比ObjC大大概400倍(当然这个不是Store App 最终size),究其原因是因为使用Swift构建的App需要包含支持Swift运行的系统动态库,在安装包内Framework文件夹下存放动态库如libswiftCore.dylib等等,只要有swift代码不管混编还是纯swift都会引入,我们无法左右也不可避免,我们相信在不久的将来随着Swift的稳定以及开发者的增加,这些包含在app内的swift core dylib会在iOS系统层面去处理。
关于Framework
我们以Swift新建一个空的工程通过Pod分别以静态库和动态库引入SnapKit,MJRefresh,通过use_frameworks!决定pod库以动态库还是静态库引入,这里有的同学可能会说Apple不支持包含Swift的静态库 ,我们等下再说这个问题,直接看对比分析表:
静态库在编译时就联入可执行文件,动态库以Framework放在IPA内,通过上表可见相同的库使用静态库会比动态库IPA更小,在iOS8以前,苹果只允许发布静态库,但是在iOS8苹果推出了APP extension的概念,可以对项目进行扩展 ,因为APP extension和主项目是两个独立的进程,为了共享代码,苹果允许我们创建动态库,即dynamic framework,在Xcode 9.0 以前Apple并不支持包含Swift的静态库,我们使用pod管理三方库只能使用通过use_frameworks!以动态库方式集成到Ipa内。
Tips:尽可能的以静态库的形式使用三方库,以减少体积,加快启动速度
Xcode 9.0 release note 里边提到(Xcode supports static library targets which contain Swift code). 随后在上个月CocoaPods 1.5.0发布更新(Swift static libraries can be used in targets whose search paths are inherited)那么到这里上边的疑问也就不是疑问了。
Note:Up until Xcode 9, support for building Swift into static libraries was non-existent and use of dynamic frameworks was required. This was a deal-breaker for some developers, particularly those worried about the launch performance implications of linked many dynamic binaries. With CocoaPods 1.5.0, developers are no longer restricted into specifying use_frameworks! in their Podfile in order to install pods that use Swift. Interop with Objective-C should just work. However, if your Swift pod depends on an Objective-C, pod you will need to enable "modular headers" (see below) for that Objective-C pod.
如果我们的app没有APP extension功能建议podfile去掉use_frameworks以静态库引用pod库,这样既可以缩小IPA文件大小又可以优化App启动时间(动态库在pre main前加载耗时在之前的文件有提过),很遗憾我在去掉use_frameworks后重新编译一些Swift三方库报错,暂不支持静态库。这不是重点,如果需要支持APP extension,那么就必须要使用动态库了,这里有国外一位大佬的使用Carthage的方案给我们提供一种思路,大概原理是将多个静态库编为一个动态库,这样在一定程度也可以缩小体积,缩短启动时间。
最后为了方便部分读者阅读理解这,里贴一下静态库动态库对比分析表
附相关资料 :
http://blog.cnbang.net/tech/2544/
How we cut our iOS app’s launch time in half
CocoaPods 1.5.0 — Swift Static Libraries
关于iOStips
「iOStips」,定时推送BAT一线圈的互联网资讯,成长感悟,高端主流技术干货,框架源码分析等文章。让你的职场生涯 不再孤单,不再迷茫!
「iOStips」,长期分享移动开发技术资料你想要的应有尽有只有你不想学的,没有你学不到的,公众号后台留下你的邮箱下列电子书任选一本送给你!
《iOS应用逆向工程(第2版)》
《Hacking.and.Securing.iOS.Applications》
《iOS_Security_Guide》
《Apress.OS.X.and.iOS.Kernel.Programming》
《Wrox Press Mac OS X and iOS Internals, To the Apple's Core》
《Wrox Press Mac OS X and iOS Internals, To the Apple's Core》
《Swift 4 Programming Cookbook》
《LLVM》
《剑指offer第二版》
《Objective-C编程之道:IOS设计模式解析》
《iOS安全攻防手记》在学习过程中自己的总结可能是全网最有深度的学习笔记
若干你需要的...