421
社区成员




OpenHarmony 应用和服务使用 Hvigor 作为工程的构建工具。 上一篇文章 深入了解hvigor的使用方法
介绍了 Hvigor 的构建流程,通过修改脚本配置使 Hvigor 执行自定义任务。本篇文章将深入了解和解析 Hvigor 的标准任务和任务流。
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;
}
}
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;
}
}
使用 Schema 校验配置文件
// 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);
}
}
···
}
收集 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;
}
}
以模块配置文件为主混合依赖的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" });
}
···
}
处理配置文件
产物:
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" });
}
}
合并资源到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}`);
}
}
编译资源文件
产物:
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);
}
}
遍历模块 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);
}
···
}
生成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);
}
}
编译 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'
}*/
}
}
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);
}
···
}
编译 .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);
});
}
···
}
收集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);
}
});
}
}
系统能力转换
产物:[模块路径]/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();
}
}
···
}
根据 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);
}
···
}
把生成的所有文件进行整合打包成 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);
}
}
给打包好的 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);
}
}
}
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;
}
}
调用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;
}
}
生成 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);
}
}
打包工具生成 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());
}
}
对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);
}
}
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;
}
}
打包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, '..');
}
}
作为 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;
}
}
构建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;
}
}
重置页面配置文件
产物:[模块路径]/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);
}
}
构建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;
}
}