在产品的运营期间,我们发现Android用户对App容量大小的敏感度明显高于iOS用户。
所以,为了提升产品在市场中竞争力,进一步提升产品的下载量,我们需要对基于Flutter开发的Android客户端进行包体优化。
经过调研,我们发现Flutter经过多年的发展后,DevTools已经完善,用较低的低成本即可满足需求。
下面我们会从分析开始,了解不同构成部分的容量分布情况。再对构成部分的特性来决定最终如何进行包体优化。
生成分析报告
首先,在build产物时,我们可以加上 --analyze-size
标识来生成分析报告。apk 和 appbundle 还可以指定产物的平台架构,如:--target-platform android-arm
,分析实际机型的情况。
# 变异产物
# Specify one of android-arm, android-arm64, or android-x64 in the --target-platform flag.
flutter build apk --analyze-size --target-platform android-arm64
flutter build appbundle --analyze-size --target-platform android-arm64
apk 分析日志
app-release.apk (total compressed) 33 MB
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
assets/
dexopt 1 KB
flutter_assets 5 MB
classes.dex 7 MB
lib/
arm64-v8a 18 MB
Dart AOT symbols accounted decompressed size 8 MB
package:flutter 3 MB
package:image 799 KB
dart:core 325 KB
package:xxx_xxx_flutter 293 KB
dart:ui 279 KB
dart:typed_data 226 KB
dart:io 212 KB
dart:collection 177 KB
package:vector_graphics_compiler 170 KB
dart:async 154 KB
package:flutter_localizations 129 KB
package:flutter_spinkit 99 KB
package:extended_image 93 KB
dart:ffi 85 KB
package:petitparser 73 KB
dart:convert 62 KB
package:archive 62 KB
package:dio 57 KB
package:vector_math 54 KB
package:riverpod 49 KB
AndroidManifest.xml 3 KB
res/
-j.png 4 KB
1k.png 33 KB
1r.png 91 KB
2M.png 3 KB
33.9.png 2 KB
3m.png 1 KB
4C.png 1 KB
4F.png 10 KB
AQ.png 33 KB
Bj.png 29 KB
CG.png 23 KB
Ch.png 98 KB
D2.png 14 KB
E7.png 98 KB
EA.png 98 KB
ER.9.png 2 KB
FM.9.png 1 KB
Fo.png 29 KB
G1.png 2 KB
J6.9.png 2 KB
JO.png 29 KB
Mr.9.png 1 KB
NF.png 6 KB
Ni.png 33 KB
ON.png 91 KB
Pi.9.png 3 KB
Q11.9.png 3 KB
RX.png 16 KB
S9.png 2 KB
SD.png 5 KB
Tu.png 10 KB
Vq.png 1 KB
Vw.png 71 KB
WR.png 30 KB
XU.png 1 KB
Yj.png 4 KB
_C.png 3 KB
_f.png 2 KB
bI.png 3 KB
color-v23 2 KB
color 16 KB
dn.png 2 KB
e1.xml 1 KB
eB.9.png 2 KB
fM.png 5 KB
fR.png 67 KB
gV.9.png 1 KB
jy.png 8 KB
nN.png 4 KB
qt.png 2 KB
tj.9.png 2 KB
u3.png 3 KB
wi.9.png 2 KB
wi1.9.png 1 KB
wn.png 10 KB
x4.png 3 KB
yT.png 1 KB
zT.png 91 KB
resources.arsc 926 KB
client_analytics.proto 1 KB
dc/
a.gz 37 KB
kotlin/
collections 1 KB
kotlin.kotlin_builtins 5 KB
ranges 1 KB
reflect 1 KB
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
A summary of your APK analysis can be found at: /Users/xxx/.flutter-devtools/apk-code-size-analysis_01.json
To analyze your app size in Dart DevTools, run the following command:
dart devtools --appSizeBase=apk-code-size-analysis_01.json
appbundle 分析日志
app-release.aab (total compressed) 18 MB
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
BUNDLE-METADATA/
assets.dexopt 1 KB
com.android.tools.build.libraries 8 KB
com.android.tools.build.obfuscation 628 KB
base/
assets 5 MB
dex 3 MB
lib 8 MB
Dart AOT symbols accounted decompressed size 8 MB
package:flutter 3 MB
package:image 799 KB
dart:core 325 KB
package:xxx_xxx_flutter 293 KB
dart:ui 279 KB
dart:typed_data 226 KB
dart:io 212 KB
dart:collection 177 KB
package:vector_graphics_compiler 170 KB
dart:async 154 KB
package:flutter_localizations 129 KB
package:flutter_spinkit 99 KB
package:extended_image 93 KB
dart:ffi 85 KB
package:petitparser 73 KB
dart:convert 62 KB
package:archive 62 KB
package:dio 57 KB
package:vector_math 54 KB
package:riverpod 49 KB
manifest 4 KB
res 1 MB
resources.pb 292 KB
root 51 KB
META-INF/
UPLOAD.SF 46 KB
UPLOAD.RSA 1 KB
MANIFEST.MF 34 KB
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
A summary of your AAB analysis can be found at: /Users/xxx/.flutter-devtools/aab-code-size-analysis_01.json
To analyze your app size in Dart DevTools, run the following command:
dart devtools --appSizeBase=aab-code-size-analysis_01.json
✓ Built build/app/outputs/bundle/release/app-release.aab (18.2MB).
解读分析报告
使用DevTools解读报告
这里以 VS Code DevTools 举例(Install and run DevTools from VS Code)
shift + cmd + p
打开命令面板,再输入Open DevTools
,打开面板。选择App Size Tooling,打开,并选择需要分析的文件,路径在生成报告时会提供(如:/Users/xxx/.flutter-devtools/aab-code-size-analysis_01.json)
以上图为例,appbundle在未压缩的情况下, 体积为23.1MB,其中base占据了主要的容量。
base中占据主要大小的分别有lib (8MB)、assest (5MB)、dex (3MB)、res (1.2MB)。
分析内容物可以得出:
- lib,Flutter端的代码实现以及依赖库。
- assets,Flutter端使用到的资源文件。
- dex,原生端的代码实现以及依赖库。
- res,原生端使用到的资源文件。
除去这些主要的文件内容,剩余的多位配置文件,所占容量的比例也不大,可优化空间不大。
可探索的优化方向
第一步,通过优化素材可以直接减少包体内容的大小。
降低视频素材的分辨率和质量
多使用jpg、svg等高压缩率的图片素材
使用IconFont替换icon的图片素材
使用网络素材,替换本地素材,比如使用网络图片/视频,网络素材包等。
使用GoogleFonts替代本地Fonts。
第二步,减少不必要的代码模块。
- 检查 pubspec.yaml 并删除未使用的库/包。
- 对第三方库进行精简定制,再引入使用,删除不需要的功能。
- 使用Flutter提供的精简代码功能,对产物代码进行重定义。
下面介绍下Flutter提供的精简代码功能。
精简代码
在build产物时,添加 --obfuscate
和 --split-debug-info
来实现对代码的混淆,以及对代码的精简。
--split-debug-info
,提取调试信息,实现精简代码,可单独使用。--obfuscate
,开启代码混淆,提高代码反编译门槛。
# 指定android-arm64平台,在当前路径输出符号表(如`app.android-arm64.symbols`)
flutter build appbundle --target-platform android-arm64 --split-debug-info=.
未精简的日志
flutter build appbundle --target-platform android-arm64
Running Gradle task 'bundleRelease'...
Font asset "MaterialIcons-Regular.otf" was tree-shaken, reducing it from 1645184 to 3124 bytes (99.8% reduction). Tree-shaking can be disabled by providing the --no-tree-shake-icons flag when building your app.
Running Gradle task 'bundleRelease'... 26.7s
✓ Built build/app/outputs/bundle/release/app-release.aab (18.2MB).
精简后的日志
flutter build appbundle --target-platform android-arm64 --split-debug-info=.
Running Gradle task 'bundleRelease'...
Font asset "MaterialIcons-Regular.otf" was tree-shaken, reducing it from 1645184 to 3124 bytes (99.8% reduction). Tree-shaking can be disabled by providing the --no-tree-shake-icons flag when building your app.
Running Gradle task 'bundleRelease'... 56.6s
✓ Built build/app/outputs/bundle/release/app-release.aab (17.6MB).
开启混淆的日志
flutter build appbundle --target-platform android-arm64 --split-debug-info=. --obfuscate
Running Gradle task 'bundleRelease'...
Font asset "MaterialIcons-Regular.otf" was tree-shaken, reducing it from 1645184 to 3124 bytes (99.8% reduction). Tree-shaking can be disabled by providing the --no-tree-shake-icons flag when building your app.
Running Gradle task 'bundleRelease'... 57.5s
✓ Built build/app/outputs/bundle/release/app-release.aab (17.6MB).
读取混淆的堆栈跟踪
如需要调试被混淆的应用程序创建的堆栈跟踪,请遵循以下步骤将其解析为可读的内容:
找到与应用程序匹配的符号文件。例如,在 Android arm64 设备崩溃时,需要
app.android-arm64.symbols
文件。向
flutter symbolize
命令提供堆栈跟踪(存储在文件中)和符号文件。例如:
flutter symbolize -i <stack trace file> -d out/android/app.android-arm64.symbols
总结
在素材和代码模块的两个方向上进行包体优化,是比较容易操作,并且不会影响App稳定性的方案。
在出包的工作流中,我们会启用精简代码以及代码混淆,优化产物中代码所占的体积。
排查已经引入的依赖库,看是否存在未使用或者已经弃用的多余依赖。同时分析占容量较大的三方依赖,判断是否需要通过精简定制来降低容量。
最终是排查素材,筛选体积,对不达标的素材进行重新制作,或者寻找替代方案,比如改用网络资源。