App瘦身优化实战

我们之前分析过瘦身优化:App瘦身优化

这篇文章我们继续分析瘦身优化

“每个字节都应该为用户体验服务,冗余即是对用户的不敬”

一、整体思路 & 优化流程

  1. 目标明确
    1. 明确一个目标:例如 安装包 ≤ 50MB 或 ​*相比当前减少 30%*​。
    2. 区分:​安装包体积(APK/​​​AAB​**)** vs ​安装后占用空间​,手段有所不同。
  2. 量化分析
    1. 使用工具:
      • Analyze APK(Android Studio 内置):看各目录和 .dex 的体积占比。
      • apktool / bundletool 解包进一步分析。
    2. 先找“大头”:一般是
      • lib/(so库)
      • res/(图片、音视频、字体)
      • classes*.dex(代码)
      • assets(离线包、H5、模型文件等)
  3. 优先级
    1. P0:资源 & 多余依赖​(通常最容易减 20~40%)
    2. P1:代码混淆压缩 & 多dex瘦身
    3. ​P2:架构升级(​​​Android App Bundle​**、动态特性模块拆分)**
    4. P3:深度方案(重构架构、替换大模块)

二、基础配置层面(低成本高收益)

  1. 使用 Android App Bundle(AAB)

如果还在发 APK,建议改为 AAB​​​ + Google Play/各应用市场的分发优化​:

  • 好处:
    • 自动做 ABI​​​ 分包​(只下当前CPU架构的 so)
    • 自动做 ​语言资源拆分​(只下当前语言)
    • 自动做 ​密度拆分​(按屏幕分发资源)
  • 配置(示意):
android {
    bundle {
        language {
            enableSplit = true
        }
        density {
            enableSplit = true
        }
        abi {
            enableSplit = true
        }
    }
}
  1. 启用 R8 / ProGuard 混淆与压缩

  • 确保开启:
buildTypes {
    release {
        minifyEnabled true        // 开启代码压缩+混淆
        shrinkResources true      // 删除未使用的资源
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
                     'proguard-rules.pro'
    }
}
  • 注意:
    • 线上一定要配好 keep 规则,避免反射导致崩溃。
    • 可以开启 -whyareyoukeeping 辅助分析为啥某些类没被清掉。

三、资源瘦身(通常收益最大)

  1. 图片资源优化

  2. 格式选择

    1. 优先使用 矢量图(Vector Drawable) 替代多分辨率 PNG 图标(尤其是图标、简单图形)。
    2. 位图资源优先考虑:
      • WebP(有损/无损)
      • 适当场景考虑 AVIF(Android 12+,视用户覆盖情况)
  3. 压缩图片

    1. 使用专业工具离线批量压缩:
      • TinyPNG、ImageOptim 等(出包前 pipeline 中跑一遍)。
    2. 控制图片分辨率:UI 不需要 4K 大图的话就不要用。
  4. 去掉冗余分辨率

    1. 只保留必要的 xxxhdpi/xxhdpi 等,避免同一资源多个密度重复。
    2. 使用 App Bundle 的 density split 后,可以适度减少本地冗余。
  5. 音视频资源

  • 优先采用 ​在线加载+缓存​,避免大体积音视频直接打进包。
  • 必须内置的音频:
    • 采用较高压缩率格式(如 oggaac)。
    • 控制长度,避免整首歌打入包。
  • 必须内置的视频:
    • 降低分辨率、码率,或做短片/循环片段。
    • 考虑 H.265/VP9(取决于最低兼容版本)。
  1. 字体资源

  • 如果使用自定义字体:
    • 尽量只内嵌 ​1~2 种主要字体​。
    • 使用 ​子集化字体​(只保留需要的字符范围,例如 latinbasic CJK),减少TTF/OTF大小。
    • 多语言字体尽量分拆,通过在线下载或按需包加载。
  1. 多语言资源(strings.xml)

  • 若使用 AAB,可以开启语言拆分,安装时只下当前语言。
  • 评估是否真的需要支持所有语言:
    • 去掉几乎没有用户的语言资源。
    • 或采用在线配置方式加载部分文案,避免全部内置。
  1. 移除无用资源

  • 开启 shrinkResources 后,配合工具排查:
    • Android Studio → Analyze → Inspect Code 查找 unused resources。
    • 注意:被反射 / 动态拼接引用的资源,要通过 tools:keep 或 proguard keep 保护。
  • 清理:
    • 不再使用的旧图标、老主题资源、废弃布局文件。
    • 旧的引导页图片、运营活动资源等。

四、代码维度瘦身(dex / 依赖)

  1. 依赖梳理与瘦身

  2. 检查 Gradle 依赖树

  3. ./gradlew app:dependencies

    1. 找出:
      • 重复的库(如同一个功能有多个不同依赖)
      • 只用到一个小功能却引入非常大的库(如整套 analytics / IM / video SDK)
  4. 替换/删除大依赖

    1. 大而全的 SDK → 精简版 SDK 或自研轻量实现。
    2. 多个 JSON 库 → 统一为一个(如 Gson / Moshi),去掉其他。
    3. 多个网络库 → 统一到 OkHttp/Retrofit 一套。
  5. 使用 ​​**implementation​ 而非 ​api**

    1. 避免传递性依赖膨胀其他 module。
  6. 代码结构优化

  • 尽量降低方法数量(方法数过多会产生 multi-dex,dex 体积上升):
    • 清理未使用的老代码(弃用模块、旧业务逻辑)。
    • 将一些复杂工具类拆分为模块依赖,按需加载或仅在特定版本使用。
  • 插件化/热修复框架 做取舍:
    • 部分框架自身体积不小,要评估是否仍有必要。
  1. 代码依赖检查方法

在 Android Studio 中检查项目模块(Module)之间的依赖关系,主要有 ​可视化界面查看​、​Gradle 命令分析​、第三方插件辅助 三种方式,覆盖从快速预览到详细分析的场景,以下是具体操作步骤:

1)、可视化界面:快速查看模块依赖(最常用)

Android Studio 内置了依赖关系可视化工具,支持直观查看模块间的直接 / 间接依赖,操作简单:

  1. 方式 1:通过「Project Structure」查看

适合快速核对单个模块的依赖(包括本地模块 + 远程库):

  • 打开 Android Studio,进入项目;
  • 两种打开方式:
    • 顶部菜单栏 → File → Project Structure(快捷键:Ctrl+Alt+Shift+S / Mac Cmd+Alt+Shift+S);
    • 右侧「Gradle」面板 → 选中项目根目录 → 右键 → Open Module Settings
  • 在左侧面板选择「Modules」,然后选中你要检查的模块(如 app);
  • 切换到右侧「Dependencies」标签页:
    • 列表中「Module dependency」类型即为 ​本地模块依赖​(如 :moduleA:library);
    • 其他类型(如 Library dependency)为远程库依赖,可忽略;
  • 若要查看其他模块的依赖,切换左侧模块列表即可。
  1. 方式 2:通过「Dependency Graph」可视化依赖树

适合查看 ​整个项目的所有模块依赖关系​(包括模块间的间接依赖),图形化展示更清晰:

  • 顶部菜单栏 → View → Tool Windows → Gradle(打开 Gradle 面板);
  • 在 Gradle 面板中,展开你的项目 → 选中要分析的模块(如 app)→ 展开 Tasks → help
  • 右键点击 dependencies 任务 → 选择 Run '模块名:dependencies'(如 Run 'app:dependencies');
  • 执行完成后,底部「Run」面板会输出文本格式的依赖树;
  • 若要可视化图形:
    • 顶部菜单栏 → Analyze → Analyze Dependencies...
    • 在弹出的窗口中,选择要分析的模块(可多选,如 appmoduleA),点击「OK」;
    • 生成依赖关系图,支持:
      • 拖动节点调整布局;
      • 右键节点 → Show Dependencies 查看该模块的详细依赖;
      • 筛选「Only Modules」只显示本地模块依赖(隐藏远程库)。

2)、Gradle 命令:详细分析依赖(支持过滤和导出)

如果需要更精确的依赖分析(如查找重复依赖、间接依赖来源),可通过 Gradle 命令行执行,Android Studio 内置终端直接支持:

  1. 打开终端
  • 底部面板 → 切换到「Terminal」标签(若未显示,通过 View → Tool Windows → Terminal 打开)。
  1. 核心命令(适用于绝大多数场景)

在终端中输入以下命令,按回车执行:

命令(Windows/Mac/Linux 通用) 作用
./gradlew :app:dependencies 查看 app 模块的所有依赖(本地模块 + 远程库),按配置(debug/release)分类
./gradlew :moduleA:dependencies 查看指定模块(如 moduleA)的依赖
./gradlew dependencies 查看整个项目所有模块的依赖(输出较多,不推荐)
  1. 过滤筛选(关键!只看模块依赖)

默认输出包含大量远程库依赖,可通过 grep(Mac/Linux)或 findstr(Windows)过滤,只保留本地模块依赖(模块名通常以 : 开头,如 :moduleA):

  • Mac​​**/Linux**​:
./gradlew :app:dependencies | grep --color ":module"  # 筛选包含 ":module" 的依赖(模块名通常含 module)# 或精确匹配本地模块(格式为 :模块名)
./gradlew :app:dependencies | grep -E ":([a-zA-Z0-9_]+)" --color
  • ​Windows(​CMD​​**​ 终端)**​:
gradlew :app:dependencies | findstr ":module"
  • ​Windows(​PowerShell​​**​ 终端)**​:
.\gradlew :app:dependencies | Select-String ":module"
  1. 导出依赖报告(便于分享 / 存档)

将依赖分析结果导出为文本文件,方便后续查看:

  • Mac/Linux:
./gradlew :app:dependencies > app_dependencies.txt
  • Windows:
gradlew :app:dependencies > app_dependencies.txt

执行后,项目根目录会生成 app_dependencies.txt 文件,包含完整依赖信息。

3)、第三方插件:增强型依赖分析(复杂项目推荐)

如果项目模块多、依赖关系复杂,可使用第三方插件提供更强大的分析功能:

  1. 推荐插件:Dependency-Check
  • 功能:可视化依赖树、检测重复依赖、冲突依赖报警、导出详细报告;
  • 安装步骤:
    • 顶部菜单栏 → File → Settings → Plugins(Mac:Android Studio → Settings → Plugins);
    • 搜索「Dependency-Check」,点击「Install」安装,重启 Android Studio;
  • 使用:
    • 右键项目根目录 → Dependency Check → Analyze Project
    • 生成交互式依赖报告,支持筛选模块、查看依赖链路、定位冲突依赖。
  1. 其他插件:
  • Gradle Dependency Helper:快速搜索依赖、查看最新版本、一键替换依赖;
  • Dexcount Gradle Plugin:分析依赖对应的方法数(辅助优化包体积)。

4)、关键说明

  1. 模块依赖格式​:本地模块依赖在 build.gradle 中表现为 implementation project(':moduleA')(Android Gradle Plugin 3.0+),旧版本可能是 compile project(':moduleA')
  2. 间接依赖​:若 app 依赖 moduleAmoduleA 依赖 moduleB,则 app 间接依赖 moduleB,通过「Dependency Graph」或 Gradle 命令可查看这种传递依赖;
  3. 依赖冲突​:若多个模块依赖同一库的不同版本,Gradle 会默认选择最高版本,可通过 ./gradlew :app:dependencies 查看冲突解决结果(标注 (variant: ...))。

通过以上方法,可全面覆盖从「快速预览」到「详细分析」的模块依赖检查需求,根据项目复杂度选择对应方式即可~

五、Native so 库瘦身

  1. 只保留必要 ABI

  • 常见 ABI:armeabi-v7aarm64-v8ax86x86_64
  • 实战策略:
    • 绝大多数线上版本可以只保留 armeabi-v7a + arm64-v8a
    • x86 系列设备占比非常低,可改为通过渠道单独提供。
  • Gradle 配置示例:
android {
    defaultConfig {
        ndk {
            abiFilters "armeabi-v7a", "arm64-v8a"
        }
    }
}
  1. 第三方 SDK 的 so 管理

  • 许多 IM、音视频、地图 SDK 默认集成全 ABI 的 so。
    • 尽量使用官方提供的 精简包 或“按需模块化包”。
    • 如果 SDK 允许手动删去某些 ABI 目录,可在构建前处理。
  1. 自研 Native 代码优化

  • 编译选项优化:
    • 打开 -Os-Oz(以减小体积为目标)。
    • 去掉不必要的调试符号。
  • 删除无用的 native 方法、旧接口。

六、模块拆分与动态交付(Dynamic Feature)

如果 App 已经比较大(>100MB),可以考虑:

  1. 按业务模块拆分
    1. 核心流程(登录/首页/基础浏览)作为 base module。
    2. 低频/重度功能做 ​Dynamic Feature Module​(例如:AR 模块、重度编辑器、游戏、视频编辑等)。
  2. 触发更新或安装
    1. 用户进入对应页面前再下载对应动态模块。
  3. 拆分原则
    1. 按“使用频次”和“体积大小”做划分:
      • 高频 + 小体积​:放 base。
      • 低频 + 大体积​:拆动态模块。
    2. 避免过度拆分导致开发和维护成本极高。

七、启动后按需加载 / 延迟加载

  1. 减少首包必须内容
    1. 把不影响“首屏体验”的功能延后加载或在线下发:
      • 运营活动资源
      • 辅助工具模块(分享、扫一扫、埋点可稍晚初始化)
  2. 在线资源 + ​本地缓存
    1. 部分资源(尤其大图 / 大配置)改为首启后后台下载到本地。
    2. 注意控制失败回退策略,防止无网时完全不可用。

八、构建流程中的自动化检查

  1. 持续集成​(​​​CI​**)里增加体积阈值检查**
    1. 每次构建统计:
      • 包体积
      • 各目录大小(lib/res/assets/dex)
    2. 超过阈值时报警,避免长期“野蛮生长”。
  2. 自动压缩/转换 Pipeline
    1. 在打包前自动执行:
      • 图片压缩脚本
      • 字体子集化
      • 删除不再使用的资源(配合白名单)

九、具体优化措施

1、assets目录优化

1)、删除字体文件,字体文件由系统预置 (缩减16MB)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

把app的这两个字体文件删除,由系统去

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一点IT+

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值