前言

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;    } }
Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐