flutter release 版本 调试_Flutter 应用混淆(包体积优化实践)

大规模应用开发过程中,性能管理是重中之重,其中就包括启动速度,交互等多个方面的优化,应用包大小和渲染性能也是很重要的衡量指标。当我们提到性能时,也无外乎运行时间占用空间这两个话题。

本篇文章,我们主要探讨的就是如何解决应用程序包大小的问题

应用程序大小

应用的大小是开发者和用户都能够直接感知的指标。作为开发者,我们清楚地知道 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 三种二进制文件。

305869ee85839e32e47ce12a76f5ce56.png

因此,各大 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 包:

  • /build/app/outputs/apk/release/app-armeabi-v7a-release.apk
  • /build/app/outputs/apk/release/app-arm64-v8a-release.apk
  • /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,则还需要指定目标平台架构,可以如下这些命令:

flutter build apk --target-platform android-arm --analyze-size 
flutter build apk --target-platform android-arm64 --analyze-size 
flutter build apk --target-platform android-x64 --analyze-sizeflutter build appbundle --target-platform android-arm --analyze-size 
flutter build appbundle --target-platform android-arm64 --analyze-size 
flutter build appbundle --target-platform android-x64 --analyze-size

运行结果如下:

d922a5ea4ddd9df217993225523d07c0.png
9574066db686515019de3ec4e55c87c8.png

该命令主要有两个作用:

  1. 在编译 Dart 代码时会记录 Dart packages 中代码大小的使用情况。
  2. 输出应用大小相关的具体细节,并将结果最终保存在 *-code-size-analysis_*.json 文件中供我们使用 DevTools 做进行分析。

如上图,终端中已经展示了项目中每项所占的空间大小,也可以通过 json 文件,使用 Dart DevTools 工具继续做更深入的分析(https://flutter.dev/docs/development/tools/devtools/overview)。

b1ea9bfd58f690528bcc09b33c6c0a3b.png
Example breakdown of app in DevTools

应用混淆

代码混淆 (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):

    修改 /android/app/build.gradle 文件:

    buildTypes {
        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  文件:

    ## 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:

    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 分支中支持),如下:

flutter build apk --obfuscate --split-debug-info=//

混淆成功后,需要保存符号映射表,以便以后需要去混淆跟踪代码堆栈。

相关命令的其他信息,可以运行 flutter build apk -h 查看,如果不支持该命令,核实 Flutter 版本,执行 flutter upgrade 更新。

读取混淆堆栈

要调试混淆后的应用,可以执行以下两个步骤:

  1. 找到符号映射表文件。如在 Android arm64 下发生 crash,可以分析 app.android-arm64.symbols 文件。
  2. 运行 flutter symbolize 命令,并指定堆栈跟踪的文件和符号映射表文件即可:
flutter symbolize -i  -d /out/android/app.android-arm64.symbols

关于 symbolize 命令的详细信息,可以运行 flutter symbolize -h 查看。

下一步

使用 Flutter 支持的代码混淆功能后,一定会在程度上减少应用程序的总大小,但这仅仅是应用优化中一个小小的环节,有关 Flutter 应用运行效率、UI 渲染相关的更多优化问题将会在之后的文章逐一探讨。

延伸阅读 [1]

Measuring your app’s size: https://flutter.dev/docs/perf/app-size

[2]

Obfuscating The Flutter App: https://medium.com/flutterdevs/obfuscating-the-flutter-app-80a190ed7540

[3]

Reducing Flutter App Size: https://itnext.io/reducing-flutter-app-size-570db9810ebb

[4]

Build and release an Android app: https://flutter.dev/docs/deployment/android

[5]

Obfuscating dart code: https://flutter.dev/docs/deployment/obfuscate