OpenHarmony应用构建工具Hvigor的实现原理

Ryaaaaaaan 2023-03-13 16:56:05

前言

OpenHarmony 应用和服务使用 Hvigor 作为工程的构建工具。 上一篇文章 深入了解hvigor的使用方法 介绍了 Hvigor 的构建流程,通过修改脚本配置使 Hvigor 执行自定义任务。本篇文章将深入了解和解析 Hvigor 的标准任务和任务流。

Clean 任务

Clean 任务用于清除项目和模块构建后的产物。执行以下命令会删除项目和模块下的 Build 文件夹。

执行命令:

node node_modules/@ohos/hvigor/bin/hvigor.js clean
// hvigor-ohos-plugin/src/tasks/common/clean.js
class Clean extends hvigor_base.Task {
    constructor(taskService) {
        super();
        this._logger = ohos_logger_js.OhosLogger.getLogger(Clean.name);
        // 注册 Clean 服务
        this.registry = () => {
            return this.clean;
        };
        // Clean 操作
        this.clean = (callback) => {
            let buildDir;
            const taskBeginTime = process.hrtime();
            let moduleName;
            // 判断执行哪种级别的删除,Project : ProjectTaskService,Module : ModuleTaskService
            if (this._taskService instanceof module_task_service_js.ModuleTaskService) {
                const moduleModel = this._taskService.getModuleModel();
                // 模块名称
                moduleName = moduleModel.getName();
                if (!moduleModel) {
                    return;
                }
                // 当前 Module 的 Build 文件夹路径
                buildDir = path.default.resolve(moduleModel.getProjectDir(), "build");
            }
            else {
                // 项目名称
                moduleName = this._taskService.getProjectModel().getName();
                // 当前 Project 的 Build 文件夹路径
                buildDir = path.default.resolve(this._taskService.getProjectModel().getProjectDir(), "build");
            }
            let hasError = false;
            if (fs.existsSync(buildDir)) {
                hasError = this.rmdirSync(buildDir, false);
            }
            const taskEndTime = process.hrtime(taskBeginTime);
            const realTime =pretty_hrtime.default(taskEndTime);
            this._logger._printTaskInfo(moduleName, "Clean", realTime);
            callback();
            if (hasError) {
                process.exit(-1);
            }
        };
        // 删除文件夹
        this.rmdirSync = (dirPath, hasError) => {
            fs.readdirSync(dirPath).forEach(name => {
                const filePath = path.default.resolve(dirPath, name);
                const fileStats = fs.statSync(filePath);
                if (fileStats.isFile()) {
                    try {
                        fs.unlinkSync(filePath);
                    }
                    catch (e) {
                        this._logger.warn(e.message);
                        hasError = true;
                    }
                }
                else if (fileStats.isDirectory()) {
                    hasError = this.rmdirSync(filePath, hasError);
                }
            });
            try {
                let canRm = true;
                const files = fs.readdirSync(dirPath);
                files.forEach(name => {
                    const filePath = path.default.resolve(dirPath, name);
                    if (fs.existsSync(filePath)) {
                        canRm = false;
                    }
                });
                if (canRm) {
                    fs.rmdirSync(dirPath);
                }
            }
            catch (e) {
                this._logger.warn(e.message);
                hasError = true;
            }
            return hasError;
        };
        this._taskService = taskService;
    }
}

AssembleHap 任务流

Hap 打包的任务流
最终产物: [模块名称]/build/[产品名称]/outputs/[目标名称]/[模块名称]-[目标名称]-[signed/unsigned].hap。

// hvigor-ohos-plugin/src/tasks/assemble/assemble-hap.js
class AssembleHap extends hvigor_base.Task {
    constructor(taskService, isFaMode) {
        super();
        // 注册 AssembleHap 服务
        this.registry = () => {
            const hvigor = new hvigor_base.Hvigor();
            // FA 模型
            if (this._isFaMode) {
                return hvigor.series(
                    // 使用 Schema 校验配置文件
                    new pre_build_js.PreBuild(this._taskService).registry(), 
                    // 收集 package.json 中配置的 npm har 包依赖,并进行 har 构建
                    new collect_har_dependency_js.CollectHarDependency(this._taskService).registry(), 
                    // 以模块配置文件为主混合依赖的 har 配置文件和项目配置文件
                    new legacy_merge_profile_js.LegacyMergeProfile(this._taskService).registry(), 
                    // 处理配置文件
                    new legacy_process_profile_js.LegacyProcessProfile(this._taskService).registry(), 
                    // 编译资源文件
                    new legacy_compile_resource_js.LegacyCompileResource(this._taskService).registry(), 
                    // 遍历模块 Ability 信息生成 JsManifest.json 文件
                    new legacy_generate_js_manifest_js.LegacyGenerateJsManifest(this._taskService).registry(), 
                    // 生成loader需要的json文件
                    new generate_loader_json_js.GenerateLoaderJson(this._taskService).registry(), 
                    // 编译 ets 源码
                    new legacy_compile_node_js.LegacyCompileNode(this._taskService, code_type_enum_js.CodeType.ETS).registry(), 
                    // 编译 js 源码
                    new legacy_compile_node_js.LegacyCompileNode(this._taskService, code_type_enum_js.CodeType.JS).registry(), 
                    // Native 代码编译任务
                    new compile_native_js.CompileNative(this._taskService).registry(), 
                    // 编译 .so 文件
                    new build_native_js.BuildNative(this._taskService).registry(), 
                    // 收集hap和har依赖中的.so文件
                    new process_libs_js.ProcessLibs(this._taskService).registry(),
                    // 系统能力转换
                    new syscap_transform_js.SyscapTransform(this._taskService).registry(), 
                    // 根据 config.json 配置文件生成 pack.info 文件
                    new legacy_make_pack_info_js.LegacyMakePackInfo(this._taskService).registry(), 
                    // 把生成的所有文件进行整合打包成 Hap 包
                    new legacy_package_hap_js.LegacyPackageHap(this._taskService).registry(),
                    // 给打包好的 Hap 包签名
                    new sign_hap_js.SignHap(this._taskService).registry()
                );
            }
            // Stage 模型
            return hvigor.series(
                // 使用 Schema 校验配置文件。
                new pre_build_js.PreBuild(this._taskService).registry(), 
                // 收集 package.json 中配置的 npm har 包依赖,并进行 har 构建
                new collect_har_dependency_js.CollectHarDependency(this._taskService).registry(), 
                // 以模块配置文件为主混合依赖的 har 配置文件和项目配置文件
                new merge_profile_js.MergeProfile(this._taskService).registry(), 
                // 处理配置文件
                new process_profile_js.ProcessProfile(this._taskService).registry(), 
                // 合并资源到index文件中
                new merge_resource_js.MergeResource(this._taskService).registry(), 
                // 编译资源文件
                new compile_resource_js.CompileResource(this._taskService).registry(), 
                // 生成loader需要的json文件
                new generate_loader_json_js.GenerateLoaderJson(this._taskService).registry(), 
                hvigor.parallel(
                    // 编译 ets 源码
                    new compile_node_js.CompileNode(this._taskService, code_type_enum_js.CodeType.ETS).registry(), 
                    // 编译 js 源码
                    new compile_node_js.CompileNode(this._taskService, code_type_enum_js.CodeType.JS).registry(), 
                    // Native 代码编译任务
                    new compile_native_js.CompileNative(this._taskService).registry()
                ), 
                // 编译 .so 文件
                new build_native_js.BuildNative(this._taskService).registry(), 
                // 收集hap和har依赖中的.so文件
                new process_libs_js.ProcessLibs(this._taskService).registry(), 
                // 系统能力转换
                new syscap_transform_js.SyscapTransform(this._taskService).registry(), 
                // 把生成的所有文件进行整合打包成 Hap 包
                new package_hap_js.PackageHap(this._taskService).registry(), 
                // 给打包好的 Hap 包签名
                new sign_hap_js.SignHap(this._taskService).registry()
            );
        };
        this._taskService = taskService;
        this._isFaMode = isFaMode;
    }
}

PreBuild

使用 Schema 校验配置文件

  • Stage 模型 : 校验 app.json5 和 module.json5
  • FA 模型 : 校验 config.json
// hvigor-ohos-plugin/src/tasks/pre-build.js
class PreBuild extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "PreBuild");
        this._log = ohos_logger_js.OhosLogger.getLogger(PreBuild.name);
    }
    doTaskAction(targetData, target) {
        // 验证版本信息 9 以下版本不支持 Stage 模型
        this.versionCheck();
        // 判断当前使用的模型
        if (this.service.getHapExtraInfo().isStageMode()) {
            // Stage 模型的 app.json5 和 module.json5文件校验
            this.appJson5Validate(target);
            this.moduleJson5Validate(target);
            this.validateHMServiceBundleName(target);
            if (this.service.getModuleModel()?.isHapModule()) {
                this.validateMainElementAndAbilities(target);
            }
        }
        else {
            // FA模型校验 config.json
            this.configJsonValidate(target);
        }
    }
    ···
}

CollectHarDependency

收集 package.json 中配置的 npm har 包依赖,并进行 har 构建
产物:[模块路径]build/[产品名称]/intermediates/merge_res/[目标名称]/merge_npm_res_file.json 和引入的 Har 模块下 Build 文件

// hvigor-ohos-plugin/src/tasks/collect-har-dependency.js
class CollectHarDependency extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "CollectHarDependency");
        this._log = ohos_logger_js.OhosLogger.getLogger(CollectHarDependency.name);
        this.npmHarCollection = [];
        this.localHarCollection = [];
        this.localHarNames = [];
        this.allDependencySet = new Set();
        this.projectProfile = taskService.getProjectModel().getProfileOpt();
        this.isStageMode = taskService.getHapExtraInfo().isStageMode();
    }
    doTaskAction(targetData, target) {
        // 获取项目级别和模块级别的 package.json 文件路径。
        const modulePkgJson = path.default.resolve(this.service.getModuleModel()?.getProjectDir(), common_const_js.CommonConst.PACKAGE_JSON);
        const projectPkgJson = path.default.resolve(this.service.getProjectModel()?.getProjectDir(), common_const_js.CommonConst.PACKAGE_JSON);

        // 获取合并后的产物路径,[模块路径]build/[产品名称]/intermediates/merge_res/[目标名称]/merge_npm_res_file.json
        const mergedNpmResFile = path.default.resolve(targetData.getPathInfo().getIntermediatesMergeRes(), build_directory_const_js.BuildArtifactConst.MERGE_NPM_FILE_JSON);

        this.npmHarCollection = [];
        this.allDependencySet = new Set();
        // 清空产物文件
        fs_extra.default.outputFileSync(mergedNpmResFile, "");
        // 读取 Module 配置文件判断当前 Module 是否为 hap 包,FA 模型读取 config.json/module.distro.moduleType,Stage 模型读取 module.json5/module.type,判断配置是否为 har
        if (this.service.getModuleModel()?.isHapModule()) {
            // 收集项目级别和模块级别 package.json 文件中的库文件路径
            this.collectNpmHarPaths([modulePkgJson, projectPkgJson]);
            for (const npmHarPath of this.npmHarCollection) {
                this._log.debug(`[HarNpm] Collect a har npm dependency: ${npmHarPath}`);
            }
        }
        // 将生成的配置信息写入产物文件
        fs_extra.default.outputJsonSync(mergedNpmResFile, {
            dependencies: this.npmHarCollection,
            local: {
                path: this.localHarCollection,
                name: this.localHarNames
            }
        });
        // 执行依赖的本地模块的构建任务
        this._log.debug(`LocalDependencies: %s`, this.localHarNames.join(', '));
        // 获取 nodejs 工具路径
        const nodeJsPath = node_util_js.findValidNodeExePath(this.service.getSdkInfo().getNodeJsDir());
        if (this.localHarNames.length > 0) {
            // 执行 Har 构建任务
            // node.exe node_modules/@ohos/hvigor/bin/hvigor.js -m module -p product=default -p module=BundleService@default assembleSubHar -d
            new process_utils_js.ProcessUtils(this.moduleName, this.taskName).executeSync
            (this.initExecuteCommand(this.localHarNames, nodeJsPath), {
                stdout: process.stdout,
                stderr: process.stderr
            });
        }
    }
    collectNpmHarPaths(pkgJsons) {
        const pkgQueue = pkgJsons;
        while (pkgQueue.length > 0) {
            // pkgQueue 中存放依赖中 package.json 的路径
            const curPkgJson = pkgQueue.shift();
            const curPkgPath = path.default.dirname(curPkgJson);
            const pkgObj = fs_extra.default.readJsonSync(curPkgJson, { throws: false });
            // 遍历 package.json 中 dependencies 配置项
            for (const pkgName in pkgObj === null || pkgObj === void 0 ? void 0 : pkgObj.dependencies) {
                // 获取该 npm 包的 package.json 路径
                const pkgJsonPath = resolve_package_path.default(pkgName, curPkgPath);
                if (pkgJsonPath === null) {
                    continue;
                }
                 //读取该 npm 包的 package.json 数据
                const packageJson = fs_extra.default.readJsonSync(pkgJsonPath, {
                    throws: false
                });
                // 获取该 npm 包的路径
                const pkgPath = path.default.dirname(pkgJsonPath);
                // 判断是否为 har包,判断 Npm 包路径下 module.json5 、 module.json 和 config.json 配置中 ModuleType 是否为 har
                if (!this.isValidHar(pkgPath)) {
                    continue;
                }
                // har包识别位,package.json中的name以@ohos/开头
                if (!(packageJson.name?.startsWith('@ohos/'))) {
                    continue;
                }
                // 考虑循环依赖,用set过滤重复项
                if (this.allDependencySet.has(packageJson.name)) {
                    continue;
                }
                // 添加 npm 包名称
                this.allDependencySet.add(packageJson.name);
                // 收集项目中所有模块的srcPath,跟pkgPath进行比对,识别出开发态/发布态的区别
                 this.projectProfile.modules?.forEach(obj => {
                    if (path.default.resolve(process.cwd(), obj.srcPath) === pkgPath) {
                        this.localHarCollection.push(pkgPath);
                        this.localHarNames.push(obj.name);
                    }
                    return obj.srcPath;
                });
                this.npmHarCollection.push(pkgPath);
                // 递归遍历当前 package.json 的 dependencies 配置项
                pkgQueue.push(pkgJsonPath);
            }
        }
    }
    ···
    initExecuteCommand(localHarNames, nodeJsPath) {
        const targets = localHarNames.map(name => {
            return `${name}@default`;
        });
        const command = [nodeJsPath, require.resolve("@ohos/hvigor/bin/hvigor"), "-m", "module"];
        command.push("-p");
        command.push(`product=default`);
        command.push("-p");
        command.push(`module=${targets.join(",")}`);
        command.push("assembleSubHar");
        command.push(this._log._getCliLevel());
        this._log._printDebugCommand("AssembleSubHar", command);
        return command;
    }
}

LegacyMergeProfile(FA) 和 MergeProfile(Stage)

以模块配置文件为主混合依赖的har配置文件和项目配置文件
产物:
FA模型
[模块路径]/build/[产品名称]/intermediates/merge_profile/[目标名称]/config.json
Stage模型
[模块路径]/build/[产品名称]/intermediates/merge_profile/[目标名称]/module.json

// hvigor-ohos-plugin/src/tasks/legacy-tasks/legacy-merge-profile.js
// 合并config.json
class LegacyMergeProfile extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "LegacyMergeProfile");
        this._log = ohos_logger_js.OhosLogger.getLogger(LegacyMergeProfile.name);
    }
    mergeDslConfig(configOpt) {
        // 从product处获取bundleName
        const bundleName = this._moduleTargetData?.getProduct().bundleName;
        const targetSdkVersion =this.service.getProjectModel()?.getCompileApiVersion();
        const compatibleSdkVersion = this.service.getProjectModel()?.getCompatibleApiVersion();
        const releaseType = this.service.getSdkInfo().getReleaseType();
        if (bundleName) {
            configOpt.app.bundleName = bundleName;
            this._appBundleName = bundleName;
            this._log.debug(`Change app bundleName with '${bundleName}'.`);
        }
        this._log.debug(`Change app target API version with '${targetSdkVersion}'`);
        this._log.debug(`Change app minimum API version with '${compatibleSdkVersion}'`);
        this._log.debug(`Change app releaseType with '${releaseType}'`);
        configOpt.app.apiVersion = {
            target: targetSdkVersion,
            compatible: compatibleSdkVersion,
            releaseType: releaseType
        };
    }
    doTaskAction(moduleTargetData, target) {
        this._moduleTargetData = moduleTargetData;
        // 获取 [模块路径]/src/main 路径
        const targetSourceSetModel = this.service.getModuleModel().getSourceSetByTargetName(target);
        // 获取模块的 config.json 配置数据
        const configOpt = targetSourceSetModel.getLegacyModuleTargetRes().getConfigJsonOpt();
        // 从 config.json 中获取 bundleName
        this._appBundleName = configOpt.app?.bundleName;
        // 从 config.json 中获取 deviceType
        const deviceType = configOpt.module.deviceType;
        // 判断是否为 Har 模块,并且 deviceType === 0
        if (this.service.getModuleModel().isHarModule() && deviceType.length === 0) {
            const cause = "The value of 'deviceType' in the config.json is empty.";
            const solution = "Please check the deviceType field in the config.json file is correctly configured.";
            this._log._buildError(cause)
                ._solution(solution)
                ._file(targetSourceSetModel.getLegacyModuleTargetRes().getJsonPath())
                ._printErrorAndExit();
        }
        // 获取 [模块路径]build/[产品名称]/intermediates/merge_res/[目标名称]/merge_npm_res_file.json 路径
        const mergedNpmResFile = path.default.resolve(moduleTargetData.getPathInfo().getIntermediatesMergeRes(), build_directory_const_js.BuildArtifactConst.MERGE_NPM_FILE_JSON);
        // 读取 npm 依赖配置
        const harList = fs.readJsonSync(mergedNpmResFile, { throws: false }).dependencies;
        const localModuleList = fs.readJsonSync(mergedNpmResFile, { throws: false }).local.path;

        // 遍历循环读取 npm 依赖配置项目中的配置文件
        const harLibs = [...lodash.difference(harList, localModuleList).map(harPath => {
                // 如果为发布态库则读取 src/main/config.json 配置文件
                return path.default.resolve(harPath, "src", "main", common_const_js.CommonConst.CONFIG_JSON);
            }), ...localModuleList.map(harPath => {
                // 如果为开发态库则读取 build/default/intermediates/merge_profile/default/config.json 配置文件
                return path.default.resolve(harPath, build_directory_const_js.BuildDirConst.BUILD_ROOT, "default", build_directory_const_js.BuildDirConst.INTERMEDIATES, build_directory_const_js.BuildDirConst.INTERMEDIATES_MERGE_PROFILE, "default", common_const_js.CommonConst.CONFIG_JSON);
            })];
        const harConfigOpts = harLibs.map(harConfigJson => {
            if (fs.pathExistsSync(harConfigJson)) {
                return project_file_reader_js.ProjectFileReader.getJson5Obj(harConfigJson);
            }
            else {
                this._log.warn(`${harConfigJson} does not exist. This library will not be 
                merged. Please confirm the correctness of this module.`);
            }
        });
        // 合并 hapConfig 和所有 harConfig
        const mergedConfigOpt = this.mergeAllConfig(configOpt, harConfigOpts);
        // 用项目配置覆盖模块的bundleName和api版本信息
        this.mergeDslConfig(mergedConfigOpt);
        // 从命令行读取 debuggable 配置
        const debuggable = hvigor_base.vigorConfigInst.getExtraConfig().get(common_const_js.CommonConst.DEBUGGABLE);
        // 如果 debuggable 未配置或为 true
        if (debuggable === undefined || debuggable) {
            const deviceConfigObj = mergedConfigOpt.deviceConfig;
            if (deviceConfigObj.default === undefined) {
                mergedConfigOpt.deviceConfig.default = {};
            }
            mergedConfigOpt.deviceConfig.default.debug = true;
        }
        // 获取产物路径 [模块路径]/build/[产品名称]/intermediates/merge_profile/[目标名称]/config.json
        const pathInfo = moduleTargetData.getPathInfo();
        const mergedModuleJson = pathInfo.getIntermediatesMergeLegacyProfile();
        // 将合并的配置写入文件
        fs.outputJSONSync(mergedModuleJson, mergedConfigOpt, { spaces: "\t" });
    }
    // 合并hapConfig和所有harConfig
    mergeAllConfig(mainConfig, harConfigOpts) {
        for (const harModuleOpt of harConfigOpts) {
            // api版本兼容,hap的compatible要大于等于三方包的compatible
            if ((harModuleOpt.app.apiVersion?.compatible) > (mainConfig.app.apiVersion?.compatible)) {
                this._log._buildError(`The compatible version of har module 
                ${harModuleOpt.module.name} is lower than hap module.`)
                    ._printErrorAndExit(this.moduleModel.getName());
            }
            // 合并 config 文件,以 hap 的配置文件为主
            mainConfig = this.mergeModel(mainConfig, harModuleOpt, "config");
        }
        return mainConfig;
    }
    ···
}
// hvigor-ohos-plugin/src/tasks/merge-profile.js
// 合并 module.json
class MergeProfile extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "MergeProfile");
        this._log = ohos_logger_js.OhosLogger.getLogger(MergeProfile.name);
    }
    doTaskAction(moduleTargetData, target) {
        this._moduleTargetData = moduleTargetData;
        // 获取项目实例
        const projectModel = this.service.getProjectModel();
        // 获取项目级别配置文件 app.json5
        const appJson = projectModel.getAppRes().getAppResOpt();
        // 如果当前模块是har模块则剔除与资源相关的字段
        if (this.service.getModuleModel().isHarModule()) {
            delete appJson.app.icon;
            delete appJson.app.label;
        }
        // 获取 [模块路径]/src/main 路径
        const targetSourceSetModel = this.service.getModuleModel().getSourceSetByTargetName(target);
        // 获取模块的 module.json5 配置数据
        const moduleOpt = targetSourceSetModel.getModuleTargetRes().getModuleJsonOpt();
        // 获取 Module 配置的 deviceTypes 信息
        const deviceTypes = moduleOpt.module.deviceTypes;
        // 判断是否为 Har 模块,并且 deviceType === 0
        if (this.service.getModuleModel().isHarModule() && deviceTypes.length === 0) {
            const cause = "The value of 'deviceType' in the module.json5 is empty.";
            const solution = "Please check the deviceType field in the module.json5 file is correctly configured.";
            this._log._buildError(cause)
                ._solution(solution)
                ._file(targetSourceSetModel.getModuleTargetRes().getJsonPath())
                ._printErrorAndExit();
        }
        // 获取 [模块路径]build/[产品名称]/intermediates/merge_res/[目标名称]/merge_npm_res_file.json 路径
        const mergedNpmResFile = path.default.resolve(moduleTargetData.getPathInfo().getIntermediatesMergeRes(), build_directory_const_js.BuildArtifactConst.MERGE_NPM_FILE_JSON);
        // 读取 npm 依赖配置
        const harList = fs.readJsonSync(mergedNpmResFile, { throws: false }).dependencies;
        const localModuleList = fs.readJsonSync(mergedNpmResFile, { throws: false }).local.path;
        // 遍历循环读取 npm 依赖配置项目中的配置文件
        const harLibs = [...lodash.difference(harList, localModuleList).map(harPath => {
                // 如果为发布态库则读取 src/main/module.json 配置文件
                return path.default.resolve(harPath, "src", "main", common_const_js.CommonConst.MODULE_JSON);
            }), ...localModuleList.map(harPath => {
                // 如果为开发态库则读取 build/default/intermediates/merge_profile/default/module.json 配置文件
                return path.default.resolve(harPath, build_directory_const_js.BuildDirConst.BUILD_ROOT, "default", build_directory_const_js.BuildDirConst.INTERMEDIATES, build_directory_const_js.BuildDirConst.INTERMEDIATES_MERGE_PROFILE, "default", common_const_js.CommonConst.MODULE_JSON);
            })];
        harLibs.map(harModuleJson => {
            if (fs.pathExistsSync(harModuleJson)) {
                return project_file_reader_js.ProjectFileReader.getJson5Obj(harModuleJson);
            }
            else {
                this._log.warn(`${harModuleJson} does not exist. This library will not be 
                merged. Please confirm the correctness of this module.`);
            }
        });
        // 合并 appJson 和 moduleOpt 配置
        const mergedConfigOpt = Object.assign(Object.assign({}, appJson), (moduleOpt));
        // 用项目配置覆盖模块的bundleName和api版本信息
        this.mergeDslConfig(mergedConfigOpt);
        // 从命令行读取 debuggable 配置
        const debuggable = hvigor_base.vigorConfigInst.getExtraConfig().get(common_const_js.CommonConst.DEBUGGABLE);
         // 如果 debuggable 未配置或为 true
        if (debuggable === undefined || debuggable !== "false") {
            mergedConfigOpt.app.debug = true;
        }
        // 获取产物路径 [模块路径]/build/[产品名称]/intermediates/merge_profile/[目标名称]/module.json
        const pathInfo = moduleTargetData.getPathInfo();
        const mergedModuleJson = pathInfo.getIntermediatesMergeProfile();
        // 将合并的配置写入文件
        fs.outputJSONSync(mergedModuleJson, mergedConfigOpt, { spaces: "\t" });
    }
    ···
}

LegacyProcessProfile(FA)和 ProcessProfile(Stage)

处理配置文件
产物:
FA模型
[模块路径]/build/[产品名称]/intermediates/process_profile/[目标名称]/config.json
Stage模型
[模块路径]/build/[产品名称]/intermediates/process_profile/[目标名称]/module.json

// hvigor-ohos-plugin/src/tasks/legacy-tasks/legacy-process-profile.js
// FA 模型处理 config.json 配置文件
class LegacyProcessProfile extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "LegacyProcessProfile");
    }
    doTaskAction(moduleTargetData, target) {
        const pathInfo = moduleTargetData.getPathInfo();
        // 获取合并后的配置文件数据
        const mergedConfigOpt = project_file_reader_js.ProjectFileReader.getJson5Obj(pathInfo.getIntermediatesMergeLegacyProfile());
        // 获取产物路径 [模块路径]/build/[产品名称]/intermediates/process_profile/[目标名称]/config.json
        const processedModuleJson = pathInfo.getIntermediatesProcessLegacyProfile();
        // 读取模块级别 build-profile.json5 配置文件中 buildOption.arkEnable 配置信息
        if (this.service.isArkModule()) {
            // 获取合并后的配置文件中 module.distro 配置信息
            const distroObj = mergedConfigOpt.module.distro;
            if (distroObj != undefined) {
                // 在配置文件中添加 module.distro.virtualMachine 配置参数,如果使用 js 开发则需要配置版本信息,ets 则默认为 ark
                mergedConfigOpt.module.distro.virtualMachine = `ark${this.service.getSdkInfo().getJsArkVersion()}`;
            }
            fs.outputJSONSync(processedModuleJson, mergedConfigOpt);
        }
        else {
            fs.outputJSONSync(processedModuleJson, mergedConfigOpt);
        }
    }
}
// hvigor-ohos-plugin/src/tasks/process-profile.js
// Stage 模型处理 module.json 配置文件
class ProcessProfile extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "ProcessProfile");
    }
    doTaskAction(moduleTargetData, target) {
        // 读取模块级别 build-profile.json5 配置文件中 buildOption.arkEnable 配置信息
        const arkEnable = this.service.isArkModule();
        const pathInfo = moduleTargetData.getPathInfo();
        // 获取合并后的配置文件数据
        const mergedModuleOpt = project_file_reader_js.ProjectFileReader.getJson5Obj(pathInfo.getIntermediatesMergeProfile());
        mergedModuleOpt.module.virtualMachine = arkEnable ? "ark" : "default";
        // 获取产物路径 [模块路径]/build/[产品名称]/intermediates/process_profile/[目标名称]/module.json
        const processedModuleJson = pathInfo.getIntermediatesProcessProfile();
        fs.outputJSONSync(processedModuleJson, mergedModuleOpt, { spaces: "\t" });
    }
}

MergeResource(Stage)

合并资源到index文件中
产物:[模块路径]/build/[产品名称]/intermediates/merge_res/[目标名称]/merge_res_file.index

// hvigor-ohos-plugin/src/tasks/merge-resource.js
class MergeResource extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "MergeResource");
    }
    doTaskAction(targetData, target) {
        const moduleModel = this.service.getModuleModel();
        const moduleType = moduleModel.getModuleType();
        if (!moduleType) {
            return;
        }
        const pathInfo = targetData.getPathInfo();
        const mergeResDir = pathInfo.getIntermediatesMergeRes();
        // 获取产物路径 [模块路径]/build/[产品名称]/intermediates/merge_res/[目标名称]/merge_res_file.index
        const mergeFile = pathInfo.getIntermediatesMergeFile();
        // 验证文件夹和文件
        file_util_js.FileUtil.checkDirWithoutDelete(mergeResDir);
        file_util_js.FileUtil.checkFile(mergeFile);
        // 把代码根路径 [模块路径]/src/main 写进 merge_res_file.index 文件中,os.EOL属性是一个常量,返回当前操作系统的换行符(Windows系统是\r\n,其他系统是\n)
        fs.default.writeFileSync(mergeFile, `"${moduleModel.getSourceSetByTargetName(target).getSourceSetRoot()}"${os.default.EOL}`);
    }
}

LegacyCompileResource(FA)和 CompileResource(Stage)

编译资源文件
产物:
FA模型
[模块路径]/build/[产品名称]/intermediates/res/[目标名称]
[模块路径]/build/[产品名称]/intermediates/res/[目标名称]/ResourceTable.txt
Stage模型
[模块路径]/build/[产品名称]/intermediates/res/[目标名称]
[模块路径]/build/[产品名称]/generated/r/[目标名称]/ResourceTable.h

// hvigor-ohos-plugin/src/tasks/legacy-tasks/legacy-compile-resource.js
// FA 模型资源编译任务
class LegacyCompileResource extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, 'CompileResource');
        this._log = ohos_logger_js.OhosLogger.getLogger(LegacyCompileResource.name);
    }
    doTaskAction(targetData, target) {
        // 获取 SDK 信息实例
        const sdkInfo = this.service.getSdkInfo();
        const moduleModel = this.service.getModuleModel();
        const pathInfo = targetData.getPathInfo();
        // 获取 process_profile 配置文件路径 [模块路径]/build/[产品名称]/intermediates/process_profile/[目标名称]/config.json
        const processJson = pathInfo.getIntermediatesProcessLegacyProfile();
        // 读取配置信息
        const configInfo = project_file_reader_js.ProjectFileReader.getJson5Obj(processJson);
        // 获取产物目录路径 [模块路径]/build/[产品名称]/intermediates/res/[目标名称]
        const outputDir = pathInfo.getIntermediatesRes();
        file_util_js.FileUtil.checkDirWithoutDelete(outputDir);
        // 获取 Restool 构造器
        const restoolBuilder = new restool_command_builder_js.RestoolCommandBuilder(sdkInfo.getRestool());
        // 获取har依赖 dependencies 信息 [模块路径]/build/[产品名称]/intermediates/merge_res/[目标名称]/merge_npm_res_file.json
        const harList = project_file_reader_js.ProjectFileReader.getJson5Obj(path.default.resolve(targetData.getPathInfo().getIntermediatesMergeRes(), build_directory_const_js.BuildArtifactConst.MERGE_NPM_FILE_JSON)).dependencies;
        // 把 har 依赖的代码根路径放入 Restool 构造器
        harList.forEach(harPath => {
            restoolBuilder.addInputDir(path.default.resolve(harPath, "src", "main"));
        });
        // 把 Module 的代码根路径放入 Restool 构造器
        restoolBuilder.addInputDir(moduleModel.getSourceSetByTargetName(target).getSourceSetRoot())
            .addJsonFile(processJson) // 配置配置文件路径 process_profile 的 config.json
            .addModulePackName(configInfo.app.bundleName) // 配置包名 process_profile 的 app.bundleName 配置项
            .addOutputDir(outputDir) // 配置产物输出目录
            .forceDelete()
            .addModules([...new Set([
                this.moduleModel.getName(),
                this.moduleModel.getSourceSetByTargetName(target)
                    .getLegacyModuleTargetRes().getConfigJsonOpt().module.distro.moduleName
            ])].join(','));
        const isShellMode = false;
        if (isShellMode) {
            // 生成的ResourceTable.txt路径 
            restoolBuilder
                .addResTable(path.default.resolve(this.getTaskTempDir(targetData), build_directory_const_js.BuildArtifactConst.RESOURCE_TABLE_JAVA))
                .addOutputBak(this.getTaskTempDir(targetData));
        }
        else {
            // 获取产物文件 ResourceTable.txt路径 [模块路径]/build/[产品名称]/intermediates/res/[目标名称]/ResourceTable.txt
            restoolBuilder.addResTable(path.default.resolve(outputDir, build_directory_const_js.BuildArtifactConst.RESOURCE_TABLE_TXT));
        }
        const commands = restoolBuilder.build();
        this._log._printDebugCommand("restool", commands);
        // 执行编译资源指令
        // [toolchains工具路径]/restool 
        // -i [模块路径]/src/main 
        // -i [har模块路径]/src/main  // 如果存在依赖 har 包
        // -j [模块路径]/build/[产品名称]/intermediates/process_profile/[目标名称]/config.json 
        // -p [bundleName] 
        // -o [模块路径]/build/[产品名称]/intermediates/res/[目标名称] 
        // -f -m [模块名称] 
        // -r [模块路径]/build/[产品名称]/intermediates/res/[目标名称]/ResourceTable.txt
        new process_utils_js.ProcessUtils(this.moduleName, this.taskName).executeSync(commands);
    }
}
// hvigor-ohos-plugin/src/tasks/compile-resource.js
// Stage 模型资源编译任务
class CompileResource extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "CompileResource");
        this._log = ohos_logger_js.OhosLogger.getLogger(CompileResource.name);
    }
    ···
    doTaskAction(targetData, target) {
        const pathInfo = targetData.getPathInfo();
        const projectModel = this.moduleModel.getParentProject();
        // 获取 process_profile 配置文件路径 [模块路径]/build/[产品名称]/intermediates/process_profile/[目标名称]/module.json
        const processJson = pathInfo.getIntermediatesProcessProfile();
        // 读取配置信息
        const appOpt = project_file_reader_js.ProjectFileReader.getJson5Obj(processJson);
        // 获取产物目录路径 [模块路径]/build/[产品名称]/intermediates/res/[目标名称]
        const outputDir = pathInfo.getIntermediatesRes();
        file_util_js.FileUtil.checkDirWithoutDelete(outputDir);
        file_util_js.FileUtil.checkDirWithoutDelete(pathInfo.getGenerateSourceR());
        // 获取 Restool 构造器
        const restoolBuilder = new restool_command_builder_js.RestoolCommandBuilder(this.sdkInfo.getRestool());
        // 获取har依赖 dependencies 信息 [模块路径]/build/[产品名称]/intermediates/merge_res/[目标名称]/merge_npm_res_file.json
        const harList = project_file_reader_js.ProjectFileReader.getJson5Obj(path.default.resolve(targetData.getPathInfo().getIntermediatesMergeRes(), build_directory_const_js.BuildArtifactConst.MERGE_NPM_FILE_JSON)).dependencies;
        // 把 har 依赖的代码根路径放入 Restool 构造器
        harList.forEach(harPath => {
            restoolBuilder.addInputDir(path.default.resolve(harPath, "src", "main"));
        });
        // 把 Module 的代码根路径放入 Restool 构造器
        restoolBuilder.addInputDir(this.moduleModel.getSourceSetByTargetName(target).getSourceSetRoot());
        // 判断是否为 hap 类型的 Module
        if (this.service.getModuleModel().isHapModule()) {
            // 把 App 级别资源路径放入 Restool 构造器
            restoolBuilder.addInputDir(path.default.resolve(projectModel.getAppRes().getResourcePath(), "..")); // app级别的资源
        }
        restoolBuilder.addJsonFile(processJson) // 配置配置文件路径 process_profile 的 module.json
            .addModulePackName(appOpt.app.bundleName) // 配置包名 process_profile 的 app.bundleName 配置项
            .addOutputDir(outputDir)
            // 获取产物文件 ResourceTable.h 路径 [模块路径]/build/[产品名称]/generated/r/[目标名称]/ResourceTable.h
            .addResTable(path.default.resolve(pathInfo.getGenerateSourceR(), build_directory_const_js.BuildArtifactConst.RESOURCE_TABLE_H))
            .forceDelete()
            .addModules([...new Set([
                this.moduleModel.getName(),
                this.moduleModel.getSourceSetByTargetName(target)
                    .getModuleTargetRes().getModuleJsonOpt().module.name
            ])].join(','));
        const commands = restoolBuilder.build();
        this._log._printDebugCommand("Restool", commands);
        // 执行编译资源指令
        // [toolchains工具路径]/restool 
        // -i [模块路径]/src/main 
        // -i [项目路径]/AppScope
        // -i [har模块路径]/src/main  // 如果存在依赖 har 包
        // -j [模块路径]/build/[产品名称]/intermediates/process_profile/[目标名称]/module.json 
        // -p [bundleName] 
        // -o [模块路径]/build/[产品名称]/intermediates/res/[目标名称] 
        // -f -m [模块名称] 
        // -r [模块路径]/build/[产品名称]/generated/r/[目标名称]/ResourceTable.h
        new process_utils_js.ProcessUtils(this.moduleName, this.taskName).executeSync(commands);
    }
}

LegacyGenerateJsManifest(FA)

遍历模块 Ability 信息生成 JsManifest.json 文件
产物:[模块路径]/build/[产品名称]/intermediates/manifest/[目标名称]/[Ability路径]/manifest.json

// hvigor-ohos-plugin/src/tasks/legacy-tasks/legacy-generate-js-manifest.js
class LegacyGenerateJsManifest extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "GenerateJsManifest");
        this._log = ohos_logger_js.OhosLogger.getLogger(LegacyGenerateJsManifest.name);
        this.previewSrcPath = hvigor_base.vigorConfigInst.getExtraConfig().get(SRC_PATH);
        this.previewPage = hvigor_base.vigorConfigInst.getExtraConfig().get(PAGE);
    }
    doTaskAction(targetData, target) {
        const moduleModel = this.service.getModuleModel();
        // 获取 Module 中所有的 Ability
        const abilityObjs = moduleModel.getLegacyAbilities(target);
        for (let i = 0; i < abilityObjs.length; i++) {
            const abilityInfo = abilityObjs[i];
            // 判断 ability 类型,如果不是 page 或 form 则不生成 manifest.js
            if (abilityInfo.getType() !== ability_type_enum_js.AbilityTypeEnum.PAGE &&
                abilityInfo.getType() !== ability_type_enum_js.AbilityTypeEnum.FORM) {
                continue;
            }
            this.generateJsonInfo(abilityObjs[i], moduleModel.getJsonObjByTargetName(target), targetData.getPathInfo());
        }
    }
    ···
    generateJsonInfo(legacyAbilityInfo, configJsonObj, targetPathInfo) {
        // 获取项目实例
        const parentProject = this.service.getModuleModel().getParentProject();
        // 从配置文件中获取信息
        let manifestObj = {
            appID: configJsonObj.app.bundleName,
            versionName: configJsonObj.app.version.name,
            versionCode: configJsonObj.app.version.code,
            minPlatformVersion: parentProject.getProfileOpt().app.compatibleSdkVersion,
            appName: LegacyGenerateJsManifest.findAppName(configJsonObj),
            deviceType: configJsonObj.module.deviceType,
            window: LegacyGenerateJsManifest.getWindowObj(legacyAbilityInfo),// 获取 config.json 中 js.window
            pages: this.getManifestPages(legacyAbilityInfo)
        };
        const mode = legacyAbilityInfo.getConfigJsonJsObj()?.mode;
        const type = legacyAbilityInfo.getType() === ability_type_enum_js.AbilityTypeEnum.FORM ?
            ability_type_enum_js.AbilityTypeEnum.FORM : legacyAbilityInfo.getConfigJsonJsObj()?.type;
        if (mode) {
            manifestObj = Object.assign(Object.assign({}, manifestObj), { mode: mode });
        }
        else if (type) {
            manifestObj = Object.assign(Object.assign({}, manifestObj), { type: type });
        }
        this._log._printDebugCommand("JsManifest", manifestObj);
        // 获取产物路径 [模块路径]/build/[产品名称]/intermediates/manifest/[目标名称]/[Ability路径]/manifest.json
        const manifestFile = path.resolve(targetPathInfo.getIntermediatesLegacyManifestJson(), legacyAbilityInfo.getRelateSrcPath(), build_directory_const_js.BuildArtifactConst.LEGACY_MANIFEST_JSON);
        // 输出文件
        fse.outputJSONSync(manifestFile, manifestObj);
    }
    ···
}

GenerateLoaderJson

生成loader需要的json文件
产物:[模块路径]/build/[产品名称]/intermediates/loader/[目标名称]/loader.json

// hvigor-ohos-plugin/src/tasks/generate-loader-json.js
class GenerateLoaderJson extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, 'GenerateLoaderJson');
        this._log = ohos_logger_js.OhosLogger.getLogger(GenerateLoaderJson.name);
    }
    doTaskAction(targetData, target) {
        // 获取产物路径 [模块路径]/build/[产品名称]/intermediates/loader/[目标名称]/loader.json
        const aceLoaderJson = path.default.resolve(targetData.getPathInfo().getIntermediatesLoaderPath(), 'loader.json');
        const workers = [];
        const moduleModel = this.service.getModuleModel();
        // 获取模块级别 build-profile.json5 配置文件中 buildOption.sourceOption.workers 配置信息
        moduleModel.getProfileOpt().buildOption?.sourceOption?.workers?.forEach((workerPath) => {
            const workerAbsolutePath = path.default.isAbsolute(workerPath) ?
                workerPath : path.default.resolve(moduleModel.getProjectDir(), workerPath);
            // 判断配置的路径是否在项目中
            if (property_get_js.Property.normalizePathSeparator(workerAbsolutePath).startsWith(property_get_js.Property.normalizePathSeparator(this.moduleModel.getProjectDir()))) {
                workers.push(workerAbsolutePath);
            }
            else {
                this._log._buildError(`${workerPath} is not under ${this.moduleModel.getProjectDir()}`)
                    ._solution(`modify ${workerPath} in build-profile.json5`)
                    ._file(this.moduleModel.getProfilePath())
                    ._printErrorAndExit();
            }
        });
        if (workers.length === 0) {
            return;
        }
        // 输出文件
        fse.outputJSONSync(aceLoaderJson, {
            workers: workers
        });
    }
    beforeTask(targetData) {
        const aceLoaderPath = targetData.getPathInfo().getIntermediatesLoaderPath();
        fse.removeSync(aceLoaderPath);
    }
}

LegacyCompileNode(FA)和 CompileNode(Stage)

编译 js/ets 源码
产物:
FA模型
[模块路径]/build/[产品名称]/intermediates/assets/[目标名称]/js/[Ability路径]
Stage模型
[模块路径]/build/[产品名称]/intermediates/assets/[目标名称]/ets

// hvigor-ohos-plugin/src/tasks/legacy-tasks/legacy-compile-node.js
// FA 模型编译 js/ets 源码
class LegacyCompileNode extends compile_node_js.CompileNode {
    constructor(taskService, codeType) {
        super(taskService, codeType);
        this._logger = ohos_logger_js.OhosLogger.getLogger(LegacyCompileNode.name);
    }
    doTaskAction(targetData, target) {
        const moduleModel = this.service.getModuleModel();
        // 获取 js/ets 源码实例
        const codeModel = moduleModel.getSourceSetByTargetName(target).getCodeMap().get(this.codeType);
        if (codeModel === undefined) {
            this._logger.debug(`Cannot find '${this.codeType}' source.`);
            return;
        }
        // 获取 js/ets 源码路径
        const aceModuleRoot = codeModel.getSrcPath();
        const pathInfo = targetData.getPathInfo();
        // 获取 ResourceTable.txt 路径 [模块路径]/build/[产品名称]/intermediates/res/[目标名称]/ResourceTable.txt
        const resourceTxt = path.default.resolve(pathInfo.getIntermediatesRes(), build_directory_const_js.BuildArtifactConst.RESOURCE_TABLE_TXT);
        // 获取 manifest.json 路径 [模块路径]/build/[产品名称]/intermediates/manifest/[目标名称]
        const aceManifestPath = path.default.resolve(pathInfo.getIntermediatesLegacyManifestJson());
        // 输出路径 FA 模型中, 不管源码是ets还是js, 都输出到js目录下 [模块路径]/build/[产品名称]/intermediates/assets/[目标名称]/js
        const aceModuleBuild = path.default.resolve(targetData.getPathInfo().getIntermediatesAssetsPath(), code_type_enum_js.CodeType.JS);
        // nodejs 路径
        const nodeJsDir = node_util_js.findValidNodeDir(this.sdkInfo.getNodeJsDir());
        // 根据代码类型获取不同的编译模型
        const loader = this.codeType === code_type_enum_js.CodeType.ETS ?
            this.sdkInfo.getEtsLoader() : this.sdkInfo.getJsLoader();
        // 获取 Module 的所有 Ability
        const abilityObjs = moduleModel.getLegacyAbilities(target);
        for (let i = 0; i < abilityObjs.length; i++) {
            const abilityInfo = abilityObjs[i];
            if (abilityInfo.getSrcLanguage() !== this.codeType) {
                continue;
            }
            let cmdEnv = Object.assign(Object.assign({}, this.commonOption), { 'abilityType': abilityInfo.getType(), 'aceManifestPath': path.default.resolve(aceManifestPath, abilityInfo.getRelateSrcPath(), build_directory_const_js.BuildArtifactConst.LEGACY_MANIFEST_JSON), 'appResource': resourceTxt, 'aceModuleRoot': path.default.resolve(aceModuleRoot, abilityInfo.getRelateSrcPath()), 'aceModuleBuild': path.default.resolve(aceModuleBuild, abilityInfo.getRelateSrcPath()), 'cachePath': this.getTaskTempDir(targetData), 'aceSuperVisualPath': path.default.resolve(moduleModel.getSourceRootByTargetName(target), 'supervisual', abilityInfo.getRelateSrcPath()) });
            console.log(`hvigor-ohos-plugin/src/tasks/legacy-tasks/legacy-compile-node.js cmdEnv : ${cmdEnv}`)
            const aceLoaderJson = path.default.resolve(pathInfo.getIntermediatesLoaderPath(), 'loader.json');
            cmdEnv = fse.existsSync(aceLoaderJson) ? Object.assign(Object.assign({}, cmdEnv), { aceBuildJson: aceLoaderJson }) : cmdEnv;
            /*{
              path: [nodejs工具路径],
              watchMode: 'false',
              abilityType: [abilityType],
              aceManifestPath: '[模块路径]/build/[产品名称]/intermediates/manifest/[目标名称]/[Ability路径]/manifest.json',
              appResource: '[模块路径]/build/[产品名称]/intermediates/res/[目标名称]/ResourceTable.txt',
              aceModuleRoot: '[模块路径]/src/main/ets/[Ability路径]',
              aceModuleBuild: '[模块路径]/build/[产品名称]/intermediates/assets/[目标名称]/js/[Ability路径]',
              cachePath: '[模块路径]/build/[产品名称]/cache/[目标名称]/CompileETS',
              aceSuperVisualPath: '[模块路径]/src/main/supervisual/[Ability路径]'
            }*/
            this.doRealLoaderCompile(nodeJsDir, loader, cmdEnv);
            this.moveReleaseMap(targetData, abilityInfo.getRelateSrcPath());
        }
    }
}
// hvigor-ohos-plugin/src/tasks/compile-node.js
// FA 模型和 Stage 模型编译 js/ets 源码
class CompileNode extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService, codeType) {
        super(taskService, `Compile${codeType.toUpperCase()}`);
        this._log = ohos_logger_js.OhosLogger.getLogger(CompileNode.name);
        this.commonOption = {
            'path': node_util_js.findValidNodeDir(this.sdkInfo.getNodeJsDir()),
            'watchMode': 'false',
        };
        this.codeType = codeType;
    }
    doTaskAction(targetData, target) {
        this.doRealLoaderCompile(node_util_js.findValidNodeDir(this.sdkInfo.getNodeJsDir(), this.codeType === code_type_enum_js.CodeType.ETS ? this.sdkInfo.getEtsLoader() : this.sdkInfo.getJsLoader(), this.generateLoaderEnv(targetData));
        this.moveReleaseMap(targetData);
    }
    ···
    // 移动_releaseMap到临时目录
    moveReleaseMap(targetData, abilityPath = '.') {
        // 获取map路径 [模块路径]/build/[产品名称]/intermediates/assets/[目标名称]/[codeType]/[abilityPath]/_releaseMap
        const reMapDir = path.default.resolve(targetData.getPathInfo().getIntermediatesAssetsPath(), this.codeType, abilityPath, build_directory_const_js.BuildArtifactConst.RELEASE_MAP);
        if (!fse.existsSync(reMapDir)) {
            return;
        }
        // 获取map临时路径 [模块路径]/build/[产品名称]/cache/[目标名称]/[abilityPath]/_releaseMap
        const tempDir = path.default.resolve(this.getTaskTempDir(targetData), abilityPath, build_directory_const_js.BuildArtifactConst.RELEASE_MAP);
        if (fse.existsSync(tempDir)) {
            fse.removeSync(tempDir);
        }
        fse.moveSync(reMapDir, tempDir);
        this._log.debug(`move ${reMapDir} to ${tempDir}`);
    }
    // 执行编译
    doRealLoaderCompile(nodeJsDir, workDir, cmdEnv) {
        // 从命令行读取 debuggable 配置信息
        const debuggable = hvigor_base.vigorConfigInst.getExtraConfig().get(common_const_js.CommonConst.DEBUGGABLE);
        const nodeCommandBuilder = new node_command_builder_js.NodeCommandBuilder(nodeJsDir, true)
            .addWebpackPath('./node_modules/webpack/bin/webpack.js')
            // 如果 CodeType 为 ETS 则使用 webpack.config.js 如果非 ETS 则使用 webpack.rich.config.js
            .addWebpackConfig(this.codeType === code_type_enum_js.CodeType.ETS ? common_const_js.CommonConst.ETS_WEBPACK_FILE : common_const_js.CommonConst.ACE_RICH_WEBPACK_FILE)
            // buildMode = isDebug ? "debug" : "release";
            .addBuildMode(debuggable === undefined || debuggable !== "false");
        if (this.moduleModel.isArkModule()) {
            nodeCommandBuilder.addCompilerType('ark');
        }
        this._log._printDebugCommand("NodeEnv", cmdEnv);
        this._log._printDebugCommand(`${this.codeType.toUpperCase()}-loader`, nodeCommandBuilder.build());
        const options = {
            cwd: workDir,
            env: cmdEnv
        };
        // 执行编译指令
        // node ./node_modules/webpack/bin/webpack.js --config,webpack.config.js --env buildMode=debug compilerType=ark 
        new process_utils_js.ProcessUtils(this.moduleName, this.taskName).executeSync(nodeCommandBuilder.build(), options);
    }
    generateLoaderEnv(targetData) {
        const pathInfo = targetData.getPathInfo();
        const cmdEnv = Object.assign(Object.assign({}, this.commonOption), { 'appResource': path.default.resolve(pathInfo.getIntermediatesRes(), build_directory_const_js.BuildArtifactConst.RESOURCE_TABLE_TXT), 'aceModuleBuild': path.default.resolve(pathInfo.getIntermediatesAssetsPath(), this.codeType), 'aceModuleRoot': this.codeModel.getSrcPath(), 'cachePath': this.getTaskTempDir(targetData), 'aceProfilePath': pathInfo.getIntermediatesResProfilePath(), 'aceModuleJsonPath': path.default.resolve(pathInfo.getIntermediatesRes(), common_const_js.CommonConst.MODULE_JSON), 'aceSuperVisualPath': path.default.resolve(this.moduleModel.getSourceRootByTargetName(targetData.getTargetName()), 'supervisual') });
        const aceLoaderJson = path.default.resolve(pathInfo.getIntermediatesLoaderPath(), build_directory_const_js.BuildArtifactConst.LOADER_JSON);
        return fse.existsSync(aceLoaderJson) ? Object.assign(Object.assign({}, cmdEnv), { aceBuildJson: aceLoaderJson }) : cmdEnv;
        /*{
          path: [nodejs工具路径],
          watchMode: 'false',
          appResource: '[模块路径]/build/[产品名称]/intermediates/res/[目标名称]/ResourceTable.txt',
          aceModuleBuild: '[模块路径]/build/[产品名称]/intermediates/assets/[目标名称]/ets',
          aceModuleRoot: '[模块路径]/src/main/ets',
          cachePath: '[模块路径]/build/[产品名称]/cache/[目标名称]/CompileETS',
          aceProfilePath: '[模块路径]/build/[产品名称]/intermediates/res/[目标名称]/resources/base/profile',
          aceModuleJsonPath: '[模块路径]/build/[产品名称]/intermediates/res/[目标名称]/module.json',
          aceSuperVisualPath: '[模块路径]/src/main/supervisual'
        }*/
    }
}

CompileNative

Native 代码编译任务
产物:[模块路径]/.cxx/default/default/[CPU架构]

// hvigor-ohos-plugin/src/tasks/compile-native.js 
class CompileNative extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "CompileNative");
        this._log = ohos_logger_js.OhosLogger.getLogger(CompileNative.name);
        this._moduleDir = this.moduleModel.getProjectDir();
        const profileOption = this.moduleModel.getProfileOpt();
        // 读取模块级别 build-profile.json5 配置文件 buildOption.externalNativeOptions 配置信息
        this._nativeOption = profileOption.buildOption.externalNativeOptions;
    }
    ···
    doTaskAction(targetData, target) {
        const pathInfo = targetData.getPathInfo();
        // 遍历模块支持的CPU架构,编译源码
        this._nativeOption.abiFilters?.forEach(abiFilter => {
            this.buildCommand(abiFilter, target, pathInfo);
        });
    }
    buildCommand(abiFilter, target, pathInfo) {
        // 获取 SDK 中的 cmake 构造器
        const builder = new native_command_builder_js.NativeCommandBuilder(this.sdkInfo.getCmakeTool());
        const args = this.getArguments();
        if (0 !== args.length) {
            builder.addAllParams(args);
        }
        // 获取产物路径 [模块路径]/build/[产品名称]/intermediates/cmake/[目标名称]/obj/[CPU架构]
        const outputDir = path.default.resolve(pathInfo.getModuleBuildIntermediates(), 'cmake', target, 'obj', abiFilter);
        // 获取临时产物路径 [模块路径]/.cxx/default/default/[CPU架构]
        const tempDir = path.default.resolve(pathInfo.getCppOutputDir(), 'default', 'default', abiFilter);
        this.checkDir(outputDir);
        this.cleanCache(tempDir);
        builder.addCmakeList(this.getCmakeListDir())
            .addTempFilePath(tempDir)
            .addOhosArch(abiFilter)
            .addOutputDir(outputDir)
            .addBuildType('normal')
            .addNativeSdk(this.sdkInfo.getSdkNativeDir())
            .addSystemName('OHOS')
            .addOhosArchAbi(abiFilter)
            .exportCompileCommands('ON')
            .addToolChain(this.sdkInfo.getNativeToolchain())
            .addGenerator('Ninja')
            .addMakeProgramPath(this.sdkInfo.getNativeNinjaTool());
        if (this._nativeOption.cFlags) {
            builder.addCFlags(this._nativeOption.cFlags);
        }
        if (this._nativeOption.cppFlags && '' !== this._nativeOption.cppFlags) {
            builder.addCxxFlags(this._nativeOption.cppFlags);
        }
        const commands = builder.build();
        this._log._printDebugCommand("Ninja", commands);
        // 执行编译 Native C++ 指令
        // [native_SDK路径]/build-tools/cmake/bin/cmake -v 
        // -DOHOS_STL=c++_shared 
        // -H[模块路径]/src/main/cpp 
        // -B[模块路径]/.cxx/default/default/[CPU架构] 
        // -DOHOS_ARCH=[CPU架构] 
        // -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=[模块路径]/build/[产品名称]/intermediates/cmake/[目标名称]/obj/[CPU架构] 
        // -DCMAKE_BUILD_TYPE=normal 
        // -DOHOS_SDK_NATIVE=[native_SDK路径] 
        // -DCMAKE_SYSTEM_NAME=OHOS 
        // -DCMAKE_OHOS_ARCH_ABI=[CPU架构] 
        // -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 
        // -DCMAKE_TOOLCHAIN_FILE=[native_SDK路径]/build/cmake/ohos.toolchain.cmake 
        // -G Ninja 
        // -DCMAKE_MAKE_PROGRAM=[native_SDK路径]/build-tools/cmake/bin/ninja 
        new process_utils_js.ProcessUtils(this.moduleName, this.taskName).executeSync(commands);
    }
    ···
}

BuildNative

编译 .so 文件
产物:[模块路径]/build/[产品名称]/intermediates/cmake/[目标名称]/obj/[CPU架构]

// hvigor-ohos-plugin/src/tasks/build-native.js
class BuildNative extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "BuildNative");
        this._log = ohos_logger_js.OhosLogger.getLogger(BuildNative.name);
        this._moduleModel = taskService.getModuleModel();
        const profileOption = this._moduleModel.getProfileOpt();
        // 读取模块级别 build-profile.json5 配置文件 buildOption.externalNativeOptions 配置信息
        this._nativeOption = profileOption.buildOption.externalNativeOptions;
        this._sdkInfo = this.service.getSdkInfo();
    }
    buildCommand(abiFilter, target) {
        const builder = new native_command_builder_js.NativeCommandBuilder(this._ninjaPath)
            .changeToDir(path.default.resolve(this._moduleModel.getProjectDir(), '.cxx', 'default', 'default', abiFilter));
        const commands = builder.build();
        this._log._printDebugCommand("Cmake", commands);
        // 执行指令
        // [native_SDK路径]/build-tools/cmake/bin/ninja -C [模块路径]/.cxx/default/default/[CPU架构]
        new process_utils_js.ProcessUtils(this.moduleName, this.taskName).executeSync(commands);
    }
    doTaskAction(targetData, target) {
        const moduleModel = this.service.getModuleModel();
        const codeMap = moduleModel.getSourceSetByTargetName().getCodeMap();
        const pathInfo = targetData.getPathInfo();
        // 拼接输出文件夹路径 [模块路径]/build/[产品名称]/intermediates/cmake/[目标名称]/obj
        const outputDir = path.default.resolve(pathInfo.getModuleBuildIntermediates(), 'cmake', target, 'obj');
        // 清空输出文件夹
        if (fs_extra.default.existsSync(outputDir)) {
            fs_extra.default.emptyDirSync(outputDir);
        }
        // 确认模块为 CPP 代码模块
        if (!codeMap.has(code_type_enum_js.CodeType.CPP) || !this._nativeOption) {
            return;
        }
        // 获取 Ninja 工具路径
        this._ninjaPath = this._sdkInfo.getNativeNinjaTool();
        const profileOption = this._moduleModel.getProfileOpt();
        // 确认 abiFilters 配置不为空
        const abiFilters = profileOption.buildOption.externalNativeOptions.abiFilters;
        if (!abiFilters || 0 === abiFilters.length) {
            return;
        }
        abiFilters.forEach(abiFilter => {
            // 执行编译 .so 指令
            this.buildCommand(abiFilter, target);
            const outputFilterDir = path.default.resolve(outputDir, abiFilter);
            // 对编译后的文件做copy处理,拷贝 libc++.so 和 libc++_shared.so 文件
            this.copyLibSo(abiFilter, outputFilterDir, pathInfo);
        });
    }
    ···
}

ProcessLibs

收集hap和har依赖中的.so文件
产物:[模块路径]/build/[产品名称]/intermediates/libs/[目标路径]

// hvigor-ohos-plugin/src/tasks/process-libs.js
class ProcessLibs extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "ProcessLibs");
        this._log = ohos_logger_js.OhosLogger.getLogger(ProcessLibs.name);
        this._moduleModel = taskService.getModuleModel();
        this._moduleDir = this._moduleModel.getProjectDir();
    }
    doTaskAction(targetData, target) {
        const pathInfo = targetData.getPathInfo();
        // hap native构建产物路径 [模块路径]/build/[产品名称]/intermediates/cmake/[目标名称]/obj/
        const hapBuildLibs = path.default.resolve(pathInfo.getIntermediatesCppOutPut());
        // hap native依赖路径 [模块路径]/libs
        const hapLocalLibs = path.default.resolve(this._moduleDir, build_directory_const_js.BuildDirConst.LIBS);
        // har 依赖路径
        const harList = project_file_reader_js.ProjectFileReader.getJson5Obj(path.default.resolve(pathInfo.getIntermediatesMergeRes(), build_directory_const_js.BuildArtifactConst.MERGE_NPM_FILE_JSON)).dependencies;
        // har 本地模块依赖路径
        const localModuleList = project_file_reader_js.ProjectFileReader.getJson5Obj(path.default.resolve(pathInfo.getIntermediatesMergeRes(), build_directory_const_js.BuildArtifactConst.MERGE_NPM_FILE_JSON)).local.path;
        // har native依赖路径 
        const harLibs = [...lodash.difference(harList, localModuleList).map(harPath => {
                // [har路径]/libs 
                return path.default.resolve(harPath, build_directory_const_js.BuildDirConst.LIBS);
            }), ...localModuleList.map(harPath => {
                // [har路径]/build/default/intermediates/libs/default
                return path.default.resolve(harPath, build_directory_const_js.BuildDirConst.BUILD_ROOT, "default", build_directory_const_js.BuildDirConst.INTERMEDIATES, build_directory_const_js.BuildDirConst.LIBS, "default");
            })];
        const libsCollections = [...harLibs, hapBuildLibs, hapLocalLibs];
        this._log.debug(`Libs: ${libsCollections.join(os.default.EOL)}`);
        // 获取产物路径 [模块路径]/build/[产品名称]/intermediates/libs/[目标路径]
        const libsOutputDir = pathInfo.getIntermediatesProcessLibs();
        fs.emptyDirSync(libsOutputDir);
        // 收集所有的目标.so文件,存进set内
        const fullSet = {};
        libsCollections.forEach(libsPath => {
            const paths = glob.glob.sync("**/*.so", {
                cwd: libsPath
            });
            this._log.debug(`Collect files: ${paths}`);
            paths.forEach(soPath => {
                if (!fullSet[soPath]) {
                    fullSet[soPath] = [];
                }
                fullSet[soPath].push(path.default.resolve(libsPath, soPath));
            });
        });
        let flag = false;
        const errorLog = [];
        for (const key in fullSet) {
            const fileName = path.default.basename(key);
            const len = fullSet[key].length;
            if (len > 1 && !(fileName === "libc++.so" || fileName === "libc++_shared.so")) {
                flag = true;
                errorLog.push(`${len} files found for path 'lib/${key}'. This can cause unexpected errors at runtime.`);
                fullSet[key].forEach(value => {
                    errorLog.push(`- ${value}`);
                });
            }
        }
        if (flag) {
            this._log._buildError(errorLog.join(`${os.default.EOL}\t `))
                ._solution("Try to rename native compilation products of modules.")
                ._printErrorAndExit(this.moduleName);
        }
        // 复制所有收集的so文件到产物路径
        libsCollections.forEach(libsPath => {
            if (fs.pathExistsSync(libsPath)) {
                fs.copySync(libsPath, libsOutputDir);
            }
        });
    }
}

SyscapTransform

SysCap使用指南

系统能力转换
产物:[模块路径]/build/[产品名称]/intermediates/syscap/[目标名称]

// hvigor-ohos-plugin/src/tasks/syscap-transform.js
class SyscapTransform extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "SyscapTransform");
        this._log = ohos_logger_js.OhosLogger.getLogger(SyscapTransform.name);
        this.hapExtraInfo = taskService.getHapExtraInfo();
    }
    doTaskAction(targetData, target) {
        // 获取代码根目录路径
        const sourceRoot = this.service.getModuleModel()?.getSourceRootByTargetName(target);
        // 获取路径信息实例
        const pathInfo = targetData.getPathInfo();
        // 获取 SDK 信息实例
        const sdkInfo = this.service.getSdkInfo();
        // 获取 SDK eTS 文件夹
        const etsDir = sdkInfo.getSdkEtsDir();
        // 获取 SDK js 文件夹
        const jsDir = sdkInfo.getSdkJsDir();
        // 获取 eTS 系统能力定义路径 [eTS SDK 路径]/api/device-define/
        const etsRequireSysCapPath = sdkInfo.getSysCapFileInEts();
        // 获取 js 系统能力定义路径 [js SDK 路径]/api/device-define/
        const jsRequireSysCapPath = sdkInfo.getSysCapFileInJs();
        const regExp = /^SystemCapability(\.[a-zA-Z0-9]+){2,3}$/;
        let jsonFile;
        let deviceTypes;
        // 判断当前 Module 是不是 Stage 模型
        if (this.hapExtraInfo.isStageMode()) {
            const moduleJsonPath = path.default.resolve(sourceRoot, common_const_js.CommonConst.MODULE_JSON5);
            const moduleJson = project_file_reader_js.ProjectFileReader.getJson5Obj(moduleJsonPath);
            // 获取 module.json5 配置信息中 module.deviceTypes 信息
            deviceTypes = moduleJson.module.deviceTypes;
            jsonFile = moduleJsonPath;
        }
        else {
            const configJsonPath = path.default.resolve(sourceRoot, common_const_js.CommonConst.CONFIG_JSON);
            const configJson = project_file_reader_js.ProjectFileReader.getJson5Obj(configJsonPath);
            // 获取 config.json 配置信息中 module.deviceTypes 信息
            deviceTypes = configJson.module.deviceType;
            jsonFile = configJsonPath;
        }
        //  判断是否存在syscap.json,如果不存在syscap.json,那么不启动rpcid的处理逻辑
        const sysCapJsonPath = path.default.resolve(sourceRoot, common_const_js.CommonConst.SYSCAP_JSON);
        if (fs.existsSync(sysCapJsonPath)) {
            // 读取 syscap.json 配置文件
            const sysCapJson = project_file_reader_js.ProjectFileReader.getJson5Obj(sysCapJsonPath);
            const sysCapDevice = sysCapJson['devices'];
            const sysCapGeneral = sysCapDevice['general'];
            const sysCapCustom = sysCapDevice['custom'];
            const requireSysCapList = [];
            const nDeviceSysCapList = [];
            let intersectionSysCapList = [];
            //  纯N设备
            if (deviceTypes.length === 0) {
                if (sysCapGeneral !== undefined && sysCapGeneral.length !== 0) {
                    const cause = "The value of 'general' in the syscap.json file must be " +
                        "the same as that of 'deviceType' in the module.json5/config.json file.";
                    const solution = "Please check whether the general field in the syscap.json file " +
                        "and the deviceType field in the module.json5 or config.json file are correctly configured.";
                    this._log._buildError(cause)
                        ._solution(solution)
                        ._file(sysCapJsonPath)
                        ._printErrorAndExit();
                }
                //  纯N设备之间SysCap取交集
                intersectionSysCapList = this.intersectNDeviceSysCap(sysCapCustom, nDeviceSysCapList, regExp, sysCapJsonPath);
            }
            else {
                if (sysCapGeneral === undefined
                    || !array_util_js.checkArrayElementIsSame(sysCapGeneral, deviceTypes)) {
                    const cause = "The 'general' field in the syscap.json file must exist, " +
                        "and its value must be the same as " +
                        "the value of 'devicesType' in the module.json5 or config.json file.";
                    const solution = "Please check whether the syscap.json, module.json5, " +
                        "or config.json files are correctly configured.";
                    this._log._buildError(cause)
                        ._solution(solution)
                        ._file(sysCapJsonPath)
                        ._printErrorAndExit();
                }
                //  按照 deviceType 从 SDK 取出对应的 syscap 集合
                sysCapGeneral.forEach((deviceInSysCap) => {
                    if (fs.existsSync(jsDir) && !fs.existsSync(etsDir)) {
                        this.getRequireSysCapList(jsRequireSysCapPath, deviceInSysCap, requireSysCapList);
                    }
                    else {
                        this.getRequireSysCapList(etsRequireSysCapPath, deviceInSysCap, requireSysCapList);
                    }
                });
                //  通过 SDK 获得的 SysCap 与N设备 custom 配置的 SysCap取交集
                if (sysCapCustom !== undefined) {
                    const newNDeviceSysCapList = this.intersectNDeviceSysCap(sysCapCustom, nDeviceSysCapList, regExp, sysCapJsonPath);
                    intersectionSysCapList = newNDeviceSysCapList.filter(v => requireSysCapList.includes(v));
                }
            }
            //  根据production配置做增删
            const production = sysCapJson['production'];
            if (production !== undefined) {
                if (production['addedSysCaps'] !== undefined && production['addedSysCaps'].length !== 0) {
                    production['addedSysCaps'].forEach(((addedSysCap) => {
                        this.fieldRegExpCheck(addedSysCap, "addedSysCaps", regExp, sysCapJsonPath);
                        if (!intersectionSysCapList.includes(addedSysCap)) {
                            intersectionSysCapList.push(addedSysCap);
                        }
                    }));
                }
                if (production['removedSysCaps'] !== undefined && production['removedSysCaps'].length !== 0) {
                    production['removedSysCaps'].forEach((removedSysCap) => {
                        this.fieldRegExpCheck(removedSysCap, "removedSysCaps", regExp, sysCapJsonPath);
                        if (intersectionSysCapList.includes(removedSysCap)) {
                            intersectionSysCapList.splice(intersectionSysCapList.indexOf(removedSysCap), 1);
                        }
                    });
                }
            }
            if (intersectionSysCapList.length === 0) {
                return;
            }
            const newSysCapMap = new Map();
            const apiVersion = this.service.getModuleModel()?.getCompileApiVersion();
            newSysCapMap.set("api_version", apiVersion);
            newSysCapMap.set("syscap", intersectionSysCapList);
            // 获取产物路径 [模块路径]/build/[产品名称]/intermediates/syscap/[目标名称] 
            const sysCapIntermediatePath = pathInfo.getIntermediatesSysCap();
            file_util_js.FileUtil.checkDirWithoutDelete(sysCapIntermediatePath);
            // rpcid.json 配置文件路径
            const rpcidJsonPath = path.default.resolve(sysCapIntermediatePath, common_const_js.CommonConst.RPCID_JSON);
            // 生成 rpcid.json 文件
            fse.outputJsonSync(rpcidJsonPath, Object.fromEntries(newSysCapMap));
            //  syscap转换:rpcid.json -----> rpcid.sc
            const sysCapTool = this.service.getSdkInfo().getSysCapTool();
            // 执行 syscap 指令
            //[toolchains工具路径]/syscap_tool -R -e -i [模块路径]/build/[产品名称]/intermediates/syscap/[目标名称]/rpcid.json -o [模块路径]/build/[产品名称]/intermediates/syscap/[目标名称] 
            new process_utils_js.ProcessUtils(this.moduleName, this.taskName).executeSync([sysCapTool, "-R", "-e", "-i", rpcidJsonPath, "-o", sysCapIntermediatePath]);
        }
        else if (deviceTypes.length === 0) {
            const cause = "The 'deviceTypes' field in the module.json5 or config.json file " +
                "may be empty or does not exist.";
            const solution = "If the 'deviceTypes' field in the module.json5 or config.json file is empty " +
                "or does not exist, import and correctly configure the syscap.json file.";
            this._log._buildError(cause)
                ._solution(solution)
                ._file(jsonFile)
                ._printErrorAndExit();
        }
    }
    ···
}

LegacyMakePackInfo(FA)

根据 config.json 配置文件生成 pack.info 文件
产物:[模块路径]/build/[产品名称]/outputs/[目标名称]/pack.info

// hvigor-ohos-plugin/src/tasks/legacy-tasks/legacy-make-pack-info.js
// FA 模型模块级别的 pack.info
class LegacyMakePackInfo extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "MakePackInfo");
        this._log = ohos_logger_js.OhosLogger.getLogger(LegacyMakePackInfo.name);
    }
    doTaskAction(targetData, target) {
        const moduleModel = this.service.getModuleModel();
        // 获取 Module 的 config.json 配置文件
        const configObj = moduleModel.getJsonObjByTargetName(target);
        // 从 config.json 中获取配置信息
        const appObj = {
            bundleName: configObj.app.bundleName,
            version: configObj.app.version
        };
        const moduleObj = {
            mainAbility: configObj.module.mainAbility,
            deviceType: configObj.module.deviceType,
            abilities: LegacyMakePackInfo.processAbilities(configObj.module.abilities),
            distro: configObj.module.distro,
            apiVersion: configObj.app.apiVersion
        };
        // 获取打包生成的 hap 包名称 [模块名称]-[目标名称]-unsigned.hap
        const fullHapName = targetData.getModuleTargetOutputFileName();
        const noSuffixHapName = fullHapName.substring(0, fullHapName.lastIndexOf(".hap"));
        const packageObj = {
            deviceType: configObj.module.deviceType,
            moduleType: configObj.module.distro.moduleType,
            deliveryWithInstall: configObj.module.distro.deliveryWithInstall,
            name: noSuffixHapName
        };
        const packInfo = {
            summary: {
                app: appObj,
                modules: [moduleObj]
            },
            // 因为是hap级别的pack.info,所以数组只有一个对象
            packages: [packageObj] 
        };
        this._log.debug("Module Pack Info: ", packInfo);
        // 生成 [模块路径]/build/[产品名称]/outputs/[目标名称]/pack.info 
        fse.outputJSONSync(path.default.resolve(targetData.getPathInfo().getModuleBuildOutputPath(), build_directory_const_js.BuildArtifactConst.PACK_INFO), packInfo);
    }
    ···
}

LegacyPackageHap(FA)和 PackageHap(Stage)

把生成的所有文件进行整合打包成 Hap 包
产物:
FA模型
[模块路径]/build/[产品名称]/outputs/[目标名称]/[模块名称]-[目标名称]-unsigned.hap
Stage模型
[模块路径]/build/[产品名称]/outputs/[目标名称]/[模块名称]-[目标名称]-unsigned.hap

// hvigor-ohos-plugin/src/tasks/legacy-tasks/legacy-package-hap.js
// FA 模型的打包Hap包任务
class LegacyPackageHap extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "PackageHap");
        this._log = ohos_logger_js.OhosLogger.getLogger(LegacyPackageHap.name);
    }
    doTaskAction(targetData, target) {
        const pathInfo = targetData.getPathInfo();
        // 创建打包工具配置实例
        const packageOptions = new packing_tool_options_js.PackingToolOptions();
        // 获取 SDK 打包工具路径
        const packageToolPath = this.service.getSdkInfo().getPackageTool();
        // 配置打包工具路径
        packageOptions.addCalledJarFile(packageToolPath);
        // 配置打包模式为 hap
        packageOptions.addMode("hap")
            .force(true)
            // 配置需要打包的文件和文件夹路径
            .addLibPath(path.default.resolve(pathInfo.getIntermediatesProcessLibs()))
            .addJsonPath(path.default.resolve(pathInfo.getIntermediatesRes(), common_const_js.CommonConst.CONFIG_JSON))
            .addResourcesPath(path.default.resolve(pathInfo.getIntermediatesRes(), build_directory_const_js.BuildDirConst.RESTOOL_BUILD_RESOURCES))
            .addAssetsPath(path.default.resolve(pathInfo.getIntermediatesAssetsPath()))
            .addIndexPath(path.default.resolve(pathInfo.getIntermediatesRes(), build_directory_const_js.BuildArtifactConst.RESOURCE_INDEX))
            .addPackInfoPath(path.default.resolve(pathInfo.getModuleBuildOutputPath(), build_directory_const_js.BuildArtifactConst.PACK_INFO))
            .addOutPath(path.default.resolve(pathInfo.getModuleBuildOutputPath(), targetData.getModuleTargetOutputFileName()));
        const rpcidSc = path.default.resolve(pathInfo.getIntermediatesSysCap(), common_const_js.CommonConst.RPCID_SC);
        if (fse.existsSync(rpcidSc)) {
            packageOptions.addSysCapPath(rpcidSc);
        }
        this._log._printDebugCommand("PackageHap", packageOptions.commandList);
        // 执行打包指令
        // java -jar [toolchains工具路径]/lib/app_packing_tool.jar 
        // --mode hap 
        // --force true 
        // --lib-path [模块路径]/build/[产品名称]/intermediates/libs/[目标名称] 
        // --json-path [模块路径]/build/[产品名称]/intermediates/res/[目标名称]/config.json 
        // --resources-path [模块路径]/build/[产品名称]/intermediates/res/[目标名称]/resources 
        // --assets-path [模块路径]/build/[产品名称]/intermediates/assets/[目标名称] 
        // --index-path [模块路径]/build/[产品名称]/intermediates/res/[目标名称]/resources.index 
        // --pack-info-path [模块路径]/build/[产品名称]/outputs/[目标名称]/pack.info 
        // --rpcid-path [模块路径]/build/[产品名称]/intermediates/syscap/[目标名称]/rpcid.sc
        // --out-path [模块路径]/build/[产品名称]/outputs/[目标名称]/[模块名称]-[目标名称]-unsigned.hap 
        new process_utils_js.ProcessUtils(this.moduleName, this.taskName).executeSync(packageOptions.commandList);
    }
}
// hvigor-ohos-plugin/src/tasks/package-hap.js
// Stage 模型的打包Hap包任务
class PackageHap extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "PackageHap");
        this._log = ohos_logger_js.OhosLogger.getLogger(PackageHap.name);
    }
    doTaskAction(targetData, target) {
        const pathInfo = targetData.getPathInfo();
        // 创建打包工具配置实例
        const packageOptions = new packing_tool_options_js.PackingToolOptions();
        // 获取 SDK 打包工具路径
        const packageToolPath = this.service.getSdkInfo().getPackageTool();
        // 配置打包工具路径
        packageOptions.addCalledJarFile(packageToolPath);
        // 配置打包模式为 hap
        packageOptions.addMode("hap")
            .force(true)
             // 配置需要打包的文件和文件夹路径
            .addLibPath(path.default.resolve(pathInfo.getIntermediatesProcessLibs()))
            .addJsonPath(path.default.resolve(pathInfo.getIntermediatesRes(), common_const_js.CommonConst.MODULE_JSON))
            .addResourcesPath(path.default.resolve(pathInfo.getIntermediatesRes(), build_directory_const_js.BuildDirConst.RESTOOL_BUILD_RESOURCES))
            .addIndexPath(path.default.resolve(pathInfo.getIntermediatesRes(), build_directory_const_js.BuildArtifactConst.RESOURCE_INDEX))
            .addOutPath(path.default.resolve(pathInfo.getModuleBuildOutputPath(), targetData.getModuleTargetOutputFileName()));
        const rpcidSc = path.default.resolve(pathInfo.getIntermediatesSysCap(), common_const_js.CommonConst.RPCID_SC);
        if (fse.existsSync(rpcidSc)) {
            packageOptions.addSysCapPath(rpcidSc);
        }
        const jsAssetsPath = path.default.resolve(pathInfo.getIntermediatesAssetsPath(), "js");
        if (fse.existsSync(jsAssetsPath)) {
            packageOptions.addJsPath(jsAssetsPath);
        }
        const etsAssetsPath = path.default.resolve(pathInfo.getIntermediatesAssetsPath(), "ets");
        if (fse.existsSync(etsAssetsPath)) {
            packageOptions.addEtsPath(etsAssetsPath);
        }
        this._log._printDebugCommand("PackageHap", packageOptions.commandList);
        // 执行打包指令
        // java -jar [toolchains工具路径]/lib/app_packing_tool.jar 
        // --mode hap 
        // --force true 
        // --lib-path [模块路径]/build/[产品名称]/intermediates/libs/[目标名称] 
        // --json-path [模块路径]/build/[产品名称]/intermediates/res/[目标名称]/config.json 
        // --resources-path [模块路径]/build/[产品名称]/intermediates/res/[目标名称]/resources 
        // --index-path [模块路径]/build/[产品名称]/intermediates/res/[目标名称]/resources.index
        // --ets-path [模块路径]/build/[产品名称]/intermediates/assets/[目标名称]/ets
        // --rpcid-path [模块路径]/build/[产品名称]/intermediates/syscap/[目标名称]/rpcid.sc
        // --out-path [模块路径]/build/[产品名称]/outputs/[目标名称]/[模块名称]-[目标名称]-unsigned.hap 
        new process_utils_js.ProcessUtils(this.moduleName, this.taskName).executeSync(packageOptions.commandList);
    }
}

SignHap

给打包好的 Hap 包签名
产物:
FA模型
[模块路径]/build/[产品名称]/outputs/[目标名称]/[模块名称]-[目标名称]-signed.hap
Stage模型
[模块路径]/build/[产品名称]/outputs/[目标名称]/[模块名称]-[目标名称]-signed.hap

// hvigor-ohos-plugin/src/tasks/sign-hap.js
// 签名 Hap 包
class SignHap extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "SignHap");
    }
    doTaskAction(targetData, target) {
        ···
        new sign_util_js.SignUtil(this.service, "hap", targetData.getProduct()).sign(inputFile, outputFile);
    }
}

执行签名的工具类

// hvigor-ohos-plugin/src/tasks/sign/sign-util.js
class SignUtil {
    ···
    sign(inputFilePath, outputFilePath) {
        this.executeSign(new sign_model.SignModel(this._moduleType, inputFilePath, outputFilePath));
    }
    executeSign(signModel) {
        // 获取项目级 build-profile.json5 中 app 配置信息
        const app = this._taskService.getProjectModel().getProfileOpt().app;
        // 获取 targetProduct(从app.products中匹配).signingConfig 的配置信息
        const productSignConfigName = this._targetProduct.signingConfig;
        // 截取 signingConfig 最后一个 . 后面的字符串,然后匹配 app.signingConfigs 列表中的 name 字段
        const signingConfig = array_util.getElementFromArr(app?.signingConfigs,productSignConfigName?.substring(productSignConfigName.lastIndexOf(".") + 1));
        // 如果从 app.signingConfigs 配置中未匹配到签名信息,则提示跳过签名
        if (signingConfig === undefined) {
            this._log.warn(`Will skip sign '${this._moduleType}',
            because no valid signingConfig is configured for '${this._targetProduct.name}' product`);
            return;
        }
        // 获取 SDK Info 实例
        const sdkInfo = this._taskService.getSdkInfo();
        // 创建指令构建者实例
        const commandBuilder = this._signCommandFactory.createCommandBuilder(this._taskService.getProjectModel(), signingConfig, sdkInfo, signModel);
        // 根据签名信息创建签名执行指令
        // java -jar [toolchains工具路径]/lib/hap-sign-tool.jar sign-app 
        // -mode localSign 
        // -keystoreFile [P12签名文件] 
        // -keystorePwd [keystorePwd] 
        // -keyAlias [keyAlias] 
        // -keyPwd [keyPwd] 
        // -signAlg [signAlg] 
        // -profileFile [P7b签名文件] 
        // -appCertFile [CER签名文件] 
        // -inFile [未签名Hap包路径] 
        // -outFile [签名Hap包路径]
        const signCommand = commandBuilder.getSignCommand();
        if (this._moduleType === "hap") {
            // 从 P7b 生成配置验证 JSON文件,从 ['content']['bundle-info']['bundle-name'] 中获取包名
            // java -jar [toolchains工具路径]/lib/hap-sign-tool.jar 
            // verify-profile 
            // -inFile [P7b文件路径] 
            // -outFile [项目路径]/TempDirForSignConfigCheck[随机生成字符串]/signConfigCheckJson.json 
            // 获取完 bundleName 后会删除临时文件 signConfigCheckJson.json
            const bundleNameFromP7b = validate_util.ValidateUtil.getBundleNameFromP7b(this._taskService, signingConfig);
            // 从配置文件中获取包名,FA 从 config.json 获取,Stage 从 app.json5 中获取。
            const bundleNameFromHap = validate_util.ValidateUtil.getBundleNameFromHap(this._taskService);
            // 比对包名是否一致,如果不一致则提示错误
            if (bundleNameFromHap !== bundleNameFromP7b) {
                this._log._buildError('The bundle name verification result does not match.')
                    ._solution('Please check the current hap bundleName or the signature ' +
                    'configuration of the signingConfigs field in build-profile.json5 file is correct.')
                    ._file(this._taskService.getProjectModel().getProfilePath())
                    ._printErrorAndExit();
            }
        }
        // 分 Project 和 Module 执行签名指令
        if (this._taskService instanceof module_task_service.ModuleTaskService) {
            new process_utils.ProcessUtils(this._taskService.getModuleModel().getName(), `Sign${this._moduleType}`)
                .executeSync(signCommand);
        }
        else {
            new process_utils.ProcessUtils(this._taskService.getProjectModel().getName(), `Sign${this._moduleType}`)
                .executeSync(signCommand);
        }
    }
}

AssembleApp 任务流

App 打包的任务流
最终产物: [项目路径]/build/outputs/[产品名称]/[项目名称]-[产品名称]-[signed/unsigned].app

// hvigor-ohos-plugin/src/tasks/assemble/assemble-app.js
class AssembleApp extends hvigor_base.Task {
    constructor(taskService, isFaMode) {
        super();
        this.registry = () => {
            const hvigor = new hvigor_base.Hvigor();
            return hvigor.series(
                // 调用hap打包任务
                new package_sub_hap_js.PackageSubHaps(this._taskService).registry(), 
                // 生成 app 级别 pack.info 文件
                new legacy_make_project_pack_info_js.LegacyMakeProjectPackInfo(this._taskService, this._isFaMode).registry(), 
                // 打包工具生成 app 包
                new package_app_js.PackageApp(this._taskService).registry(), 
                // 对app包进行签名
                new sign_app_js.SignApp(this._taskService).registry());
        };
        this._taskService = taskService;
        this._isFaMode = isFaMode;
    }
}

PackageSubHaps

调用hap打包任务
产物:
FA模型
[模块路径]/build/[产品名称]/outputs/[目标名称]/[模块名称]-[目标名称]-unsigned.hap
Stage模型
[模块路径]/build/[产品名称]/outputs/[目标名称]/[模块名称]-[目标名称]-unsigned.hap

// hvigor-ohos-plugin/src/tasks/package-sub-hap.js
class PackageSubHaps extends ohos_app_task_js.OhosAppTask {
    constructor(taskService) {
        super(taskService, "PackageSubHaps");
        this._log = ohos_logger_js.OhosLogger.getLogger(PackageSubHaps.name);
    }
    doTaskAction() {
        // 获取产品名称
        const targetProductName = this.service.getTargetProduct().name;
        // node js 路径
        const nodeJsPath = node_util_js.findValidNodeExePath(this.service.getSdkInfo().getNodeJsDir());
        const commands = this.initExecuteCommand(targetProductName, nodeJsPath);
        this._log.debug("PackageSubHap", commands.join(' '));
        // 执行 Hap 打包指令
        // node [项目路径]/node_modules/@ohos/hvigor/bin/hvigor.js -m module -p product=default -p debuggable=false assembleHap -d
        new process_utils_js.ProcessUtils().executeSync(commands, { stdout: process.stdout, stderr: process.stderr });
        this._log.debug('All hap package finished ======================================================');
    }
    initExecuteCommand(product, nodeJsPath) {
        const command = [nodeJsPath, require.resolve("@ohos/hvigor/bin/hvigor"), "-m", "module", "-p"];
        command.push(`product=${product}`);
        command.push("-p");
        command.push(`${common_const_js.CommonConst.DEBUGGABLE}=false`);
        command.push("assembleHap");
        command.push(this._log._getCliLevel());
        return command;
    }
}

LegacyMakeProjectPackInfo

生成 app 级别 pack.info 文件
产物:[项目路径]/build/outputs/[产品名称]/pack.info

// hvigor-ohos-plugin/src/tasks/legacy-tasks/legacy-make-project-pack-info.js
class LegacyMakeProjectPackInfo extends ohos_app_task_js.OhosAppTask {
    constructor(taskService, isFaMode) {
        super(taskService, "MakeProjectPackInfo");
        this._log = ohos_logger_js.OhosLogger.getLogger(LegacyMakeProjectPackInfo.name);
        this._projectPackInfoObj = {
            summary: {
                app: {
                    bundleName: "bundleName",
                    version: {
                        name: "name",
                        code: 0
                    }
                },
                modules: []
            },
            packages: []
        };
        this._isFaMode = isFaMode;
    }
    doTaskAction() {
        // 如果不是 FA 模型则生成空文件,路径 [项目路径]/build/outputs/[产品名称]/pack.info
        if (!this._isFaMode) {
            fs.outputJSONSync(path.default.resolve(this.service.getPathInfo().getProjectOutputPath(), build_directory_const_js.BuildArtifactConst.PACK_INFO), {});
            return;
        }
        this.service.getProductDataMap().forEach((value) => {
            for (const moduleTargetData of value) {
                // 获取 Module 的 PACK_INFO 路径 [模块路径]/build/[产品名称]/outputs/[目标名称]/pack.info
                const hapPackInfo = path.default.resolve(moduleTargetData.getPathInfo().getModuleBuildOutputPath(), build_directory_const_js.BuildArtifactConst.PACK_INFO);
                if (!fs.existsSync(hapPackInfo)) {
                    continue;
                }
                const hapPackInfoObj = project_file_reader_js.ProjectFileReader.getJson5Obj(hapPackInfo);
                this._projectPackInfoObj.summary.app = hapPackInfoObj.summary.app; // 此处直接赋值 因为同一个app中该属性都是相同的.
                this._projectPackInfoObj.summary.modules.push(hapPackInfoObj.summary.modules[0]);
                this._projectPackInfoObj.packages.push(hapPackInfoObj.packages[0]);
            }
        });
        this._log.debug("Project Pack Info:", this._projectPackInfoObj);
        // 输出 App 级别 pack.info [项目路径]/build/outputs/[产品名称]/pack.info
        fs.outputJSONSync(path.default.resolve(this.service.getPathInfo().getProjectOutputPath(),
        build_directory_const_js.BuildArtifactConst.PACK_INFO), this._projectPackInfoObj);
    }
}

PackageApp

打包工具生成 app 包
产物:[项目路径]/build/outputs/[产品名称]/[项目名称]-[产品名称]-unsigned.app

// hvigor-ohos-plugin/src/tasks/package-app.js
class PackageApp extends ohos_app_task_js.OhosAppTask {
    constructor(taskService) {
        super(taskService, "PackageApp");
        this._log = ohos_logger_js.OhosLogger.getLogger(PackageApp.name);
        this.executePackageApp = () => {
            // 创建 PackingTool 配置
            const packageOptions = new packing_tool_options_js.PackingToolOptions();
            const sdkInfo = this.service.getSdkInfo();
            const pathInfo = this.service.getPathInfo();
            packageOptions.addCalledJarFile(sdkInfo.getPackageTool());
            const allHapPath = [];
            this.service.getProductDataMap().forEach((value) => {
                for (const moduleTargetData of value) {
                    // 获取打包生成的 Hap 包名
                    const outputHapFileName = moduleTargetData.getModuleTargetOutputFileName();
                    // 获取打包生成的 Hap 包路径 [模块路径]/build/[产品路径]/outputs/[目标路径]/[目标名称]/[模块名称]-[目标名称]-unsigned.hap 
                    const hapPath = path.default.resolve(moduleTargetData.getPathInfo().getModuleBuildOutputPath(), outputHapFileName);
                    // 获取打包生成的 App 包路径 [模块路径]/build/[产品路径]/outputs/[目标路径]/app
                    const destDir = path.default.resolve(moduleTargetData.getPathInfo().getModuleBuildOutputPath(), "app");
                    file_util_js.FileUtil.checkDirWithoutDelete(destDir);
                    // 获取最终 Hap 包路径 [模块路径]/build/[产品路径]/outputs/[目标路径]/app/[模块名称]-[目标名称].hap 
                    const destFile = path.default.resolve(destDir, outputHapFileName.replace("-unsigned", ""));
                    file_util_js.FileUtil.checkFile(destFile);
                    // 把未签名的 hap 包放到最终路径
                    fs.default.writeFileSync(destFile, fs.default.readFileSync(hapPath));
                    // 把 hap 包地址放入 List 中
                    allHapPath.push(destFile);
                }
            });
            // 获取App输出目录 pack.info 文件路径
            const packInfoPath = path.default.resolve(pathInfo.getProjectOutputPath(), build_directory_const_js.BuildArtifactConst.PACK_INFO);
            const packInfoObj = project_file_reader_js.ProjectFileReader.getJson5Obj(packInfoPath);
            const packages = packInfoObj.packages;
            for (let i = 0; i < (packages === null || packages === void 0 ? void 0 : packages.length); i++) {
                // 修改 package.name 
                packages[i].name = packages[i].name.replace("-unsigned", "");
            }
            file_util_js.FileUtil.checkDirWithoutDelete(packInfoPath);
            fs.default.writeFileSync(packInfoPath, JSON.stringify(packInfoObj));
            packageOptions.addMode("app")
                .addPackInfoPath(packInfoPath)
                .addHapPath(allHapPath.join(","))
                .force(true);
            const appOutputFileName = this.service.getAppOutputFileName();
            // 设置产物路径 [项目路径]/build/outputs/[产品名称]/[项目名称]-[产品名称]-unsigned.app
            packageOptions.addOutPath(path.default.resolve(pathInfo.getProjectOutputPath(), appOutputFileName));
            this._log._printDebugCommand("PackageApp", packageOptions.commandList);
            return packageOptions.commandList;
        };
    }
    doTaskAction() {
        // 执行打 App 包指令
        // java -jar [toolchains工具路径]/lib/app_packing_tool.jar 
        // --mode app 
        // --force true 
        // --pack-info-path [项目路径]/build/outputs/[产品名称]/pack.info
        // --hap-path [模块路径]/build/[产品名称]/outputs/[目标名称]/app/[模块名称]-[目标名称].hap
        // --out-path [项目路径]/build/outputs/[产品名称]/[项目名称]-[产品名称]-unsigned.app
        new process_utils_js.ProcessUtils().executeSync(this.executePackageApp());
    }
}

SignApp

对app包进行签名
产物:[项目路径]/build/outputs/[产品名称]/[项目名称]-[产品名称]-signed.app

// hvigor-ohos-plugin/src/tasks/sign-app.js
class SignApp extends ohos_app_task_js.OhosAppTask {
    constructor(taskService) {
        super(taskService, "SignApp");
    }
    doTaskAction() {
        const pathInfo = this.service.getPathInfo();
        const outputFileName = this.service.getAppOutputFileName();
        // 入参和出参的包名规则需要变更
        const inputFile = path.default.resolve(pathInfo.getProjectOutputPath(), outputFileName);
        const outputFile = path.default.resolve(pathInfo.getProjectOutputPath(), this.service.getAppOutputFileName(true));
        // 参考 hap 包打包
        new sign_util_js.SignUtil(this.service, "app", this.service.getTargetProduct()).sign(inputFile, outputFile);
    }
}

AssembleHar 任务流

Har 打包的任务流
最终产物:[模块路径]/build/[产品名称]/outputs/[目标名称]/[har包名]-[版本].tgz

// hvigor-ohos-plugin/src/tasks/assemble/assemble-har.js
class AssembleHar extends hvigor_base.Task {
    constructor(taskService, isFaMode) {
        super();
        this.registry = () => {
            const hvigor = new hvigor_base.Hvigor();
            // FA 模型
            if (this._isFaMode) {
                return hvigor.series(
                    // 使用 Schema 校验配置文件
                    new pre_build_js.PreBuild(this._taskService).registry(), 
                    // 收集 package.json 中配置的 npm har 包依赖,并进行 har 构建
                    new collect_har_dependency_js.CollectHarDependency(this._taskService).registry(), 
                    // 以模块配置文件为主混合依赖的 har 配置文件和项目配置文件
                    new legacy_merge_profile_js.LegacyMergeProfile(this._taskService).registry(), 
                    // 处理配置文件
                    new legacy_process_profile_js.LegacyProcessProfile(this._taskService).registry(), 
                    // 编译资源文件
                    new legacy_compile_resource_js.LegacyCompileResource(this._taskService).registry(), 
                    // Native 代码编译任务
                    new compile_native_js.CompileNative(this._taskService).registry(), 
                    // 编译 .so 文件
                    new build_native_js.BuildNative(this._taskService).registry(), 
                    // 收集 har 依赖中的.so文件
                    new process_libs_js.ProcessLibs(this._taskService).registry(), 
                    // 打包Har包
                    new package_har_js.PackageHar(this._taskService).registry());
            }
            // Stage 模型
            return hvigor.series(
                // 使用 Schema 校验配置文件
                new pre_build_js.PreBuild(this._taskService).registry(), 
                // 收集 package.json 中配置的 npm har 包依赖,并进行 har 构建
                new collect_har_dependency_js.CollectHarDependency(this._taskService).registry(), 
                // 以模块配置文件为主混合依赖的 har 配置文件和项目配置文件
                new merge_profile_js.MergeProfile(this._taskService).registry(),
                // 处理配置文件 
                new process_profile_js.ProcessProfile(this._taskService).registry(), 
                // 合并资源到index文件中
                new merge_resource_js.MergeResource(this._taskService).registry(),
                // 编译资源文件
                new compile_resource_js.CompileResource(this._taskService).registry(), 
                // Native 代码编译任务
                new compile_native_js.CompileNative(this._taskService).registry(), 
                // 编译 .so 文件
                new build_native_js.BuildNative(this._taskService).registry(), 
                // 收集 har 依赖中的.so文件
                new process_libs_js.ProcessLibs(this._taskService).registry(),
                // 打包Har包 
                new package_har_js.PackageHar(this._taskService).registry());
        };
        this._taskService = taskService;
        this._isFaMode = isFaMode;
    }
}

PackageHar

打包Har包
产物:[模块路径]/build/[产品名称]/outputs/[目标名称]/[har包名]-[版本].tgz

// hvigor-ohos-plugin/src/tasks/package-har.js
class PackageHar extends ohos_hap_task_js.OhosHapTask {
    constructor(taskService) {
        super(taskService, "PackageHar");
        this._moduleDir = taskService.getModuleModel().getProjectDir();
        const profileOption = taskService.getModuleModel().getProfileOpt();
        this._nativeOption = profileOption.buildOption.externalNativeOptions;
        this._sdkInfo = this.service.getSdkInfo();
    }
    doTaskAction(targetData, target) {
        const pathInfo = targetData.getPathInfo();
        // 获取模块路径
        const moduleDir = this.service.getModuleModel().getProjectDir();
        // 获取模块 libs 路径 [模块路径]/build/[产品名称]/intermediates/libs/[目标名称] 
        const processedLibs = pathInfo.getIntermediatesProcessLibs();
        // 获取模块 res 路径 [模块路径]/build/[产品名称]/intermediates/res/[目标名称] 
        const resourceDir = pathInfo.getIntermediatesRes();
        fs.emptyDirSync(pathInfo.getModuleBuildOutputPath());
        fs.emptyDirSync(this.getTaskTempDir(targetData));
        if (fs.pathExistsSync(processedLibs)) {
            // 将 [模块路径]/build/[产品名称]/intermediates/libs/[目标名称] 中文件
            // 复制到 [模块路径]/build/[产品名称]/cache/[目标名称]/PackageHar/libs
            fs.copySync(pathInfo.getIntermediatesProcessLibs(), path.default.resolve(this.getTaskTempDir(targetData), build_directory_const_js.BuildDirConst.LIBS));
        }
        // ResourceTable.txt
        if (fs.pathExistsSync(resourceDir)) {
             // 将 [模块路径]/build/[产品名称]/intermediates/res/[目标名称]/ResourceTable.txt 文件
             // 复制到 [模块路径]/build/[产品名称]/cache/[目标名称]/PackageHar/ResourceTable.txt
            fs.copySync(path.default.resolve(resourceDir, build_directory_const_js.BuildArtifactConst.RESOURCE_TABLE_TXT), path.default.resolve(this.getTaskTempDir(targetData), build_directory_const_js.BuildArtifactConst.RESOURCE_TABLE_TXT));
        }
        // 打包过滤目录 ["libs","build","node_modules",".cxx",".preview"]
        let filter = [build_directory_const_js.BuildDirConst.LIBS, build_directory_const_js.BuildDirConst.BUILD_ROOT, common_const_js.CommonNodeConst.NODE_MODULES, ".cxx", ".preview"];
        if (!filter.includes(pathInfo.getBuildRoot())) {
            filter.push(pathInfo.getBuildRoot());
        }
        filter = filter.map(baseName => {
            return path.default.resolve(moduleDir, baseName);
        });
        fs.readdirSync(moduleDir).forEach(srcPath => {
            const src = path.default.resolve(moduleDir, srcPath);
            if (filter.includes(src)) {
                return;
            }
            // 将module下的其他目录经过过滤复制到 [模块路径]/build/[产品名称]/cache/[目标名称]/PackageHar/
            fs.copySync(path.default.resolve(moduleDir, srcPath), path.default.resolve(this.getTaskTempDir(targetData), srcPath), {
                filter: (src, dest) => {
                    return !(this._nativeOption && src === this.getCmakeListDir());
                }
            });
        });
        // 拷贝 cpp/types
        if (this._nativeOption) {
            const cppTypes = path.default.resolve(this.getCmakeListDir(), "types");
            fs.copySync(cppTypes, path.default.resolve(this.getTaskTempDir(targetData), "src", "main", "cpp", "types"));
        }
        // 将合并后的 module.json5/config.json 复制到对应位置
        const harProfile = pathInfo.getIntermediatesMergeProfileDir();
        fs.copySync(harProfile, path.default.resolve(this.getTaskTempDir(targetData), "src", "main"));
        const harModuleJson = path.default.resolve(this.getTaskTempDir(targetData), "src", "main", common_const_js.CommonConst.MODULE_JSON5);
        if (fs.pathExistsSync(harModuleJson)) {
            fs.removeSync(harModuleJson);
        }
        const npmPath = path.default.resolve(node_util_js.findValidNodeExePath(this.service.getSdkInfo().getNodeJsDir()), "..");
        // 获取 npm 构造器
        const npmBuilder = new npm_command_builder_js.NpmCommandBuilder(npmPath);
        npmBuilder.addAllParams(["pack"]);
        // 执行打包命令
        // npm pack 
        // cwd [模块路径]/build/[产品名称]/cache/[目标名称]/PackageHar/
        new process_utils_js.ProcessUtils(this.moduleName, this.taskName).executeSync(npmBuilder.build(), {
            cwd: this.getTaskTempDir(targetData)
        }, true);
        // 把生成的 .tgz 文件 复制到 [模块路径]/build/[产品名称]/outputs/[目标名称]/[har包名]-[版本].tgz
        fs.copySync(this.getTaskTempDir(targetData), pathInfo.getModuleBuildOutputPath(), {
            filter: (src, dest) => {
                return (!fs.lstatSync(src).isDirectory() && src.endsWith(".tgz"))
                    || src === this.getTaskTempDir(targetData);
            }
        });
    }
    getCmakeListDir() {
        return path.default.resolve(this._moduleDir, this._nativeOption.path, '..');
    }
}

AssembleSubHar 任务流

作为 Hap 的子模块打 Har 包的任务流

// hvigor-ohos-plugin/src/tasks/assemble/assemble-sub-har.js
class AssembleSubHar extends hvigor_base.Task {
    constructor(taskService, isFaMode) {
        super();
        this.registry = () => {
            const hvigor = new hvigor_base.Hvigor();
            // FA 模型
            if (this._isFaMode) {
                return hvigor.series(
                    // 使用 Schema 校验配置文件 
                    new pre_build_js.PreBuild(this._taskService).registry(), 
                    // 收集 package.json 中配置的 npm har 包依赖,并进行 har 构建
                    new collect_har_dependency_js.CollectHarDependency(this._taskService).registry(), 
                    // 以模块配置文件为主混合依赖的 har 配置文件和项目配置文件
                    new legacy_merge_profile_js.LegacyMergeProfile(this._taskService).registry(), 
                    // 处理配置文件 
                    new legacy_process_profile_js.LegacyProcessProfile(this._taskService).registry(), 
                    // 编译资源文件
                    new legacy_compile_resource_js.LegacyCompileResource(this._taskService).registry(), 
                    // Native 代码编译任务
                    new compile_native_js.CompileNative(this._taskService).registry(), 
                    // 编译 .so 文件
                    new build_native_js.BuildNative(this._taskService).registry(), 
                    // 收集 har 依赖中的.so文件
                    new process_libs_js.ProcessLibs(this._taskService).registry());
            } 
            // Stage 模型
            return hvigor.series(
                // 使用 Schema 校验配置文件
                new pre_build_js.PreBuild(this._taskService).registry(),
                // 收集 package.json 中配置的 npm har 包依赖,并进行 har 构建
                new collect_har_dependency_js.CollectHarDependency(this._taskService).registry(), 
                // 以模块配置文件为主混合依赖的 har 配置文件和项目配置文件
                new merge_profile_js.MergeProfile(this._taskService).registry(), 
                // 处理配置文件 
                new process_profile_js.ProcessProfile(this._taskService).registry(),
                // 合并资源到index文件中 
                new merge_resource_js.MergeResource(this._taskService).registry(), 
                // 编译资源文件
                new compile_resource_js.CompileResource(this._taskService).registry(), 
                // Native 代码编译任务
                new compile_native_js.CompileNative(this._taskService).registry(), 
                // 编译 .so 文件
                new build_native_js.BuildNative(this._taskService).registry(), 
                // 收集 har 依赖中的.so文件
                new process_libs_js.ProcessLibs(this._taskService).registry());
        };
        this._taskService = taskService;
        this._isFaMode = isFaMode;
    }
}

BuildPreviewerRes 任务流

构建hap模块预览编译文件

// hvigor-ohos-plugin/src/tasks/previewer/build-previewer-res.js
class BuildPreviewerRes extends hvigor_base.Task {
    constructor(taskService, isFaMode) {
        super();
        this.registry = () => {
            return this._isFaMode ?
                // FA 模型
                new hvigor_base.Hvigor().series(
                    // 收集 package.json 中配置的 npm har 包依赖,并进行 har 构建
                    new collect_har_dependency_js.CollectHarDependency(this._taskService).registry(),
                    // 使用 Schema 校验配置文件 
                    new pre_build_js.PreBuild(this._taskService).registry(), 
                    // 以模块配置文件为主混合依赖的 har 配置文件和项目配置文件
                    new legacy_merge_profile.LegacyMergeProfile(this._taskService).registry(),
                    // 处理配置文件  
                    new legacy_process_profile.LegacyProcessProfile(this._taskService).registry(), 
                    // 编译资源文件
                    new legacy_compile_resource.LegacyCompileResource(this._taskService).registry(),
                    // 系统能力转换 
                    new syscap_transform.SyscapTransform(this._taskService).registry(), 
                    // 遍历模块 Ability 信息生成 JsManifest.json 文件
                    new legacy_generate_js_manifest.LegacyGenerateJsManifest(this._taskService).registry(), 
                    // 生成loader需要的json文件
                    new generate_loader_json_js.GenerateLoaderJson(this._taskService).registry()) :
                // Stage 模型
                new hvigor_base.Hvigor().series(
                    // 收集 package.json 中配置的 npm har 包依赖,并进行 har 构建
                    new collect_har_dependency_js.CollectHarDependency(this._taskService).registry(), 
                    // 使用 Schema 校验配置文件
                    new pre_build_js.PreBuild(this._taskService).registry(), 
                    // 以模块配置文件为主混合依赖的 har 配置文件和项目配置文件
                    new merge_profile_js.MergeProfile(this._taskService).registry(), 
                    // 处理配置文件 
                    new process_profile_js.ProcessProfile(this._taskService).registry(),
                    // 合并资源到index文件中  
                    new merge_resource_js.MergeResource(this._taskService).registry(),
                    // 编译资源文件 
                    new compile_resource_js.CompileResource(this._taskService).registry(), 
                    // 系统能力转换
                    new syscap_transform.SyscapTransform(this._taskService).registry(), 
                    // 生成loader需要的json文件
                    new generate_loader_json_js.GenerateLoaderJson(this._taskService).registry(), 
                    // 重置页面配置文件
                    new replace_previewer_page.ReplacePreviewerPage(this._taskService).registry());
        };
        this._taskService = taskService;
        this._isFaMode = isFaMode;
    }
}

ReplacePreviewerPage(Stage)

重置页面配置文件
产物:[模块路径]/build/[产品名称]/intermediates/res/[目标名称]/resources/base/profile/[文件名称].json

// hvigor-ohos-plugin/src/tasks/previewer/replace-previewer-page.js
class ReplacePreviewerPage extends ohos_hap_task.OhosHapTask {
    constructor(taskService) {
        super(taskService, 'ReplacePreviewerPage');
        this._log = ohos_logger_js.OhosLogger.getLogger(ReplacePreviewerPage.name);
    }
    doTaskAction(targetData, target) {
        // 获取命令行参数 previewer.replace.page
        const previewPage = hvigor_base.vigorConfigInst.getExtraConfig().get(inject_const.InjectConst.PREVIEWER_REPLACE_PAGE);
        if (!previewPage) {
            return;
        }
        const pathInfo = targetData.getPathInfo();
        // 获取处理后的配置文件路径  [模块路径]/build/[产品名称]/intermediates/res/[目标名称]/module.json
        const moduleJsonPath = path.default.resolve(pathInfo.getIntermediatesRes(), common_const.CommonConst.MODULE_JSON);
        // 获取配置文件数据
        const moduleJsonObj = project_file_reader_js.ProjectFileReader.getJson5Obj(moduleJsonPath);
        // 获取配置参数 module.pages
        const pagesStr = moduleJsonObj.module.pages;
        if (!pagesStr) {
            this._log._buildError("Unabled to replace. Cannot find moduleJsonObj.module.pages.")
                ._printErrorAndExit(this.moduleModel.getName());
            return;
        }
        const pageModel = {
            src: [previewPage]
        };
        const pageJsonFileName = `${pagesStr.replace(/\$profile:/, '')}.json`;
        // 获取页面的配置文件 [模块路径]/build/[产品名称]/intermediates/res/[目标名称]/resources/base/profile/[文件名称].json
        const pageJsonFilePath = path.default.resolve(pathInfo.getIntermediatesResProfilePath(), pageJsonFileName);
        this._log.debug(`Resolved file ${pageJsonFilePath}.`);
        this._log.debug(`Replace page to ${previewPage}`);
        // 输出配置到文件
        fse.outputJSONSync(pageJsonFilePath, pageModel);
    }
}

BuildHarPreviewerRes 任务流

构建har模块预览编译文件

// hvigor-ohos-plugin/src/tasks/previewer/build-har-previewer-res.js
class BuildHarPreviewerRes extends hvigor_base.Task {
    constructor(taskService, isFaMode) {
        super();
        this.registry = () => {
            const hvigor = new hvigor_base.Hvigor();
            if (this._isFaMode) {
                return hvigor.series(
                    // 收集 package.json 中配置的 npm har 包依赖,并进行 har 构建
                    new collect_har_dependency_js.CollectHarDependency(this._taskService).registry(), 
                    // 使用 Schema 校验配置文件
                    new pre_build_js.PreBuild(this._taskService).registry(), 
                    // 以模块配置文件为主混合依赖的 har 配置文件和项目配置文件
                    new legacy_merge_profile.LegacyMergeProfile(this._taskService).registry(), 
                    // 处理配置文件 
                    new legacy_process_profile.LegacyProcessProfile(this._taskService).registry(),
                    // 编译资源文件
                    new legacy_compile_resource.LegacyCompileResource(this._taskService).registry(), 
                    // 生成 JsManifest.json 文件
                    new legacy_generate_har_js_manifest_js.LegacyGenerateHarJsManifest(this._taskService).registry());
            }
            return hvigor.series(
                // 收集 package.json 中配置的 npm har 包依赖,并进行 har 构建
                new collect_har_dependency_js.CollectHarDependency(this._taskService).registry(), 
                // 使用 Schema 校验配置文件
                new pre_build_js.PreBuild(this._taskService).registry(), 
                // 以模块配置文件为主混合依赖的 har 配置文件和项目配置文件
                new merge_profile_js.MergeProfile(this._taskService).registry(),
                // 处理配置文件  
                new process_profile_js.ProcessProfile(this._taskService).registry(), 
                // 合并资源到index文件中 
                new merge_resource_js.MergeResource(this._taskService).registry(), 
                // 编译资源文件
                new compile_resource_js.CompileResource(this._taskService).registry());
        };
        this._taskService = taskService;
        this._isFaMode = isFaMode;
    }
}
...全文
8779 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
闫文敬 2023-12-26
  • 打赏
  • 举报
回复

厉害,麻烦问下这个源码在哪里能看到?

517

社区成员

发帖
与我相关
我的任务
社区描述
OpenHarmony开发者社区
其他 企业社区
社区管理员
  • csdnsqst0025
  • shewaliujingli
  • BaoWei
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧