HarmonyOS 7 应用冷启动与包体积优化实录
应用每次发版,看着那居高不下的应用包体积和用户反馈的“点开就白屏”,我都感到一阵心悸。在这个快节奏时代,安装包每大 10MB,卸载率就会上升一个台阶。这次,我们从资源压缩到启动链路,对应用进行了一场极其暴力的“抽脂”手术。
斩断无用资源的尾巴
打开工程的 resources 目录,里面躺着无数历史遗留的高清切图,有些是早被废弃的活动图,有些是同一张图的多个尺寸备份。这些资源不仅增大了包体积,在打包时还会增加编译时间。
我们使用构建工具开启了严格的“摇树(Tree Shaking)”机制。在项目级的 build-profile.json5 中开启混淆,并在 strictMode 中配置资源检查,构建工具会自动扫描未被代码引用的图片和字符串资源,并在打包时将它们踢出 HAP 包。这一招,直接砍掉了将近 15MB 的死重。
全面替换 WebP 格式
剩下的图片依然很大。UI 团队给出的切图清一色是 PNG 或 JPG。我们在构建脚本里加入了一个自动转换任务,将除了极其复杂的透明图之外的所有静态资源,全部转换为 WebP 格式。注意:WebP 在鸿蒙系统上支持极其完美,但体积比 PNG 缩小了将近 60%。用户肉眼看不出任何画质损失,但我们的安装包又瘦了 10MB。
动态化模块的降维打击
包体积减不下去的另一个大头,是某些低频使用的业务模块。比如我们的应用内置了短视频播放功能,但只有 5% 的用户会点开它。为了这 5% 的用户,让 95% 的用户承担 30MB 的下载成本,显然不划算。
我们将短视频相关的所有代码、图片、甚至底层的播放器三方库,全部剥离到了独立的 Feature 模块(HSP)中。
json
// 在短视频模块的 module.json5 中 "deliveryWithInstall": false // 核心配置:不随主包一起下载
配合应用市场的能力,用户首次安装时只下载主功能包。当用户第一次点击短视频入口时,系统才会在后台静默下载该模块。这极大地降低了首次下载的门槛。
冷启动的首屏秒开重构
包变小了,启动速度自然会快一点,但真正的瓶颈在于冷启动时的初始化逻辑。
以前在 EntryAbility 的 onCreate 里,我们初始化了各种推送 SDK、网络库、甚至预加载了首页的数据。这些操作全部在主线程串行执行,直接把首屏渲染的时间拖到了两秒之后。
我们引入了 AppStartup 机制,将所有的初始化任务剥离出来。
typescript
export default class InitNetworkTask extends StartupTask {
// 警示:非首屏必需的初始化,一定要设置为按需执行
isOnDemand: boolean = true;
async init(context: StartupTaskContext): Promise<void> {
// 这里的耗时操作不会阻塞首屏渲染
await initHttpClient();
}
}
同时,我们把首屏的 UI 渲染与网络请求完全解耦。页面一加载,立刻渲染出灰色的“骨架屏”。网络数据回来后,再替换为真实内容。用户的视觉体验从“白屏干等”变成了“秒开骨架”,哪怕绝对耗时没有变,主观流畅度也提升了一大截。
规避同步 IO 的冻结陷阱
在排查启动耗时的时候,抓包发现有一次启动异常缓慢。深入代码后发现,有同事在组件的 aboutToAppear 里用 fs.readTextSync 读取了一个几百 KB 的本地配置文件。在低端机上,同步读取文件直接把主线程卡死了几十毫秒。
必须彻底消灭主线程的同步 IO。所有的本地文件读写、数据库查询,全部改成了异步 Promise,如果必须在首屏渲染前拿到数据,就把它放进 TaskPool 里去并发加载。
用 DevEco Studio 的包体积分析工具打开你的 HAP 包。找到占用空间最大的前三个文件。如果它们是大图,尝试将其转为 WebP;如果是三方库,看看能否将其剥离为动态共享包。把包体积缩减 20% 作为你的第一个小目标。
更多推荐
所有评论(0)