返回

杰哥的 APK 瘦身实战之旅

Android







各位观众老爷们,我是杰哥。作为一个吃遍大厂、独步江湖的移动江湖浪人,行走江湖多年,也见识了不少,这不,这次又来和大家聊聊一个江湖中的武林秘籍——APK 瘦身。

**前言** 

随着移动互联网的飞速发措,APP 开发也如火如荼,然而,随着APP 功能的不断增强,体积也是越来越庞大。一个庞大臃肿的APK给我们的生活带来诸多不便:

- 安装费时:现在网速再怎么快,也架不住动辄几百兆的 APK 安装包啊!
- 流量浪费:如果你在 4G 网络下,在一个小时内下了 1G 的 APK,那恭喜你,这个月话费稳稳的超支了!
- 用户体验差:作为一个 5G 时代的新新青年,谁还愿意忍受动不动就要等个几分钟的漫长等待呢?

一个轻量级的 APK 无论对开发者还是对终端使用者都有着非常重浚意义。好了,话不多说,闲话少叙,这秘籍在江湖中名唤“APK 瘦身**心** 经》,就让咱一步一步来看看这秘籍中是如何记载这“APK 瘦身**秘** 方”的吧。

**一、APK 瘦身之资源瘦身** 

**1、无用资源清理** 

* **清理无用 layout 布局** :使用 Android studio 的 Analyze 功能,筛选出无引用的 layout 布局,将其坚决**物理** delete。
* **清理无用 drawable 图片** :同样使用 Analyze 功能,找出从未引用的无用 drawable 图片,**物理** delete。
* **清理无用 anim 动画** :同上,找出无用 anim 资源,**物理** delete。
* **清理无用 style 布局** :同上,清理无用 style 资源,**物理** delete。

**2、资源大小优化** 

* **使用更高效的 图片格式** :充分运用 WebP 图片格式,相较于 PNG 图片,体积能缩小一半以上。
* **使用**  **Vector Drawable** :Vector Drawable 的可绘制尺寸不受限制,并且体积小,可以**替换** 掉部分大尺寸的 Bitmap Drawable。
* **使用**  **AdaptiveVector Drawable** :当需要兼容低版本的 Android SDK(不带 SVG 渲染引擎)时,可选择使用AdaptiveVector Drawable 来替代 Vector Drawable。
* **去除**  **9-patch** :9-patch 图片会导致 dex 体积变大,能**不用则不用*** **使用**  **View Binding** :View Binding 可以将 layout 中定义的 View 组件转化为常量,进而**避免** 了大量繁琐的 `findById()` 操作,减少了内存的开销。

**二、APK 瘦身之 Gradle 优化** 

**1、启用**  **minify**  **with Dex**  **Shrinker****app/build.gralde**  中启用 Dex 混淆:

```groovy
buildTypes {
    release {
        // 使用 Dex 混淆进行瘦身
        minifyWithDex = true
    }
}

2、使用 资源缩小

app/build.gralde 中启用资源缩小:

aaptOptions {
    // 启用资源缩小
    cruncherEnabled = true
}

3、使用 zipAlign

app/build.gralde 中启用 zipAlign 进行对齐优化:

buildTypes {
    release {
        // 启用 ZipAlign
        zipAlign {
            // 设置 ZipAlign 优化级别
            // isFaster 默认为 True
            isFaster = false
            // 设置 ZipAlign 顺序
            // isDeterministic 默认为 True
            isDeterministic = true
        }
    }
}

三、APK 瘦身之 dex 优化

1、方法计数混淆

app/build.gralde 中启用方法计数混淆:

buildTypes {
    release {
        // 启用方法计数混淆
        // minifyEnabled 默认为 True
        minifyEnabled = true
        // 启用混淆调试信息
        // 是否输出混淆后的文件
        // 默认值为 false
        debugInformationFile = 'output.txt'
        // 启用混淆报告
        // 是否输出混淆报告
        // 默认值为 false
        useProguard = true
        // 设置混淆规则
        useLegacyPackaging = true
        // 自动混淆,自动将不想混淆的类和成员抽出混淆规则
        // 默认值为 false
        // 如果该项设为 true,则 unsetMinify 默认为 True,必须要显式 set 为 False 才能禁用自动混淆
        optimizeResourcesForDexSize = true
    }
}

2、混淆规则优化

  • 舍弃无用的方法 :可以舍弃掉调试、日志、无用第三方库中用到的方法,将它们列入混淆规则中。
  • 混淆重载方法 :为重载方法指定混淆后的共同名字,可以减小冗余的 方法符 的长度。
  • 混淆私有方法 :混淆不含 public 访问权限的私有方法。

四、APK 瘦身之 SO 瘦身

1、裁剪 SO 库

app/build.gralde 中裁剪 SO 库:

android {
    // 裁剪 SO 库
    packagingOptions {
        excludeAssets */lib/armeab*
        excludeAssets */lib/arm64-v8a*
        excludeAssets */lib/mips*
        excludeAssets */lib/x86*
    }
}

2、拆分 SO 库

  • 根据分辨率进行拆分:可以按照不同的屏幕分辨率进行 SO 库的拆分,只将与屏幕分辨率相对应的 SO 库进行打包。
  • 根据 ABI 进行拆分:可以按照不同的 ABI 进行 SO 库的拆分,只将与终端机型 ABI 相对应的 SO 库进行打包。

五、APK 瘦身之性能优化

1、减少内存泄漏

  • 使用内存泄漏检测工具:使用 LeakCanaryMAT 等工具,在开发阶段就找出内存泄漏问题。
  • 正确使用软引用和强引用:软引用强引用 决定了缓存策略。
  • 避免使用大内存占用控件:比如 WebViewFragmentView 等控件。
  • 关闭不用的服务和广播:ServiceBroadcastReceiver 等组件在不使用时应立即关闭,以防止内存泄漏。

2、减少耗电量

  • 优化 UI 线程:避免在 UI 线程中进行耗时运算,使用 HandlerThread 等异步调度进行优化。
  • 优化动画:避免过度使用动画,使用 Property AnimationValue Animator 进行优化。
  • 关闭不用的后台线程:如果后台线程不再需要,应立即将其关闭,以防止内存泄漏和耗电。
  • 使用 JobScheduler 合理调度后台耗时性作业

六、APK 瘦身之实战经验

以上理论在 公司 App 中如何落地呢?举个栗子 :App 体积从 18MB -> 12MB,提速 33%:

瘦身前:

资源瘦身

  • 移除无用 layout 布局:21 个
  • 移除无用 style 布局:40 个
  • 移除无用 anim 动画:3 个
  • 移除无用 drawabale 图片:120 张
  • 使用 Vector Drawable 替代 PNG :20 张
  • 使用 WebP 替代 PNG :50 张
  • 去除 9-patch :10 处

Gradle 优化

  • MinifyWithDex 启用
  • 资源缩小 启用
  • zipAlign 启用

Dex 优化

  • 方法计数混淆
  • 自定义混淆规则

SO 瘦身

  • 裁剪 SO 库 :不兼容的库裁剪掉

性能优化

  • 修复内存泄漏:20 处
  • 优化耗电量:优化 UI 线程、线程优化

瘦身后的:

APK 体积:12MB瘦身 6MB ,**体积缩减 33%