# OneApp 包体积分析与优化方案

数据来源：
- Android： [apk_size.csv](./apk_size.csv)
- iOS： [ipa_size.csv](./ipa_size.csv)
- iOS 参考资料： [放心课App包大小分析.pdf](./放心课App包大小分析.pdf)

体积分布来源（tree 结构展示）：

Android（APK 解包）：
```
oneapp.apk/
├─ lib/
│  └─ arm64-v8a/
│     ├─ libapp.so
│     ├─ libAMapSDK_MAP_v10_0_700.so
│     ├─ libCubicSDK.so
│     ├─ libfuai.so
│     ├─ libmodpdfium.so
│     ├─ libavcodec.so
│     ├─ libavformat.so
│     ├─ libliteavsdk.so
│     ├─ libtxffmpeg.so
│     └─ libdownloadproxy.so
├─ assets/
│  ├─ engine/EngineAssets.bundle
│  ├─ model/ai_face_processor_e51.bundle
│  └─ flutter_assets/
│     └─ assets/fonts/
│        ├─ HYQiHei-60S.ttf
│        └─ HYQiHei-80S.ttf
├─ res/
└─ resources.arsc
```

iOS（IPA 解包）：
```
Runner.app/
├─ Frameworks/
│  ├─ App.framework/App
│  ├─ Flutter.framework/Flutter
│  ├─ FURenderKit.framework/FURenderKit
│  ├─ FUAIKit.framework/FUAIKit
│  ├─ OneAppSDK.framework/OneAppSDK
│  ├─ libavcodec.framework/libavcodec
│  ├─ libavformat.framework/libavformat
│  ├─ TXFFmpeg.framework/TXFFmpeg
│  └─ RemoteParkAssistCoreMEB.framework/RemoteParkAssistCoreMEB
├─ EngineAssets.bundle
├─ ai_face_processor_e51.bundle
└─ Runner
```

说明：以下体积分布基于 WizTree 导出的解包目录统计（安装包解压后的文件集合），用于定位体积大户与优化方向，不等同于应用商店展示的下载体积。

## Android（APK）体积分布

总体体积（解包后汇总）：约 267.8 MB

一级目录占比（解包后汇总）：
- assets：约 105.8 MB
- lib：约 143.4 MB
- 根目录（含 classes.dex / resources.arsc / 清单等）：约 267.8 MB
- res：约 13.2 MB

主要大文件（Top 10）：
- libapp.so：约 35.1 MB
- assets/0OO00l111l1l.：约 27.7 MB
- assets/engine/EngineAssets.bundle：约 20.3 MB
- libAMapSDK_MAP_v10_0_700.so：约 19.1 MB
- libCubicSDK.so：约 13.7 MB
- libflutter.so：约 10.3 MB
- assets/model/ai_face_processor_e51.bundle：约 10.2 MB
- 字体 HYQiHei-60S.ttf：约 8.2 MB
- 字体 HYQiHei-80S.ttf：约 8.0 MB
- libavcodec.so：约 8.1 MB

按文件类型占比（Top）：
- .so：约 143.4 MB
- .bundle：约 31.0 MB
- 无扩展名资源：约 29.9 MB
- .ttf：约 17.3 MB
- .webp：约 15.5 MB
- .png：约 6.8 MB
- .json：约 5.7 MB

结论：SO 与 assets 体积是主要矛盾，尤其是低频功能的引擎、地图、视频与模型资源。

## Android（APK）优化方案

### 1) SO 动态加载（最推荐，预估可省 35–45 MB 以上）

核心策略：将低频重度功能从首包剥离，改为运行时按需下载，再用 System.load() 加载，避免首包加载与体积膨胀。

原理：
- APK 安装体积主要由 assets 与 lib 贡献，把不必要的 .so 挪出首包可直接减小安装体积
- 仅在功能触发时下载并加载，提升首装体验与首启时间

实施步骤：
- 选型与边界
  - 明确低频、重依赖模块边界，避免核心首页路径依赖
  - 建立下载开关与回退策略
- 拆包与产物
  - 从构建产物中移除对应 .so 与资源
  - 产出按 ABI 分包的动态资源包（arm64-v8a 等）
- 下载与校验
  - 按需下载到应用私有目录
  - 校验包完整性与版本兼容性
- 加载与初始化
  - 调用 System.load() 加载本地路径
  - 延迟初始化 SDK，确保只在功能入口执行
- 失败兜底
  - 下载失败或加载失败时，降级到提示或轻量替代方案

第一梯队：必须动刀的大户
- libAMapSDK_MAP_v10_0_700.so（19.1 MB）
  - 现状：地图引擎大、加载时机过早
  - 方案：仅在用户进入“附近充电桩 / 导航”等页面时下载与加载
- libCubicSDK.so（13.7 MB）与 libCubicAISDK.so
  - 现状：3D 车模渲染引擎，低频重度
  - 方案：仅进入 3D 车模时下载与加载
- libfuai.so（7.4 MB）
  - 现状：人脸识别/相机特效
  - 方案：实名认证、人脸识别、社区发帖时再下载
- libmodpdfium.so（5.0 MB）
  - 现状：PDF 阅读
  - 方案：点开说明书时加载

第二梯队：多媒体与社交功能
- FFmpeg 系列库（libavcodec.so 8.1 MB、libavformat.so 4.3 MB 等）
  - 方案：视频/行车记录回放模块进入时再加载
- 腾讯云音视频相关（libliteavsdk.so 3.5 MB、libtxffmpeg.so 2.5 MB、libdownloadproxy.so 2.5 MB）
  - 方案：直播/音视频通话页面再加载
- libpag.so（2.4 MB）
  - 方案：首页无 PAG 动画则动态化

### 2) 静态资源极致脱水（目标 20–30 MB）

原理：
- 高分辨率图片与字体是 assets 体积大户，压缩与替换可快速带来收益
- 资源分级与按需下发可避免一次性装入所有车型与动效

实施步骤：
- 图片优化
  - PNG/JPG 批量转 WebP，保持视觉质量
  - 大图按场景拆分与缩放，减少冗余尺寸
- 动效优化
  - GIF/序列帧替换为 Lottie 或矢量动画
- 字体优化
  - 字体子集化，仅保留实际用字
  - 合并或减少字体家族数量
- 模型与大资源
  - AI 模型与 3D 资源改为在线按需下载

重点目录：
- flutter_assets（39.6 MB）
  - PNG/JPG 全量转 WebP（无损或高保真），通常可缩 40%–60%
  - 动效从 GIF/序列帧改为 Lottie
- model（10.2 MB）
  - AI 模型剥离为在线按需下载

### 3) 架构策略：全面迁移 AAB

原理：
- 通过 ABI 与屏幕密度拆分，终端只安装必需资源
- 从构建层面减少冗余架构与高密度资源

实施步骤：
- 产物策略
  - 主线市场使用 AAB
  - 国内渠道按 ABI 与密度拆分多 APK
- ABI 与密度
  - 仅向 64 位设备下发 arm64-v8a
  - 仅向高分屏设备下发 xxhdpi 及以上
- 动态功能模块
  - 高频模块留首包，低频模块采用动态下发
  - 注意国内商店对动态特性的支持差异

### 4) 代码与资源裁剪

原理：
- 未使用代码与资源不会影响功能，但会增加安装体积

实施步骤：
- 开启 R8 压缩与混淆，移除未使用代码
- 开启资源收缩，移除未使用图片与资源文件
- 移除无用语言与地区资源，仅保留目标市场

### 5) Native 库裁剪与去符号

原理：
- Native 库的调试符号与无用段会显著增加体积

实施步骤：
- 统一使用 release 产物与 strip 后的 .so
- 只保留必要的 ABI 与必要的插件 .so
- 对第三方 SDK 进行精简版本选型

## iOS（IPA）体积分布

总体体积（解包后汇总）：约 304..6 MB

一级目录占比（解包后汇总）：
- Frameworks：约 222.7 MB
- 根目录（Runner.app 根目录）：约 304.6 MB
- 各类 .bundle：约 28.9 MB

主要大文件（Top 10）：
- App.framework/App：约 43.7 MB
- Runner：约 43.7 MB
- EngineAssets.bundle：约 18.1 MB
- FURenderKit.framework：约 13.3 MB
- FUAIKit.framework：约 12.6 MB
- ai_face_processor_e51.bundle：约 10.2 MB
- Flutter.framework：约 9.6 MB
- OneAppSDK.framework：约 8.0 MB
- libavcodec.framework：约 7.7 MB
- RemoteParkAssistCoreMEB.framework：约 6.7 MB

按文件类型占比（Top）：
- 无扩展名（二进制可执行与 framework 主体）：约 215.6 MB
- .bundle：约 28.9 MB
- .ttf：约 17.2 MB
- .webp：约 9.7 MB
- .car（Asset Catalog）：约 8.8 MB
- .png：约 4.1 MB
- .json：约 5.4 MB

结论：Frameworks 是 iOS 体积主因，其次是 EngineAssets 与人脸识别相关模块。

## iOS（IPA）优化方案

以下方案结合当前包体分布给出可落地项：

与 Android 不同，iOS 更依赖构建期裁剪与资源下沉

### 1) 移除多余架构（armv7）

原理：armv7 属于历史设备架构，保留会直接扩大二进制与 Framework 体积。

实施步骤：
- Build Settings（Release）
  - Excluded Architectures：armv7
  - Validate Workspace 仅保留 arm64 产物
- 在 Build Phases 添加 Run Script，对嵌入 Framework 进行瘦身
  - 确保脚本在 Code Sign 之前执行

```shell
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
if lipo -info "$FRAMEWORK_EXECUTABLE_PATH" | grep -q "armv7"; then
 lipo -remove armv7 "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH"
fi
done
```

预期收益：通常在 10–20 MB 量级

### 2) 裁剪符号表与导出符号

原理：调试符号与未使用的导出符号不会影响运行时功能，但会增加可执行文件与动态库体积。通过剥离符号、限制导出符号集合，可以直接减少安装包体积。

实施步骤：
- 主二进制裁剪
  - Build Settings：STRIP_STYLE=all
  - EXPORTED_SYMBOLS_FILE 指向空文件，收敛导出符号
- 动态库裁剪
  - Build Settings：STRIP_STYLE=non-global
  - 对三方库先裁剪再签名，避免破坏签名
```shell
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
APP_EXECUTABLE_NAME="$(echo $WRAPPER_NAME | cut -d '.' -f1)"
arch="$(lipo -info "$APP_PATH/$APP_EXECUTABLE_NAME")"
if ! echo "$arch" | grep -q "arm64"; then exit 0; fi
cd "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}"
framework_path=$(pwd)
for file in $(find . -type f -perm +111); do
if ! [[ "$(file "$file")" == *"dynamically linked shared library"* ]]; then continue; fi
extracted_file_path=$framework_path${file:1}
 strip -x $extracted_file_path
done
```

收益：对安装包体积有直接缩减效果，通常在数 MB 至 10 MB 级别

### 3) 资源与三方库瘦身

原理：Frameworks 与资源包是 iOS 安装体积的核心来源，资源下沉与按需加载能有效降低首包。

实施步骤：
- 资源优化
  - 图片统一走 Asset Catalog，开启压缩与优化
  - 字体做子集化，仅保留实际用字
- 按需资源
  - 低频资源拆分为 ODR 或在线资源包
  - 首包仅保留核心路径资源
- 三方库瘦身
  - 优先选择精简版 SDK 或模块化版本
  - 低频 SDK 与资源做按需下载

结合当前分布可优先处理：
- 人脸/美颜 SDK（FURenderKit、FUAIKit、ai_face_processor_e51.bundle）
  - 低频功能可改为按需下载，或将静态资源外置
- EngineAssets.bundle
  - 低频 3D/引擎资源按需下载
- 音视频相关库（libavcodec、TXFFmpeg）
  - 仅在视频/直播功能进入时加载，或者拆分成按需模块

### 4) 死代码与无用资源清理

原理：未被引用的符号与资源不会影响功能，但会增加二进制与资源体积。

实施步骤：
- DEAD_CODE_STRIP=YES（确保保持开启）
- 使用 LinkMap 定位未引用目标与静态库
- 清理未使用类、图片、bundle 与重复资源

## iOS 参考
[抖音品质建设 - iOS 安装包大小优化实践篇](https://www.cnblogs.com/fadaijun/p/14285852.html)
[iOS逆向实战--019：符号的剥离与恢复](https://www.jianshu.com/p/752d3f07884f)

## 优化优先级建议

- P0：Android 动态 SO + iOS 架构裁剪
- P1：两端资源压缩与 3D/AI 模型外置
- P2：符号表裁剪、死代码与无用资源清理

| 优化项           | 预期收益  | 技术风险 | 实施成本 | 优先级 |
| ------------- | ----- | ---- | ---- | --- |
| Android 动态 SO | ⭐⭐⭐⭐⭐ | 中    | 中    | P0  |
| iOS 架构裁剪      | ⭐⭐⭐   | 低    | 低    | P0  |
| 资源压缩          | ⭐⭐    | 低    | 低    | P1  |
| AI / 3D 外置    | ⭐⭐⭐⭐  | 中    | 中    | P1  |
| 符号裁剪          | ⭐⭐    | 中    | 低    | P2  |
