去年在做应用启动优化时,AppStartup 已经把初始化任务拆成并行、理清依赖关系,冷启动从 2.3 秒压到了 1.8 秒。直到在开发者大会上听到“快启”这个概念——系统级别跳过启动流程,当时就觉得这才是终极方案。
回去研究后发现,鸿蒙从 API 24 开始支持 HyperStartup(应用快启)。原理很简单:系统在灭屏或锁屏后,偷偷帮你把 AbilityStage 模块加载、onCreate、UIAbility 模块加载这些初始化工作先跑完,然后缓存结果。下次用户点开应用,直接跳过快启点之前的流程,从快启点继续执行。
官方给的参考值很到位:如果冷启动时延高于 1.6 秒,或者资源加载、模块加载占启动耗时超过 25%,就值得接入。我们项目实测冷启动最终降到了 1.2 秒左右。当然,快启只优化快启点前的流程,首屏渲染和网络请求瓶颈它帮不上忙。
一、快启的门槛与约束
快启不是配个配置文件就搞定的。它有几个硬性条件:
- 仅支持手机设备(平板、折叠屏暂时不行)
- API 24 及以上
- debug 签名开发者模式可直接调试,线上环境需去 AppGallery Connect 申请开通(项目设置 → 开放能力管理 → 应用快启)
- 系统说了算:即使用户接入了快启,实际是否触发快启初始化、什么时机触发,都由系统根据用户使用习惯决定,开发者无法强制。
二、核心风险操作
快启初始化是在后台偷偷执行的,如果在这个阶段做了某些操作,快启启动时流程被跳过,会导致数据不一致。官方列出了几类必须避免的风险操作:
1. 磁盘数据访问:快启初始化时读取了配置文件(比如字体设置),用户随后改了配置,快启启动时读取的是旧缓存。
2. 事件监听回调注册:快启初始化时注册的颜色模式变化监听,在初始化完成后不会持续响应,中间发生的事件会丢失。
3. 网络访问:快启初始化中建立的 TCP 连接在初始化完成后中断,快启启动时不会重建。
4. 有状态的 IPC:保存状态、数据持久化等操作会导致快启初始化直接失败。
三、适配方法:将风险操作挪到快启点外
系统从 API 24 开始提供了两个关键回调:
1. onAboutToCreateAbility()
这个回调在 AbilityStage.onCreate() 执行完后触发,但**不参与快启初始化过程**。无论是否开启快启,它都会被执行。因此,把 onCreate 里的风险操作迁移到这里是最直接的方案。
- // 改造前——onCreate 里有风险操作
- import { AbilityStage } from '@kit.AbilityKit';
- import { hilog } from '@kit.PerformanceAnalysisKit';
- export default class MyAbilityStage extends AbilityStage {
- onCreate(): void {
- hilog.info(0x0000, 'HyperStartup', 'onCreate');
- this.readConfigFromFile();
- this.registerThemeListener();
- }
- private readConfigFromFile(): void { /* 读取磁盘 */ }
- private registerThemeListener(): void { /* 注册监听 */ }
- }
复制代码
改造后:- import { AbilityStage } from '@kit.AbilityKit';
- import { hilog } from '@kit.PerformanceAnalysisKit';
- export default class MyAbilityStage extends AbilityStage {
- onCreate(): void {
- hilog.info(0x0000, 'HyperStartup', 'onCreate');
- // onCreate 里只放无风险操作
- }
- onAboutToCreateAbility(): void {
- hilog.info(0x0000, 'HyperStartup', 'onAboutToCreateAbility');
- this.readConfigFromFile();
- this.registerThemeListener();
- }
- // ...
- }
复制代码
注意时序依赖:如果 onCreate 里的一些逻辑是 onAboutToCreateAbility 里其他操作的前置条件,拆的时候要考虑清楚执行顺序。官方建议首次适配时直接把整个 onCreate 内容搬到 onAboutToCreateAbility,确保功能正常。
2. 顶层代码中的风险操作
模块级别的顶层代码(比如类实例化、静态初始化)在 import 时就会执行。如果这个模块在快启点内被加载,风险操作就会纳入快启初始化。解决方法是改成懒加载:
- import { AbilityStage } from '@kit.AbilityKit';
- class ConfigManager {
- constructor() { /* 构造时不做事 */ }
- public loadFromDisk(): void { /* 外部调用时才加载 */ }
- }
- let configInstance: ConfigManager | null = null;
- export function getConfigManager(): ConfigManager {
- if (!configInstance) {
- configInstance = new ConfigManager();
- }
- return configInstance;
- }
复制代码
然后在 onAboutToCreateAbility 里调用 getConfigManager().loadFromDisk()。
3. C++ constructor 中的风险操作
如果 native 库的 constructor 里有文件读取或网络访问,需要把 dlopen 放到 UIAbility 生命周期中,而不是 AbilityStage.onCreate 里。
4. 类静态变量初始化
静态变量和静态代码块在类加载时执行,同样需要移到回调里。
四、onLaunchFromHyperSnap:快启启动时同步最新数据
有些逻辑确实剥离不出来,比如需要读取最新的配置文件。这时可以用 onLaunchFromHyperSnap 回调——它只在快启启动时执行,普通冷启动不执行。
- import { AbilityStage } from '@kit.AbilityKit';
- import { hilog } from '@kit.PerformanceAnalysisKit';
- export default class MyAbilityStage extends AbilityStage {
- onCreate(): void {
- hilog.info(0x0000, 'HyperStartup', 'onCreate');
- this.initLanguage('zh-CN');
- }
- private initLanguage(lang: string): void { /* 初始化语言 */ }
- onLaunchFromHyperSnap(): void {
- hilog.info(0x0000, 'HyperStartup', '快启启动,重新同步数据');
- this.updateLanguage();
- }
- private updateLanguage(): void { /* 从磁盘重新读取最新语言配置 */ }
- }
复制代码
五、云推开关与主动重置
快启功能可以通过 hyperSnapManager.setHyperSnapEnabled() 动态开关,默认关闭。使用流程:
- 应用安装后第一次启动,从云端拉取配置
- 如果云端允许快启,调用 setHyperSnapEnabled(true)
- 云端配置变化时通过推送通知应用更新
- 在 AbilityStage.onCreate 里读取本地持久化配置再次调用(保障重启后生效)
注意:setHyperSnapEnabled 的调用本身如果放在 onCreate 里,快启启动时会被跳过。所以需要在 UIAbility 的配置变化监听中也调用一次,形成双层保障。
主动重置使用 hyperSnapManager.requestRebuildHyperSnap(),销毁当前快启缓存,让系统重新初始化。适合在检测到关键数据异常时调用。
六、踩坑记录
坑1:以为接入快启就能原地起飞
快启不需要在 module.json5 配额外字段,但对代码有严格要求。另外系统不一定每次都走快启,传统优化手段(AppStartup、懒加载、分包)不能丢。
坑2:搬代码没注意时序依赖
迁移 onCreate 内容时,如果只搬了部分代码,导致前置初始化未执行,快启启动时可能崩溃。建议首次整体搬。
坑3:顶层代码没排查干净
工具类顶层代码中隐藏的风险操作(如日志写入)容易被忽略。改成懒加载即可。
坑4:setHyperSnapEnabled 调用时机不对
onCreate 被跳过时,需要在 UIAbility 配置变化监听中再调一次。
坑5:调试时发现快启没生效
开发者模式下系统需要先进行一次静默的快启初始化(锁屏或灭屏后触发),然后杀进程重启才会走快启路径。可以用 DevEco Profiler 检查是否有风险操作导致初始化失败。
七、提升快启收益的技巧
把冷启动需要的 import 操作前置到 AbilityStage.onCreate 中(使用动态 import 预加载模块)。注意不要把启动后才需要的 import 前置,否则会劣化普通冷启动性能。
八、总结
HyperStartup 的接入门槛确实比 AppStartup 高,涉及系统级启动流程改动,对代码质量要求严格。但收益也实实在在:冷启动超过 1.6 秒的应用值得投入。适配时记住几个要点:
- onCreate 里的风险操作搬到 onAboutToCreateAbility
- 顶层代码排查干净
- onLaunchFromHyperSnap 用来同步最新数据
- 云推开关配合本地持久化双层保障
- 别指望系统每次都走快启,传统优化手段别丢
- API 24 以下设备做版本判断,避免调用 hyperSnapManager 接口导致 crash
搞了几天适配,虽然折腾,但看到启动时间从 2.3 秒降到 1.2 秒的那一刻,感觉值了。 |