目录

Application Quick Start

Overview

As application functions continue to expand, the startup phase often requires a series of operations such as process creation, runtime initialization, module loading, resource parsing, and first-screen construction. When the cold startup path is long or resource and module loading account for a high proportion of the startup phase, users will wait longer on the first screen, which in turn affects application experience and retention performance.

Starting from API version 24, the system provides the application quick start mechanism. This mechanism completes the initialization of reusable processes in the startup phase in advance. When the user starts the application again, the relevant startup initialization results are reused, reducing repeated initialization and loading overhead and shortening the startup path, which helps improve application startup speed and stability.

Features of the application quick start mechanism:

Developers can determine whether an application is suitable for integrating the quick start capability from the following dimensions:

Basic Concepts

Constraints

Implementation Principle

The quick start technology completes the initialization of reusable parts in the startup process in advance. When the application starts, it can reuse the relevant initialization results, thereby skipping this part of the startup process and achieving the goal of faster startup. As shown in the following figure, compared with normal startup, quick start can skip some stages in the startup process, thereby reducing the startup latency:

The processes included in the quick start point are: AbilityStage module loading, AbilityStage.onCreate, and UIAbility module loading. During module loading, some code is executed, including top-level code, so constructors, and class static variable initialization.

Quick Start Adaptation

[h2]Quick Start Risky Operations

Quick start skips part of the startup process. To ensure data consistency and correct state, developers need to eliminate risky operations in the quick start initialization process to guarantee the correctness of application data after quick start.

Examples of risky operations are as follows:

[h2]Postpone Quick Start Risky Operations Beyond the Quick Start Point

The system provides a new callback API onAboutToCreateAbility(). This API is triggered after AbilityStage.onCreate() completes, but it does not participate in the quick start initialization process. This callback is invoked regardless of whether the application quick start feature is enabled.

Example 1: AbilityStage.onCreate contains quick start risky operations.

export class AppAbilityStage extends AbilityStage {
    onCreate() {
        this.readFile();
    }
    readFile() {
        // Read a file from the disk.
    }
}

Recommendation:

  1. Postpone the quick start risky operations to AbilityStage.onAboutToCreateAbility.

    export class AppAbilityStage extends AbilityStage {
        onAboutToCreateAbility() {
            this.readFile();
        }
    }
  2. When adjusting the business logic, consider timing dependencies to ensure the correctness of the business logic.

  3. AbilityStage.onCreate() is the first lifecycle callback that contains a large amount of business logic. If the business in this callback is difficult to split, it is recommended that developers move the entire content of AbilityStage.onCreate() to onAboutToCreateAbility() during the initial adaptation. Later, the benefits can be expanded by moving business logic forward.

Example 2: Quick start risky operations exist in the top-level code.

The following example instantiates a class in the top-level code, which ultimately leads to file access:

class ClassA {
    constructor() {
        this.readFile();
    }

    readFile() {
        // Read the file from the disk.
    }
}

let tmp = new ClassA();

Recommendation:

  1. Top-level code is executed when the module is imported, so its timing is bound to the first caller. This makes it an implicit and uncontrollable invocation, and modifying it can easily disrupt the invocation sequence. Therefore, it is recommended to implement business logic in non-top-level code.

  2. Specifically for the quick start feature, the system requires that application modules must not perform quick start risky operations in top-level code. Instead, such operations should be moved to lifecycle callbacks based on the business logic.

Example 3: A quick start risky operation exists in a C++ constructor.

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() {
    // Read the file from the disk.
}

extern "C" __attribute__((constructor)) void RegisterOpenPlatformModule(void) {
    napi_module_register(&OpenPlatformModule);
    read_file();
}

Recommendation:

  1. Check the .so files loaded during the startup process one by one. For .so files whose constructors do not contain quick start risky operations, perform dlopen in AbilityStage.onCreate to expand the quick start benefit.

  2. For .so files whose constructors contain risky operations, invoke them in lifecycle callbacks outside the quick start point, such as UIAbility.

Example 4: A quick start risky operation exists in the initialization of a class static variable.

The following example contains two types of static initialization: one is static variable initialization, which reads a file; the other is static code block execution, which performs network access.

export class AppAbilityStage extends AbilityStage {
    private a = 1;
    static data = AppAbilityStage.readFile();
    static {
        AppAbilityStage.netAccess();
    }
    static readFile() {
        // Read the file from the disk.
    }
    static netAccess() {
        // Access the network.
    }
}

Recommendation: Adjust the code based on the business logic to move the quick start risky operations out of the quick start point.

[h2]Updating Data in the Update Callback

Considering the difficulty of actually adjusting business logic, some external data interactions are hard to isolate. The quick start mechanism provides developers with a new callback onLaunchFromHyperSnap(). This callback is executed only in the quick start process (rather than the quick start initialization process), and is not executed during a normal cold start. Developers can re-request external data for synchronization in this callback to ensure data consistency.

export class AppAbilityStage extends AbilityStage {
    onCreate() {
        this.initLanguage(language);
    }
    initLanguage(language) {
        readFile(); // A quick start risky operation exists in AbilityStage.onCreate.
    }
    readFile() {
        // Read the file from the disk.
    }
}
export class AppAbilityStage extends AbilityStage {
    onLaunchFromHyperSnap() {
        this.updateLanguage(); // Update in onLaunchFromHyperSnap.
    }
    updateLanguage() {
        readFile();
    }
}

Enabling or Disabling Quick Start Through the Application-Side Cloud Push Switch

The cloud push switch is a mechanism that dynamically enables or disables specific application features through online cloud configuration.

With setHyperSnapEnabled(), an application can disable the quick start feature as needed until the cloud push switch re-enables it.

Basic specifications of the cloud push switch:

Example of using the cloud push switch:

With the preceding implementation, the application can continue to use the quick start feature after an update.

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() {
        // Read the setHyperSnapEnabled parameter from the database.
    }
}

Actively Resetting the Quick Start Initialization Result by the Application

The system provides the requestRebuildHyperSnap() API, which allows the application to actively call it in its own business logic to clear the current quick start initialization result and re-perform quick start initialization when conditions are met.

export class LauncherAbility extends UIAbility {
    onCreate() {
        // ...
        try {
            // ...
        } catch (error) {
            // ...
            requestRebuildHyperSnap(); // Regenerate the quick start initialization result when an error is reported based on the business logic.
            // ...
        }
    }
}

Improving Quick Start Acceleration Benefits by Adjusting Business Logic

The more startup logic included in a quick start point, the more obvious the quick start benefits usually are. Developers can sort out and analyze the entire startup process, and move the startup logic suitable for inclusion in the quick start point (that is, logic that does not contain quick start risky operations) into the quick start point while ensuring the correctness of business logic, so as to expand the benefits of the application quick start technology in improving startup performance.

Supporting Tools for Hyper Startup Integration

To help you locate the content that needs to be adapted and modified, the system provides the plug-in tools. This tool scans code to identify code that may cause Hyper Startup issues and reports the issues to developers for correction. This reduces the workload of manual check and improves the efficiency of adapting apps to Hyper Startup.

Sample Code

The following sample is provided to help you better understand how to develop Hyper Startup for your app: