一、包体积对用户的影响
更小的包体积能提升用户下载意愿,且通常也意味着更快的启动速度,提升用户体验。下面来看一个2017年Google Play的研究报告:
APK
大小每增加6MB,安装转化率就会下降1%APK
大小约为10MB的应用的下载完成率将比APK
大小为100MB的应用高出约30%- 由于担心数据流量和手机存储空间,2017年数据约70%的新兴市场(中东、非洲和东南亚)用户在下载应用程序之前会考虑其大小。 这对于国际化APP来说包大小尤为重要。
如上图,假设您的应用在印度每月获得 10,000 次安装,转化率为 20%,那么减少 10MB 可以带来每月额外的约 1,140 次安装。(2017)
二、iOS包大小衡量
2.1 关注安装大小和下载大小
安装大小就是appstore上用户下载时看到的大小,也是安装后占用的磁盘空间。
下载大小是从appstore下载的大小。Appstore
对使用蜂窝网络下载APP有限制,如果APP的下载大小超过限制(iOS 12.4之后是200MB),iOS 13
之前只能通过 Wi-Fi 网络下载;iOS 13
之后默认会弹框让用户选择是否使用蜂窝网络下载下载,用户可在设置中更改。
2.2 开发期间衡量APP大小
在 App Store Connect
中可以选择一个上传的构建版本,查看到发布后各个设备上的APP包大小
。但是需要先上传然后等待苹果处理,操作麻烦且需要等待,那么有没有在开发期间能准确预估APP大小的方式呢?
答案是有的,苹果提供了两种方式。
- 方式一
是通过Xcode
打包导出ipa,这个时候会包含一个App Thinning Size Report.txt文件,通过这个文件可以查看到一个相对准确的预估,样式如下:
App Thinning Size Report for All Variants of ExampleApp
Variant: ExampleApp.ipa
Supported variant descriptors: [device: iPhone11,4, os-version: 12.0], [device: iPhone9,4, os-version: 12.0], [device: iPhone10,3, os-version: 12.0], [device: iPhone11,6, os-version: 12.0], [device: iPhone10,6, os-version: 12.0], [device: iPhone9,2, os-version: 12.0], [device: iPhone10,5, os-version: 12.0], [device: iPhone11,2, os-version: 12.0], and [device: iPhone10,2, os-version: 12.0]
App + On Demand Resources size: 6.7 MB compressed, 18.6 MB uncompressed
App size: 6.7 MB compressed, 18.6 MB uncompressed
On Demand Resources size: Zero KB compressed, Zero KB uncompressed
- 方式二:
通过脚本的方式指定输出App Size
报告:
xcodebuild -exportArchive -archivePath iOSApp.xcarchive -exportPath Release/MyApp -exportOptionsPlist OptionsPlist.plist
三、具体的做法
根据包体积的构成按如下思路进行细化
下面分别讲述具体的改法:
3.1 无用/重复代码清理
这类代码大体的分布会是:未使用代码、Debug下才使用的代码、多个库都有一份。
- 未使用代码
最好是项目中迭代的时候就约定了不使用的代码在开发时清除,并且在codereview时把关;如果是老项目,那么可以使用APPCode进行扫描
- Debug下才使用的代码
对于某一段代码debug
下才执行,要注意使用Debug
宏;对于debug
下才使用的库,可以在Podfile
中写明:
# 1.Podfile中可以配置库只在debug下集成,
target 'TargetName' do
pod '某库名', '~> 1.1.7', :configurations => ['Debug']
...
end
- 重复代码在多个库有一份 这种情况下其实不说也应该知道,只能是跟库维护者协调将文件下沉。
3.2 动态库改静态库
动态库是运行时链接的库,就是在APP启动的时候链接的库,这类库在ipa包中的Frameworks
文件夹中; 静态库是编译期间就链接好库。静态库相对于动态库在最终打包的ipa中会占用更小体积,动态库中引用的其他库的符号会占用额外的空间,但是改为静态库之后,各个静态库和主工程引用的相同的符号就会转为跟主工程一样,只占用额外的一份空间。
动态库改为静态库的方式有两个,一个是在库的.podspec
文件中声明spec.static_framework = true
; 另外一个是在Podfile
中全局改为静态链接use_frameworks! :linkage => :static
但是动态库全部改为静态库后,可能会产生符号冲突,需要手动解决好。 如果对于动态库和静态库有疑问,可以查看文章iOS 动态库与静态库基础
3.3 资源图片处理
- 使用
Asset Catalog
来管理图片:因为这样能享受到APP Thining
和苹果压缩算法持续优化的好处. - 无用资源清理:可以使用LSUnusedResource工具进行未使用资源检查清理。重复资源需要自己开发中发现后处理。
- 图片压缩:目前来看使用ImageOptim工具来压缩比较方便.
- 更小体积的图片格式:比如使用HEIC、或者webP图片,但是使用webP图片会需要引入解码库。下面是HEIC图片转换,转换后可以直接拖到Imageassets中,跟PNG图标一样使用。
选中图标右键转换图像 | 选择HEIF格式(HEIC是HEIF格式的一个静态样式) |
---|---|
- 资源按需加载:也就是图片放到后台。
3.4 编译设置优化
编译设置优化推荐在Podfile
中修改控制,这样更方便使Pod
库也生效。这里直接贴出一些有效的写法,其中的原因网上文章已经写得很清楚详细了,可以参考阅读下面文章。
# pod安装时会执行的hook函数
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if config.name == 'Release'
# swift编译优化级别
config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Osize'
config.build_settings['SWIFT_COMPILATION_MODE'] = 'wholemodule'
# GCC编译优化级别
config.build_settings['GCC_OPTIMIZATION_LEVEL'] = 'z'
config.build_settings['LLVM_LTO'] = 'YES_THIN'
# 打包后裁剪不必要的符号
config.build_settings['STRIP_INSTALLED_PRODUCT'] = 'YES'
config.build_settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf-with-dsym'
end
end
end
end
此外还有个主工程对外暴露符号Exported Symbols File
可以设置一个为空文件,对主工程来说不需要对外暴露符号。
设置为空文件之后,通过MachOview
来查看,可以看到主工程可执行文件的Exprot info
这一个节的数据为空。
参考文章: