大规模应用开发过程中,性能管理是重中之重,其中就包括启动速度,交互等多个方面的优化,应用包大小和渲染性能也是很重要的衡量指标。当我们提到性能时,也无外乎运行时间和占用空间这两个话题。
本篇文章,我们主要探讨的就是如何解决应用程序包大小的问题。
应用程序大小
应用的大小是开发者和用户都能够直接感知的指标。作为开发者,我们清楚地知道 APK 文件、App Bundle 或者 IPA 之类的安装包中包含了应用代码、资源文件以及运行时的所有内容,如果体积过大,则对性能影响会造成非常大的影响,不仅会占用更多空间,也可能会无法使用一些特色功能,如 Android instant apps。
默认情况下,为了支持热重载和代码级调试等功能,debug 版本的安装包会天然具有较大体积,性能优化时,可以忽略这种情况。
在 Android Studio 中,打开任意 Flutter 项目,使用 flutter build apk --release
构建安装包之后,点击 Build >> Analyze Apk
,会发现 lib 目录的大小占整个包大小的 95% 以上,并且其中默认编译出来的 APK 包含有 android-arm,android-arm64,android-x64 三种二进制文件。
因此,各大 Android 应用商店的或者 App Store 接收到包之后还会做进一步处理,如根据用户的机型过滤掉一些 native 库、DPI 等。官方也推荐我们使用 flutter build appbundle
构建 Android App Bundle(.aab) 文件,具体请看 https://developer.android.com/platform/technology/app-bundle。
对于不支持自动拆解 App Bundles 的厂商,我们可以直接使用 flutter build apk --split-per-abi
直接编译出各平台下的拆分 APK 包:
<app dir>/build/app/outputs/apk/release/app-armeabi-v7a-release.apk
<app dir>/build/app/outputs/apk/release/app-arm64-v8a-release.apk
<app dir>/build/app/outputs/apk/release/app-x86_64-release.apk
下面,我们也可以使用最新的开发工具检查和估算 Flutter 应用程序的具体大小…
优化包体积
Flutter 1.22 之后,官方发布了一款应用包大小的分析工具,可以帮助开发者直观地看到应用各个模块占用空间大小的详细信息。我们只需要在构建应用时传入 --analyze-size
参数即可使用该分析工具:
flutter build apk --analyze-size
flutter build appbundle --analyze-size
flutter build ios --analyze-size
flutter build linux --analyze-size
flutter build macos --analyze-size
flutter build windows --analyze-size
如果构建的是 Android APK 或 bundle,则还需要指定目标平台架构,可以如下这些命令:
1 | flutter build apk --target-platform android-arm --analyze-size |
运行结果如下:
该命令主要有两个作用:
- 在编译 Dart 代码时会记录 Dart packages 中代码大小的使用情况。
- 输出应用大小相关的具体细节,并将结果最终保存在
*-code-size-analysis_*.json
文件中供我们使用 DevTools 做进行分析。
如上图,终端中已经展示了项目中每项所占的空间大小,也可以通过 json
文件,使用 Dart DevTools 工具继续做更深入的分析(https://flutter.dev/docs/development/tools/devtools/overview)。
应用混淆
代码混淆 (Obfuscated code) 亦称花指令,是将计算机程序的代码,转换成一种功能上等价,但是难于阅读和理解的形式的方式。通常针对的是二进制文件。实际使用中将可以代码中的各种元素,如变量,函数,类的名字改写成无意义的名字,防止攻击者会应用逆向。
——维基百科
要混淆 Flutter 应用程序,首先需要适配不同平台的版本:
android /iOS:Flutter 1.16.2 以后支持。
macOS:macOS(Flutter 1.13 发布测试版)也支持在 Flutter 1.16.2 版本后混淆。
Linux / Windows:不支持
Flutter Web:不支持
本篇文章,我们主要介绍如何混淆 Dart 代码,关于减少应用大小,我们也可以尝试如下几种方法:
删除未使用的资源(Resource Shrinking)。
压缩从三方库导入的资源。
混淆原生代码(java):
修改
<app dir>/android/app/build.gradle
文件:1
2
3
4
5
6
7buildTypes {
release {
minifyEnabled true // add this
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // add this
signingConfig signingConfigs.release // this is default for release
}
}创建
proguard-rules.pro
文件:1
2
3
4
5
6
7
8
9
10## Flutter wrapper
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
# -keep class com.google.firebase.** { *; } // uncomment this if you are using firebase in the project
-dontwarn io.flutter.embedding.**
-ignorewarnings`gradle.properties:
1
extra-gen-snapshot-options=--obfuscate
压缩 PNG 和 JPEG 等资源文件。
删除不必要的第三方库。
使用 .svg 格式的图标。
Flutter 应用混淆
Flutter 应用的混淆非常简单,只需要在构建 release 版应用时结合使用 --obfuscate
和 --split-debug-info
这两个参数即可。
--obfuscate --split-debug-info
用来指定输出调试文件的位置,该命令会生成一个符号映射表。目前支持 apk,appbundle,ios 和 ios-framework 等目标平台(macOS 和 aar 在 master 和 dev 分支中支持),如下:
1 | flutter build apk --obfuscate --split-debug-info=/<project-name>/<directory> |
混淆成功后,需要保存符号映射表,以便以后需要去混淆跟踪代码堆栈。
相关命令的其他信息,可以运行 flutter build apk -h
查看,如果不支持该命令,核实 Flutter 版本,执行 flutter upgrade
更新。
读取混淆堆栈
要调试混淆后的应用,可以执行以下两个步骤:
- 找到符号映射表文件。如在 Android arm64 下发生 crash,分析
app.android-arm64.symbols
文件。 - 运行
flutter symbolize
命令,并指定堆栈跟踪的文件和符号映射表文件:
1 | flutter symbolize -i <stack trace file> -d /out/android/app.android-arm64.symbols |
关于 symbolize 命令的详细信息,可以运行
flutter symbolize -h
查看。
下一步
使用 Flutter 支持的代码混淆功能后,一定会在程度上减少应用程序的总大小,但这仅仅是应用优化中一个小小的环节,有关 Flutter 应用运行效率、UI 渲染相关的更多优化问题将会在之后的文章逐一探讨。
延伸阅读
Build and release an Android app
关注公众号「Meandni」,及时阅读最新前沿技术动态,不至于落后时代。