随着应用功能不断丰富,启动阶段往往需要完成进程创建、运行时初始化、模块加载、资源解析、首屏构建等一系列操作。当冷启动链路较长或启动阶段资源、模块加载占比较高时,将导致用户在首屏等待时间变长,进而影响应用体验和留存表现。
从API version 24开始,系统提供应用快启机制。该机制通过提前完成启动阶段中可复用流程的初始化工作,在用户再次启动应用时,复用相关启动初始化结果,减少重复初始化和加载开销,缩短启动链路耗时,有助于提升应用启动速度和稳定性。
应用快启机制的特点:
开发者可以从以下维度判断应用是否适合接入快启能力:
快启技术会提前完成启动流程中可复用部分的初始化工作。应用启动时,可复用相关初始化结果,从而跳过这部分启动流程,达到启动加速的目标。如下图所示,快启相较于普通启动可跳过启动过程中的部分阶段,从而减少启动时延:

包含在快启点内的流程有:AbilityStage模块加载、AbilityStage.onCreate和UIAbility模块加载。其中,在模块加载过程中将执行部分代码,包括顶层代码(top level)、so的constructor和类静态变量初始化等。
快启会跳过部分启动流程。为了保证数据一致性和状态正确,开发者需要消除快启初始化流程中的风险操作,才能保障快启后应用数据的正确性。
风险操作的实例如下:
磁盘数据访问
快启初始化过程中发生的磁盘数据读取操作,不会在快启中执行,因此会导致数据不一致问题。
示例:快启初始化过程中,应用业务读取存储在数据库中的字体属性(宋体)。应用快启后,用户将字体调整为楷体,该属性被持久化到数据库文件,随后应用退出;下次应用快启时,由于没有再次读取数据库(该流程已被跳过),导致字体仍为宋体,而不是更新后的楷体。
事件监听回调注册
快启初始化过程中建立的回调事件监听,不会在快启前持续响应,可能导致事件丢失。
示例:快启初始化过程中,应用业务注册了颜色模式监听,初始为深色模式;在应用未被用户启动的情况下,系统颜色模式发生变化,切换为浅色模式。由于该监听不会在快启前持续响应,因此无法接收到切换颜色模式的广播消息。下次用户通过快启方式启动应用时,应用仍会显示为深色模式。
网络访问
快启初始化中建立的网络连接不可控,可能出现连接中断等问题。
示例:快启初始化中,建立了长时TCP连接以接收云端信息;快启初始化完成后,该连接不会持续响应,超时导致连接失败。
进程间通信(IPC)
快启初始化中,禁止有状态的进程间通信,例如保存应用状态和数据持久化(允许参数获取等无状态的进程间通信),否则会触发保护机制导致快启初始化失败。
系统为开发者提供了新的回调接口onAboutToCreateAbility()。该接口在AbilityStage.onCreate()执行完毕后触发,但不参与快启初始化过程。无论是否开启应用快启功能,该回调均会被调用。
示例1: AbilityStage.onCreate中存在快启风险操作。
export class AppAbilityStage extends AbilityStage {
onCreate() {
this.readFile();
}
readFile() {
// 从磁盘读取文件
}
} 建议:
将快启风险操作后置到AbilityStage.onAboutToCreateAbility。
export class AppAbilityStage extends AbilityStage {
onAboutToCreateAbility() {
this.readFile();
}
} 调整业务逻辑时,需要考虑时序依赖,保障业务逻辑正确性。
AbilityStage.onCreate()是首个包含较多业务逻辑的生命周期回调。若该回调中的业务不易拆分,建议开发者在首次适配时,将AbilityStage.onCreate()的内容整体移至onAboutToCreateAbility()。后续可通过业务前移扩大收益。
示例2: 顶层代码中存在快启风险操作。
以下示例在顶层代码中实例化类,并最终导致文件访问:
class ClassA {
constructor() {
this.readFile();
}
readFile() {
// 从磁盘读取文件
}
}
let tmp = new ClassA(); 建议:
顶层代码会随import该模块而执行,所以在时序上顶层代码与首个调用者绑定,属于隐式且不可控的调用,修改时容易造成调用时序混乱,所以建议在非顶层代码中实现业务逻辑。
具体到快启特性,系统要求应用模块不可以在顶层代码执行快启风险操作,而是要根据业务逻辑调整到生命周期回调中执行。
示例3: C++的构造函数中存在快启风险操作。
static napi_module OpenPlatformModule = {
.nm_version = 1,
.nm_flags = 100,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "openplatform",
.nm_priv = ((void *)0),
.reserved = {0}
};
void read_file() {
// 从磁盘读取文件
}
extern "C" __attribute__((constructor)) void RegisterOpenPlatformModule(void) {
napi_module_register(&OpenPlatformModule);
read_file();
} 建议:
逐一检查启动过程中加载的so。constructor中不存在快启风险操作的so在AbilityStage.onCreate中进行dlopen,以扩大快启收益。
存在风险操作constructor的so,需要放到UIAbility等快启点之外的生命周期中调用。
示例4: 类静态变量初始化中存在快启风险操作。
以下示例中存在两类静态初始化:一是静态变量初始化,会读取文件;二是静态代码块执行,会进行网络访问。
export class AppAbilityStage extends AbilityStage {
private a = 1;
static data = AppAbilityStage.readFile();
static {
AppAbilityStage.netAccess();
}
static readFile() {
// 从磁盘读取文件
}
static netAccess() {
// 网络访问
}
} 建议:根据业务逻辑进行调整,将快启风险操作移出快启点。
考虑到实际调整业务逻辑的困难,部分对外数据交互难以剥离。快启机制为开发者提供新的回调接口onLaunchFromHyperSnap(),该回调接口仅在快启流程(而不是快启初始化流程)中执行,正常冷启动不执行该回调。开发者可以在该回调接口中重新请求外部数据进行同步,保证数据一致性。
export class AppAbilityStage extends AbilityStage {
onCreate() {
this.initLanguage(language);
}
initLanguage(language) {
readFile(); // AbilityStage.onCreate中存在快启风险操作
}
readFile() {
// 从磁盘读取文件
}
} export class AppAbilityStage extends AbilityStage {
onLaunchFromHyperSnap() {
this.updateLanguage(); // 在onLaunchFromHyperSnap中进行更新
}
updateLanguage() {
readFile();
}
} 云推开关是一种通过云端在线配置、动态开启或关闭应用特定功能的机制。
借助setHyperSnapEnabled(),应用可以根据需要关闭快启功能,直至云推开关重新开启。
云推开关的基本规格:
云推开关使用示例:
通过上述实现,可保障应用更新后继续使用快启特性。
export class LauncherAbility extends UIAbility {
onCreate() {
// ...
}
onConfigChange(key: string, value: string) {
if (key == "enable_hyper_snap") {
if (value == "true") {
setHyperSnapEnabled(true);
} else {
setHyperSnapEnabled(false);
}
}
}
}
export class AppAbilityStage extends AbilityStage {
onCreate() {
const hyperSnapConfig = this.readConfigFromDB();
if (hyperSnapConfig === "true") {
setHyperSnapEnabled(true);
} else {
setHyperSnapEnabled(false);
}
}
readConfigFromDB() {
// 从数据库读取setHyperSnapEnabled参数
}
} 系统对外提供了requestRebuildHyperSnap()接口,该接口支持应用在自己的业务逻辑中主动调用,清理当前快启初始化结果,在满足条件时重新进行快启初始化。
export class LauncherAbility extends UIAbility {
onCreate() {
// ...
try {
// ...
} catch (error) {
// ...
requestRebuildHyperSnap(); // 开发者可根据业务在报错时重新生成快启初始化结果
// ...
}
}
} 纳入快启点的启动逻辑越多,快启收益通常越明显。开发者可以对整个启动流程进行梳理和分析,将适合纳入快启点的启动逻辑(即不含快启风险操作),在保障业务逻辑正确性的条件下前置到快启点内,扩大应用快启技术提升启动性能的收益。
将启动过程中的时序无关且无快启风险操作的逻辑前置到快启点内
如果存在可前置且无时序依赖的任务,建议评估是否将其放到快启点内以扩大收益。同时,需要确保该任务不会引入快启风险操作。
将启动过程中的加载依赖库逻辑前置到快启点内
import动作前置存在适用范围,系统建议将冷启动过程中的import动作尽可能放到快启初始化流程内,以扩大收益。通过DevEco Profiler调优工具扫描关键词“Evaluate”,获取启动过程中的import动作。
不建议将启动后的import动作前置到启动流程甚至快启初始化流程中,否则可能导致以下问题。
(1)劣化普通冷启动性能。
(2)导致启动流程的资源占用不必要地增加。
建议采用动态import的方式在AbilityStage.onCreate中执行import动作。
export class AppAbilityStage extends AbilityStage {
onCreate() {
// ...
this.preLoadKit();
// ...
}
async preLoadKit() {
await import('@ohos/common/src/..../1');
await import('@ohos/common/src/..../2');
// ...
await import('@ohos/common/src/..../N');
}
}