一、简介
hvigor构建工具是一款基于TS实现的构建任务构建工具,鸿蒙使用构建工具hvigor来完成HAP/APP的构建打包。hvigor将工程解析为一个树形结构,项目为树的根节点,hvigor将项目或模块称为一个节点。本文将详细的介绍hvigor生命周期、hvigor任务、hvigor插件。
二、hvigor生命周期
hvigor生命周期分为初始化、配置和执行。
2、1初始化
- 根据命令参数和hvigor-config.json5文件中的配置,设置hvigor的构建参数,并构造出hvigor对象和hvigorConfig对象
- 通过项目根目录下的build-profile.json5文件,创建出根节点的节点描述对象,并通过其中的modules字段,来初始化出工程中所有模块的节点描述对象。
- 执行项目根目录下的hvigorconfig.ts文件,可以在此文件中通过hvigor的相关API来为生命周期注册hook或在构建开始时进行其他处理。
- 根据节点描述对象构造出每个节点的HvigorNode对象实例。
2、2配置
- 执行每个节点(项目或者模块)中的hvigorfile.ts文件,为每个节点添加插件(向hvigor注册任务),执行插件的apply方法,并添加插件上下文。
- 根据前一步加载出的插件和任务,根据任务执行的依赖关系构造出有向无环图。
2、3执行
- 执行选定的任务。
- 任务之间的依赖关系决定了任务执行顺序。
- 任务可以并行执行。
2、4生命周期及hook点
在hvigor的生命周期中有多个hook点可供使用,下图中所有绿色标记的线框为可以使用的hook点。
三、hvigor任务
3、1了解任务
任务是hvigor构建过程中的执行基本单元,任务中通常包含一段编译过程处理的可执行代码;一个任务可以依赖其他多个任务。hvigor任务调度执行时通过解析依赖关系确定任务执行时序。
下图是在打包过程中执行的一些任务,打包其实就是按照有向无环图执行任务。
UP-TO-DATE是任务标识,表示任务未实际执行。hvigor任务增量跳过机制,在二次执行任务时检测任务输入输出条件未发生变化,则任务跳过执行提高构建效率。
default@MakePackInfo、default@ProcessProfile等是任务名称。
3、2注册任务
在打包过程中,除了已经内置的任务,开发者可以自行注册任务。
1、编辑工程下hvigorfile.ts文件。
```
// 导入模块
import { getNode, HvigorNode, HvigorTask } from '@ohos/hvigor';
```
2、编写任务代码。
// 获取当前hvigorNode节点对象
const node: HvigorNode = getNode(__filename);
// 注册Task
node.registerTask({
name: 'customTask',
run() {
console.log('这是一个任务');
}
});
3、执行任务。
hvigorw customTask
需要注意的是,目前编译器对于ts文件不支持代码提示,直接在hvigorfile.ts文件中敲代码跟使用记事本敲代码没区别,非常容易出错。为了解决这个问题,可以使用VS Code,后面会教大家如何使用VS Code。
四、hvigor插件
hvigor允许开发者开发自己的插件,并与他人共享。hvigor主要提供了两种方式来实现插件:基于hvigorfile脚本开发插件、基于typescript项目开发。
4、1基于hvigorfile脚本开发
优点是可实现快速开发,直接编辑工程或模块下hvigorfile.ts即可编写插件代码。不足之处是在多个项目中,无法方便的进行插件代码的复用和共享分发。并且编译器对于ts文件不支持代码提示,直接在hvigorfile.ts文件中敲代码跟使用记事本敲代码没区别,非常容易出错。
1、编辑工程下hvigorfile.ts文件。
// 导入模块
import { HvigorPlugin, HvigorNode } from '@ohos/hvigor';
2、编写插件代码。在hvigorfile.ts中定义插件方法,实现HvigorPlugin接口。
// 实现自定义插件
function customPlugin(): HvigorPlugin {
return {
pluginId: 'customPlugin',
apply(node: HvigorNode) {
// 插件主体
console.log('这是个自定义插件');
}
}
}
3、在导出声明中使用插件。
export default {
system: appTasks,
plugins:[
customPlugin() // 应用自定义Plugin
]
}
4、执行hvigor命令时,在hvigor生命周期配置阶段执行插件中的apply方法。
4、2使用VS Code基于typescript项目开发
基于typescript项目开发较好地弥补了上一小节中使用hvigorfile脚本方式编写插件代码不易复用和共享分发的问题。同时可以使用VS Code开发,这样就有代码提示。因此通常情况下推荐此方式开发。
4、2、1初始化typescript项目
1、使用node -v命令查看node.js版本,如果node.js版本低于18.14.1,先将node.js版本升级到18.14.1或者以上,否则有些依赖会下载失败。
node -v
2、在鸿蒙项目的根目录下创建空目录,使用VS Code打开目录。
3、在VS Code的菜单栏中依次点击终端——新建终端,在终端依次输入下面的命令。
// 全局安装TypeScript,如果已经全局安装了TypeScript,就不用执行此命令
npm install typescript -g
// 初始化一个npm项目
npm init
// 初始化TypeScript配置文件
tsc --init
4、typescript项目初始化完成。
4、2、2开发插件
1、配置npm镜像仓库地址。在用户目录下创建或打开.npmrc文件,配置如下信息:
registry=https://repo.huaweicloud.com/repository/npm/
@ohos:registry=https://repo.harmonyos.com/npm/
2、打开package.json添加devDependencies配置。
"devDependencies": {
"@ohos/hvigor": "^5.8.9",
"@ohos/hvigor-ohos-plugin": "^5.8.9"
}
3、执行如下命令安装依赖。
npm install
在node_modules目录下能够看到hvigor目录和hvigor-ohos-plugin目录,说明依赖下载成功。
4、打开tsconfig.json,将tsconfig.json里面的配置替换成下面的配置。
{
"compilerOptions": {
"target": "ES2021",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"sourceMap": false,
"removeComments": true,
"outDir": "./dist",
"rootDir": "./src",
"declaration": true
},
"include": ["./src/**/*"],
"exclude": ["./node_modules/", "./dist/", "./tests/"]
}
5、在plugin目录下新建src目录和index.ts文件,在src目录下新建custom-plugin.ts,custom-plugin.ts的名字可以改,只要是ts文件即可。最终就有下图中这些文件。
6、打开custom-plugin.ts文件,添加下面的代码。如下代码,添加customPlugin函数,返回HvigorPlugin。pluginId指定插件的名字,重写apply方法,在apply方法中添加输出语句。
import {HvigorPlugin, HvigorNode} from '@ohos/hvigor'
export function customPlugin(): HvigorPlugin {
return {
pluginId: 'customPlugin',
apply(node: HvigorNode) {
console.log('这是一个自定义插件')
}
}
}
7、打开index.ts文件,在该文件中声明插件方法的导出。
export {customPlugin} from './src/custom-plugin'
8、在终端执行npm pack命令,在plugin目录下就生成了plugin-1.0.0.tgz文件。
npm pack
9、回到DevEco-Studio,打开hvigor目录下的hvigor-config.json文件,在dependencies添加下面的代码,将上一步生成的tgz文件引入。
{
"modelVersion": "5.0.0",
"dependencies": {
"@hadss/hmrouter-plugin": "file:../HMRouterPlugin/hadss-hmrouter-plugin-1.0.0.tgz",
"@shijing/plugin": "file:../plugin/plugin-1.0.0.tgz" /*引入tgz文件*/
},
"execution": {
// "analyze": "default", /* Define the build analyze mode. Value: [ "default" | "verbose" | false ]. Default: "default" */
// "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */
// "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */
// "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */
// "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */
},
"logging": {
// "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
},
"debugging": {
// "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */
},
"nodeOptions": {
// "maxOldSpaceSize": 4096 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process */
}
}
10、打开entry目录下hvigorfile.ts,导入customPlugin,将自定义插件添加到export default的plugins中。
import { harTasks } from '@ohos/hvigor-ohos-plugin';
import { customPlugin } from '@shijing/plugin';
export default {
system: harTasks,
plugins:[customPlugin()] /* 应用自定义插件 */
}
11、打开DevEco-Studio的终端,执行hvigorw --sync命令。
hvigorw --sync
在第6步中,我们在apply方法中添加了输出语句,执行hvigorw --sync命令,就会调用apply方法。
12、回到VS Code,我们修改apply方法,再添加两条输出语句。
import {HvigorPlugin, HvigorNode} from '@ohos/hvigor'
export function customPlugin(): HvigorPlugin {
return {
pluginId: 'customPlugin',
apply(node: HvigorNode) {
console.log('开始执行插件')
console.log('这是一个自定义插件')
console.log('结束执行插件')
}
}
}
13、修改完apply方法后,在VS Code的终端执行npm pack,这样就生成了一个新的plugin-1.0.0.tgz文件。
14、回到DevEco-Studio,打开DevEco-Studio的终端,执行hvigorw --sync命令。
如上图,明明我们添加了三条输出语句,但还是只输出了一条语句。虽然我们生成了新的plugin-1.0.0.tgz文件,但由于文件的版本号并没有发生改变,DevEco-Studio认为文件没有发生变化,就不会同步新的plugin-1.0.0.tgz文件,仍然使用的是老的plugin-1.0.0.tgz文件。其实我们只要修改版本号,DevEco-Studio就会同步新的tgz文件。
15、回到VS Code,打开package.json,将version字段修改为1.0.1。在VS Code的终端执行npm pack,这样就生成了一个新的plugin-1.0.1.tgz文件。
16、回到DevEco-Studio,打开hvigor/hvigor-config.json文件,按照下图操作。
如下图所示,输出了三条语句。
五、hvigor插件实战
当打包hap的时候,会在entry/build/default/outputs/default目录下生成entry-default-signed.hap和entry-default-signed.hap,这两个hap的文件名并没有带上版本号,也没有带上项目名称,为此需要修改文件名。在上一节中,我们学会如何自定义插件,现在我们就来实现一个修改文件名的插件。
5、1新建文件
新建rename.ts,添加下面的代码。
import { HvigorNode, HvigorPlugin, HvigorTaskContext } from "@ohos/hvigor";
import { OhosAppContext, OhosPluginId } from '@ohos/hvigor-ohos-plugin';
import { AppJson } from "@ohos/hvigor-ohos-plugin/src/options/configure/app-json-options";
import fs from 'fs'
export function rename(): HvigorPlugin {
return {
// 插件名称
pluginId: 'renameHapPlugin',
apply(node: HvigorNode) {
}
}
}
5、2注册任务
由于我们需要在打包期间执行插件,那就需要在插件中自定义任务。如下代码,在插件的apply方法中调用HvigorNode的registerTask方法注册任务,指定任务名称,当执行任务的时候,就会调用run方法。
export function rename(): HvigorPlugin {
return {
// 插件名称
pluginId: 'renameHapPlugin',
apply(node: HvigorNode) {
// 注册任务,指定任务名称,当执行任务的时候,就会调用run方法
node.registerTask({
// 任务名称
name: 'renameHapTask',
run: (taskContext: HvigorTaskContext) => {
}
})
}
}
}
5、3拿到模块名和模块路径
在run方法里面,通过HvigorTaskContext拿到模块名和模块路径。假设我们在entry目录的hvigorfile.ts文件调用插件,那拿到的模块名就是entry,模块路径就是entry模块的绝对路径。
export function rename(): HvigorPlugin {
return {
// 插件名称
pluginId: 'renameHapPlugin',
apply(node: HvigorNode) {
// 注册任务,指定任务名称,当执行任务的时候,就会调用run方法
node.registerTask({
// 任务名称
name: 'renameHapTask',
run: (taskContext: HvigorTaskContext) => {
// 获取模块名
const moduleName = taskContext.moduleName
// 获取模块路径
const modulePath = taskContext.modulePath
// 假设我们在entry目录的hvigorfile.ts文件调用插件,那拿到的模块名就是entry,模块路径就是entry模块的绝对路径。
console.log(`模块名:${moduleName}`)
console.log(`模块路径:${modulePath}`)
}
})
}
}
}
5、4获取原文件目录,创建新文件目录
如下图所示,生成的hap会在entry/build/default/outputs/default目录下。既然修改文件名,那就需要拿到原文件。在上一步,我们拿到了模块所在的路径,进而就可以拼接出原文件所在的路径。同时还需要创建新文件所在的目录。
export function rename(): HvigorPlugin {
return {
// 插件名称
pluginId: 'renameHapPlugin',
apply(node: HvigorNode) {
// 注册任务,指定任务名称,当执行任务的时候,就会调用run方法
node.registerTask({
// 任务名称
name: 'renameHapTask',
run: (taskContext: HvigorTaskContext) => {
// 获取模块名
const moduleName = taskContext.moduleName
// 获取模块路径
const modulePath = taskContext.modulePath
// 假设我们在entry目录的hvigorfile.ts文件调用插件,那拿到的模块名就是entry,模块路径就是entry模块的绝对路径。
console.log(`模块名:${moduleName}`)
console.log(`模块路径:${modulePath}`)
// hap所在路径
const originSignFilePath = `${modulePath}/build/default/outputs/default/${moduleName}-default-signed.hap`
const originUnsignFilePath = `${modulePath}/build/default/outputs/default/${moduleName}-default-unsigned.hap`
console.log(`原签名文件路径:${originSignFilePath}`)
console.log(`原未签名文件路径:${originUnsignFilePath}`)
// 新文件所在的目录
const targetFileDir = `${modulePath}/build/default/outputs/default/target`
// 创建目录
fs.mkdir(targetFileDir, {recursive: true}, (err) => {
console.log(`目录创建失败:{err}`)
})
}
})
}
}
}
5、5指定新文件的文件名
我们希望新文件的文件名带上项目名和版本。拿到父节点和OhosAppContext,就能获取到项目名。版本的话,我们希望读取AppScope目录下app.json文件里面的versionName字段。调用OhosAppContext的getAppJsonOpt,就能获取到app.json5文件中内容的obj对象,拿到versionName字段。拿到项目名和版本,就能确定新文件的文件名了。
export function rename(): HvigorPlugin {
return {
// 插件名称
pluginId: 'renameHapPlugin',
apply(node: HvigorNode) {
// 注册任务,指定任务名称,当执行任务的时候,就会调用run方法
node.registerTask({
// 任务名称
name: 'renameHapTask',
run: (taskContext: HvigorTaskContext) => {
// 获取模块名
const moduleName = taskContext.moduleName
// 获取模块路径
const modulePath = taskContext.modulePath
// 假设我们在entry目录的hvigorfile.ts文件调用插件,那拿到的模块名就是entry,模块路径就是entry模块的绝对路径。
console.log(`模块名:${moduleName}`)
console.log(`模块路径:${modulePath}`)
// hap所在路径
const originSignFilePath = `${modulePath}/build/default/outputs/default/${moduleName}-default-signed.hap`
const originUnsignFilePath = `${modulePath}/build/default/outputs/default/${moduleName}-default-unsigned.hap`
console.log(`原签名文件路径:${originSignFilePath}`)
console.log(`原未签名文件路径:${originUnsignFilePath}`)
// 新文件所在的目录
const targetFileDir = `${modulePath}/build/default/outputs/default/target`
// 创建目录
fs.mkdir(targetFileDir, {recursive: true}, (err) => {
console.log(`目录创建失败:{err}`)
})
// 获取父节点
const parentNode = node.getParentNode()
// 获取OhosAppContext
const appContext = parentNode?.getContext(OhosPluginId.OHOS_APP_PLUGIN) as OhosAppContext
// 获取项目名
const projectName = appContext.getProjectName()
console.log(`项目名:${projectName}`)
// 获取AppScope目录下app.json文件里面的json
const appOptObj: AppJson.AppOptObj = appContext.getAppJsonOpt()
// 获取AppScope目录下app.json文件里面的versionName字段
const versionName = appOptObj.app.versionName
// 新文件路径
const targetSignFilePath = `${modulePath}/build/default/outputs/default/target/${projectName}-${versionName}-default-signed.hap`
const targetUnsignFilePath = `${modulePath}/build/default/outputs/default/target/${projectName}-${versionName}-default-unsigned.hap`
}
})
}
}
}
5、6复制文件
原文件存在的情况下才复制。
export function rename(): HvigorPlugin {
return {
// 插件名称
pluginId: 'renameHapPlugin',
apply(node: HvigorNode) {
// 注册任务,指定任务名称,当执行任务的时候,就会调用run方法
node.registerTask({
// 任务名称
name: 'renameHapTask',
run: (taskContext: HvigorTaskContext) => {
console.log(`开始执行重命名任务`)
// 获取模块名
const moduleName = taskContext.moduleName
// 获取模块路径
const modulePath = taskContext.modulePath
// 假设我们在entry目录的hvigorfile.ts文件调用插件,那拿到的模块名就是entry,模块路径就是entry模块的绝对路径。
console.log(`模块名:${moduleName}`)
console.log(`模块路径:${modulePath}`)
// hap所在路径
const originSignFilePath = `${modulePath}/build/default/outputs/default/${moduleName}-default-signed.hap`
const originUnsignFilePath = `${modulePath}/build/default/outputs/default/${moduleName}-default-unsigned.hap`
console.log(`原签名文件路径:${originSignFilePath}`)
console.log(`原未签名文件路径:${originUnsignFilePath}`)
// 新文件所在的目录
const targetFileDir = `${modulePath}/build/default/outputs/default/target`
// 创建目录
fs.mkdir(targetFileDir, {recursive: true}, (err) => {
console.log(`目录创建失败:{err}`)
})
// 获取父节点
const parentNode = node.getParentNode()
// 获取OhosAppContext
const appContext = parentNode?.getContext(OhosPluginId.OHOS_APP_PLUGIN) as OhosAppContext
// 获取项目名
const projectName = appContext.getProjectName()
console.log(`项目名:${projectName}`)
// 获取AppScope目录下app.json文件里面的json
const appOptObj: AppJson.AppOptObj = appContext.getAppJsonOpt()
const versionName = appOptObj.app.versionName
// 新文件路径
const targetSignFilePath = `${modulePath}/build/default/outputs/default/target/${projectName}-${versionName}-default-signed.hap`
const targetUnsignFilePath = `${modulePath}/build/default/outputs/default/target/${projectName}-${versionName}-default-unsigned.hap`
// 复制文件
if (fs.existsSync(originSignFilePath)) {
// 原文件存在才复制
fs.copyFile(originSignFilePath, targetSignFilePath, (err) => {
console.log(`复制文件失败:${err}`)
})
}
if (fs.existsSync(originUnsignFilePath)) {
// 原文件存在才复制
fs.copyFile(originUnsignFilePath, targetUnsignFilePath, (err) => {
console.log(`复制文件失败:${err}`)
})
}
console.log(`重命名任务执行完成`)
}
})
}
}
}
5、7指定任务的插入位置
我们自定义了任务,那任务什么时候执行呢?打包就是执行一个一个的任务,所有的任务组成了一个有向无环图。我们既然要重命名文件,那必然得等到原文件生成。查看所有的任务,我们会发现,当执行完default@SignHap任务后,hap就生成了,并且签名也完成,于是我们的重命名任务就需要default@SignHap执行完成后执行。
当执行完default@assembleHap任务后,打包就结束了。所以,重命名任务就需要在default@SignHap执行完成后执行,在assembleHap任务执行之前执行。
在注册任务的时候,dependencies用于指定前置依赖的任务,先执行前置依赖,再执行重命名任务。postDependencies用于指定后置依赖的任务,执行后置依赖前,必须先执行重命名任务。三个任务的执行顺序就变成了这样,default@SignHap ——> renameHapTask ——> assembleHap。
// 重命名任务在default@SignHap任务执行完成后执行
dependencies: ['default@SignHap'],
// 重命名任务在default@assembleHap任务执行完成前执行
postDependencies: ['assembleHap'],
// 任务名称
name: 'renameHapTask'
5、8完整代码
import { HvigorNode, HvigorPlugin, HvigorTaskContext } from "@ohos/hvigor";
import { OhosAppContext, OhosPluginId } from '@ohos/hvigor-ohos-plugin';
import { AppJson } from "@ohos/hvigor-ohos-plugin/src/options/configure/app-json-options";
import fs from 'fs'
export function rename(): HvigorPlugin {
return {
// 插件名称
pluginId: 'renameHapPlugin',
apply(node: HvigorNode) {
// 注册任务,指定任务名称,当执行任务的时候,就会调用run方法
node.registerTask({
// 任务名称
name: 'renameHapTask',
// 重命名任务在default@SignHap任务执行完成后执行
dependencies: ['default@SignHap'],
// 重命名任务在default@assembleHap任务执行完成前执行
postDependencies: ['assembleHap'],
run: (taskContext: HvigorTaskContext) => {
console.log(`开始执行重命名任务`)
// 获取模块名
const moduleName = taskContext.moduleName
// 获取模块路径
const modulePath = taskContext.modulePath
// 假设我们在entry目录的hvigorfile.ts文件调用插件,那拿到的模块名就是entry,模块路径就是entry模块的绝对路径。
console.log(`模块名:${moduleName}`)
console.log(`模块路径:${modulePath}`)
// hap所在路径
const originSignFilePath = `${modulePath}/build/default/outputs/default/${moduleName}-default-signed.hap`
const originUnsignFilePath = `${modulePath}/build/default/outputs/default/${moduleName}-default-unsigned.hap`
console.log(`原签名文件路径:${originSignFilePath}`)
console.log(`原未签名文件路径:${originUnsignFilePath}`)
// 新文件所在的目录
const targetFileDir = `${modulePath}/build/default/outputs/default/target`
// 创建目录
fs.mkdir(targetFileDir, {recursive: true}, (err) => {
console.log(`目录创建失败:{err}`)
})
// 获取父节点
const parentNode = node.getParentNode()
// 获取OhosAppContext
const appContext = parentNode?.getContext(OhosPluginId.OHOS_APP_PLUGIN) as OhosAppContext
// 获取项目名
const projectName = appContext.getProjectName()
console.log(`项目名:${projectName}`)
// 获取AppScope目录下app.json文件里面的json
const appOptObj: AppJson.AppOptObj = appContext.getAppJsonOpt()
const versionName = appOptObj.app.versionName
console.log(`版本:${versionName}`)
// 新文件路径
const targetSignFilePath = `${modulePath}/build/default/outputs/default/target/${projectName}-${versionName}-default-signed.hap`
const targetUnsignFilePath = `${modulePath}/build/default/outputs/default/target/${projectName}-${versionName}-default-unsigned.hap`
// 复制文件
if (fs.existsSync(originSignFilePath)) {
// 原文件存在才复制
fs.copyFile(originSignFilePath, targetSignFilePath, (err) => {
console.log(`复制文件失败:${err}`)
})
}
if (fs.existsSync(originUnsignFilePath)) {
// 原文件存在才复制
fs.copyFile(originUnsignFilePath, targetUnsignFilePath, (err) => {
console.log(`复制文件失败:${err}`)
})
}
console.log(`重命名任务执行完成`)
}
})
}
}
}
5、9导出方法
打开index.ts文件,在该文件中声明插件方法的导出。
export {rename} from './src/rename'
5、10打包
打开终端,执行npm pack进行打包,生成tgz文件。
npm pack
5、11引入文件
回到DevEco-Studio,打开hvigor目录下的hvigor-config.json文件,在dependencies添加下面的代码,将上一步生成的tgz文件引入。
{
"modelVersion": "5.0.0",
"dependencies": {
"@shijing/plugin": "file:../plugin/plugin-1.0.0.tgz" /*引入tgz文件*/
}
}
5、12应用插件
打开entry目录下的hvigorfile.ts,导入rename,将自定义插件添加到export default的plugins中。
import { rename } from '@shijing/plugin';
export default {
system: hapTasks,
plugins:[rename()] /* 应用重命名任务 */
}
5、13执行插件
打开DevEco-Studio的终端,执行hvigorw assembleHap命令打包。如下图,default@SignHap任务执行完成后,开始重命名任务,相关的日志页打印出来了。
build/default/outputs/default/target目录也生成了文件。
六、hvigor定制构建
有的时候,仅仅只需要实现一个小小的功能,这时可以不使用插件,可以直接在hvigorfile.ts编码代码。但直接在hvigorfile.ts敲代码没有代码提示,仍然可以在VS Code中编码,然后将代码复制到hvigorfile.ts。
6、1修改app.json5中的配置信息
在项目的根目录下的hvigorfile.ts中添加如下代码内容:
import { appTasks, OhosAppContext, OhosPluginId } from '@ohos/hvigor-ohos-plugin';
import { hvigor } from '@ohos/hvigor'
// 为根节点添加一个afterNodeEvaluate hook 在hook中修改app.json5的内容并使能
hvigor.getRootNode().afterNodeEvaluate(rootNode => {
// 获取app插件的上下文对象
const appContext = rootNode.getContext(OhosPluginId.OHOS_APP_PLUGIN) as OhosAppContext;
// 通过上下文对象获取从app.json5文件中读出来的obj对象
const appJsonOpt = appContext.getAppJsonOpt();
// 修改obj对象为想要的,此处举例修改app中的versionCode
appJsonOpt['app']['versionCode'] = 1000001;
// 将obj对象设置回上下文对象以使能到构建的过程与结果中
appContext.setAppJsonOpt(appJsonOpt);
})
export default {
system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}
6、2修改module.json5中的配置信息
通过hvigor对象的hook能力快捷为所有的node创建hook,此处先举例为单一的node创建一个hook并修改其中的module.json5的配置信息。
例如此处需要修改entry下的module.json5配置,则在entry下的hvigorfile.ts中添加如下内容:
import { hapTasks, OhosHapContext, OhosPluginId } from '@ohos/hvigor-ohos-plugin';
import { getNode } from '@ohos/hvigor'
const entryNode = getNode(__filename);
// 为此节点添加一个afterNodeEvaluate hook 在hook中修改module.json5的内容并使能
entryNode.afterNodeEvaluate(node => {
// 获取此节点使用插件的上下文对象 此时为hap插件 获取hap插件上下文对象
const hapContext = node.getContext(OhosPluginId.OHOS_HAP_PLUGIN) as OhosHapContext;
// 通过上下文对象获取从module.json5文件中读出来的obj对象
const moduleJsonOpt = hapContext.getModuleJsonOpt();
// 修改obj对象为想要的,此处举例修改module中的deviceTypes
moduleJsonOpt['module']['deviceTypes'] = ["phone", "tablet", "2in1", "car"];
// 将obj对象设置回上下文对象以使能到构建的过程与结果中
hapContext.setModuleJsonOpt(moduleJsonOpt);
})
export default {
system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}
6、3修改oh-package.json5中的依赖
可以通过hvigorfile.ts自定义插件修改工程级、模块级的oh-package.json5的依赖,例如在工程级hvigorfile.ts或模块级hvigorfile.ts分别添加以下内容:
// 工程级hvigorfile.ts
import { appTasks, OhosAppContext, OhosPluginId, Target } from '@ohos/hvigor-ohos-plugin';
import { HvigorNode, HvigorPlugin, TaskInput, TaskOutput } from '@ohos/hvigor';
export function customPlugin(): HvigorPlugin {
return {
pluginId: 'customPlugin',
async apply(currentNode: HvigorNode): Promise<void> {
const appContext = currentNode.getContext(OhosPluginId.OHOS_APP_PLUGIN) as OhosAppContext;
const dependency = appContext.getDependenciesOpt({}); //获取dependency依赖
dependency["library"]="file:library.har"
console.log(dependency);
appContext.setDependenciesOpt(dependency ); //修改dependency依赖
}
};
}
export default {
system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[customPlugin()] /* Custom plugin to extend the functionality of Hvigor. */
}
// 模块级hvigorfile.ts
import {hapTasks,OhosHapContext,OhosPluginId,Target} from '@ohos/hvigor-ohos-plugin';
import { hvigor, HvigorNode, HvigorPlugin} from '@ohos/hvigor';
import * as fs from 'fs';
export function customPlugin(options: OnlineSignOptions): HvigorPlugin {
return {
pluginId: 'customPlugin',
context() {
return {
signConfig: options
};
},
async apply(currentNode: HvigorNode): Promise<void> {
const hapContext = currentNode.getContext(OhosPluginId.OHOS_HAP_PLUGIN) as OhosHapContext;
const dependency = hapContext.getDependenciesOpt({});//获取dependency依赖
dependency["library"]="file:library.har"
hapContext.setDependenciesOpt(dependency);}
}
};
export default {
system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[customPlugin()] /* Custom plugin to extend the functionality of Hvigor. */
}
七、总结
- DevEco-Studio不支持ts文件的代码提示,可以使用VS Code。
- 在VS Code修改完代码后,打开package.json修改版本,执行npm pack命令打包,然后回到DevEco-Studio应用插件。
- 代码是在打包期间执行的,无法断点调试,所以需要多多的打印日志,通过日志排查问题。