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