HarmonyOS开发:NodeJs脚本实现组件化动态切换

前言

上篇文章,我们使用NodeJs脚本完成了HarmonyOS项目的组件化运行,但是由于脚本是基于4.0.0.400版本的DevEco Studio开发的,可能在配置文件的修改上有些许差距,那么遇到这种情况怎么办,一种是再写一套针对性的脚本文件或者在原有的脚本中增加配置版本参数,第二种就是自己搞一个,俗话说,授人以鱼不如授人以渔,索性这篇文章,就把上篇的脚本,是如何实现的,给大家阐述一下,这样,大家就可以自己操作了。

分析需求

需求的总体概括就非常的简单,让动态共享包的模块,在运行包和动态共享包之间可以动态的切换,省去人工配置的步骤,由上篇文章,我们已经得知,动态共享包和运行包之间的区别,主要来源于三处,分别是hvigorfile.ts文件、module.json5文件和缺少入口ability

首先,肯定需要一个可以控制的开关,利用这个开关,判断是否要进行模块的动态切换,如果需要切换,那么就执行动态共享包切换运行包,否则就还原,大致流程如下:

梳理模板

无论是由动态共享包切换为运行包,还是由运行包切换为动态共享包,我们改变的都是配置文件,也就是上述中存在差异的那三个文件,文件的内容,如何来回的更改呢,当然了可以设置统一的内容,只更改区别之处,但是为了直观,方便的查看和修改,无疑使用模版是比较简单的。

首先准备好两份文件,一份是动态共享包,一份是运行包,切换的时候,直接选择不同的模版即可。

动态共享包模版

动态共享包,需要提供两个模版即可,分别是hvigorfile.ts文件和module.json5文件。

1、hvigorfile.ts

import { hspTasks } from '@ohos/hvigor-ohos-plugin';export default {system: hspTasks,  /* Built-in plugin of Hvigor. It cannot be modified. */plugins:[]         /* Custom plugin to extend the functionality of Hvigor. */
}

2、module.json5

{"module": {"name": "mine","type": "shared","description": "$string:shared_desc","deviceTypes": ["phone","tablet"],"deliveryWithInstall": true,"pages": "$profile:main_pages"}
}

运行包模版

运行包除了两个配置文件不同,还必须有Ability,作为主入口,这是必不可少的。

1、hvigorfile.ts

import { hapTasks } from '@ohos/hvigor-ohos-plugin';export default {system: hapTasks,  /* Built-in plugin of Hvigor. It cannot be modified. */plugins:[]         /* Custom plugin to extend the functionality of Hvigor. */
}

2、module.json5

{"module": {"name": "entry","type": "entry","description": "$string:module_desc","mainElement": "EntryAbility","deviceTypes": ["phone","tablet"],"deliveryWithInstall": true,"installationFree": false,"pages": "$profile:main_pages","abilities": [{"name": "EntryAbility","srcEntry": "./ets/entryability/EntryAbility.ts","description": "$string:EntryAbility_desc","icon": "$media:icon","label": "$string:EntryAbility_label","startWindowIcon": "$media:icon","startWindowBackground": "$color:start_window_background","exported": true,"skills": [{"entities": ["entity.system.home"],"actions": ["action.system.home"]}]}]}
}

3、Ability

import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import hilog from '@ohos.hilog';
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import window from '@ohos.window';export default class EntryAbility extends UIAbility {onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');}onDestroy() {hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');}onWindowStageCreate(windowStage: window.WindowStage) {// Main window is created, set main page for this abilityhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');windowStage.loadContent('pages/Index', (err, data) => {if (err.code) {hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');return;}hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');});}onWindowStageDestroy() {// Main window is destroyed, release UI related resourceshilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');}onForeground() {// Ability has brought to foregroundhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');}onBackground() {// Ability has back to backgroundhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');}
}

技术实现

1、创建配置文件

第一步,书写开关,也就是配置文件,当然了配置文件具体如何定义,看自己安排,无论何种形式展现,该有的参数一定要有,比如是否要开启组件化以及开启组件化的模块名字,至于其他的参数,可以根据需要进行添加,目前我定义的配置文件如下,具体的解释,都有注释,上篇文章中也做了一系列的解读。

#组件化配置文件
#是否开启组件化
startModule=false
#开启的组件名字,开启后,当前的组件可以独立运行
startModuleName=
#上述组件开启后,其他非必要组件是否改为动态包模式,默认不改变
startOtherShared=false
#过滤组件名字,永远不会独立运行,以应为逗号作为分割
filterModuleName=
#当前脚本默认加载的页面,默认不填是Index.ets
loadPage=

配置文件,这里我自定义了后缀,具体是什么文件都所谓,主要的是文件里的内容。

有了配置文件之后,我们就可以根据配置文件来一层一层的实现相关逻辑。

2、初始化项目

nodeJs环境,在安装DevEco Studio的时候就已经配置完成,检验是否安装,可以在命令行中执行如下命令:

node -v

如果正常能显示版本号,则安装成功。

在需要创建脚本的目录,执行初始化操作:

npm init

具体的步骤解释:

package name 包名,也就是工程名,默认是括号中的内容 
version:版本号,默认是括号中的内容 
description:描述信息 
entry point:入口文件名,默认是括号中的内容 
test command:测试命令 
git repository:git仓库地址 
keywords: 密码 
author: 作者名字 
license: (ISC)许可证

一路按照相关提示,执行下一步即可,其实就是生产了一个json配置文件,大家也可以自己手动创建。

执行完毕之后,就会在当前目录,创建一个json文件。

json文件内容:

3、创建执行js文件

这个js文件就是我们所有逻辑的书写地方,为了能够让js文件可以正常运行,我们需要在package.json文件里进行配置,如下:

以后执行脚本的时候,直接在命令行中,执行npm run module即可,我们先简单的输出一个“Hello world”,首先在module.js里进行打印,如下所示:

执行命令结果:

3、完成最后的逻辑

由于需要对文件进行操作,这里使用到了Node.js中的核心模块fs,一句话介绍,fs模块提供了丰富的函数和方法,可以进行文件的读取、写入、复制、删除等操作,同时也支持目录的创建、遍历和修改等操作,如果你想要更详细的了解,可以查看我的往期文章,或者在网上搜索也行,有大量的资料存在。

1)、读取配置文件

所有的功能实现都是基于配置文件,所以配置文件里的参数至关重要,也是程序的第一步,读取配置文件,逐项拿到设置的相关参数,并记录下来。

//读取文件信息let path = require('path');let dirName = path.join(__dirname); //获取跟目录try {//读取配置文件,查找对应的配置信息let data = fs.readFileSync(dirName + "/module.harmony", 'utf-8');var startModule;var startModuleName;var filterModuleName;var startOtherShared;var loadContentPage;data.split(/\r?\n/).forEach((line, position) => {if (position === 2) {let open = line.split("=")[1];startModule = open.toString();}if (position === 4) {let moduleName = line.split("=")[1];startModuleName = moduleName.toString();}if (position === 6) {let otherName = line.split("=")[1];startOtherShared = otherName.toString();}if (position === 8) {let filterName = line.split("=")[1];filterModuleName = filterName.toString();}if (position === 10) {//load的页面信息let loadPage = line.split("=")[1];loadContentPage = loadPage.toString();}});//开启组件化之后,单独的模块可以独立运行//不开启组件化,那么entry可以独立运行,其他均不可,需要一一更改配置文件traverseFolder(dirName, startModule.indexOf("true") !== -1,startModuleName, startOtherShared, filterModuleName, loadContentPage);} catch (e) {console.log("发生了错误,请检查配置文件是否存在,或反馈至AbnerMing");}

2)、动态修改配置文件信息

根据配置文件信息,进行组件化运行,也就是动态共享包切换为运行包,如何切换,拿到差异性文件,然后读取模版信息,进行写入即可。

需要注意的是,动态共享包,切换为运行包,需要动态创建ability,除此之外,关于组件的名字,ability名字,尽量和组件保持一致。

运行包切换为动态共享包,也是读取配置文件,然后进行写入即可。

function traverseFolder(folderPath, isModule, startModuleName,startOtherShared, filterModuleName, loadContentPage) {const items = fs.readdirSync(folderPath);items.forEach(item => {let dir = folderPath + "/" + item;const stats = fs.statSync(dir);if (stats.isDirectory()) {let hvigorFilePath = dir + "/hvigorfile.ts";fs.readFile(hvigorFilePath, "utf8", (err, dataStr) => {if (err) {return;}if (isModule) {//开启组件化//把当前的组件改为运行状态if (item == startModuleName) {let moduleName = item.substring(0, 1).toUpperCase()+ item.substring(1, item.length)//修改为可运行状态let entryHvigorFile = getEntryHvigorFile();//读取string.json文件,增加labellet jsonName = dir + "/src/main/resources/base/element/string.json";fs.readFile(jsonName, "utf8", (err, dataStr) => {if (err) {return;}let obj = JSON.parse(dataStr);let array = obj["string"];let label = { "name": "shared_label", "value": item };let isSharedLabel = false;for (var i = 0; i < array.length; i++) {let name = array[i]["name"];if (name == "shared_label") {isSharedLabel = true;break;}}if (!isSharedLabel) {array.push(label);}writeContent(jsonName, JSON.stringify(obj));//进一步更改json5文件let json5 = dir + "/src/main/module.json5";writeContent(json5, getEntryModuleJson5(item, moduleName));});if (loadContentPage == null || loadContentPage == "") {//为空的时候才去创建//创建Index.ets文件let indexPath = dir + "/src/main/ets/pages";const indexItem = fs.readdirSync(indexPath);let isHaveIndex = false;indexItem.forEach(item => {if (item == "Index.ets") {//证明存在isHaveIndex = true;}});if (!isHaveIndex) {//不存在,就要去创建writeContent(indexPath + "/Index.ets", getIndex());}}//创建Ability文件let etsPath = dir + "/src/main/ets/" + item + "ability/" + moduleName + "Ability.ts";fs.mkdir(dir + "/src/main/ets/" + item + "ability", function (err) {if (err) {writeContent(etsPath, getAbility(moduleName, loadContentPage));return;}//写入文件writeContent(etsPath, getAbility(moduleName, loadContentPage));});} else {//非当前的组件,需要改为动态包模式吗,根据配置文件来改变,有两种是永远不能改变的if (item != "entry" && filterModuleName.indexOf(item) == -1 && startOtherShared) {//把其他的模块都改成动态包,不能运行let moduleJson5 = getSharedModuleJson5(item);let hvigorFile = getSharedHvigorFile();writeContent(hvigorFilePath, hvigorFile);writeContent(dir + "/src/main/module.json5", moduleJson5);}}} else {//主模块和需要过滤的模块不进行动态包设置if (item != "entry" && filterModuleName.indexOf(item) == -1) {//把其他的模块都改成动态包,不能运行let moduleJson5 = getSharedModuleJson5(item);let hvigorFile = getSharedHvigorFile();writeContent(hvigorFilePath, hvigorFile);writeContent(dir + "/src/main/module.json5", moduleJson5);}}});}});
}

相关总结

由于逻辑比较简单,完整的逻辑,大家可以查看源码:

https://gitee.com/abnercode/harmony-os-module

由于开发环境的不同,配置文件信息也有所不同,无非就是更改的模版不一样,只需要在脚本中,换成你的环境下的配置文件内容即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/120875.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Oracle】[INS-30131]执行安装程序验证所需的初始设置失败。

这里写目录标题 一、问题描述1 报错内容1.1 无法从节点“kotin”检索 exectask 的版本1.2 工作目录"xxx"无法在节点"kotin"上使用 2 相关环境2.1 安装软件2.2 安装系统 3 解决思路分析 二、解决方案1 方案一、 满足验证条件 - 不换系统1.1 第一步、检查文件…

笔记 | MySQL 运维常用语句

1.导出整个库 mysqldump -u 用户名 -p –default-character-setlatin1 数据库名 > 导出的文件名(数据库默认编码是latin1) mysqldump -u wcnc -p smgp_apps_wcnc > wcnc.sql2.导出一个表 mysqldump -u 用户名 -p 数据库名 表名> 导出的文件名 mysqldump -u wcnc…

p5.js 到底怎么设置背景图?

本文简介 点赞 关注 收藏 学会了 在 《p5.js 光速入门》 里我们学过加载图片元素&#xff0c;学过过背景色的用法&#xff0c;但当时没提到背景图要怎么使用。 本文就把背景图这部分内容补充完整&#xff0c;并且会提到在 p5.js 里使用背景图的一些注意点。 背景图的用法…

Oracle数据库基础

一、Oracle数据库介绍: Oracle数据库是由Oracle公司开发的关系型数据库管理系统(RDBMS),它是世界上最流行和广泛使用的商业数据库之一。Oracle数据库提供了可靠、高性能和安全的数据管理解决方案,被广泛应用于企业级应用程序和大型数据中心。 二、Oracle数据库各个版本的…

在虚拟环境中,通过pip安装tensorflow

目录 激活python虚拟环境&#xff0c;更新pip 通过pip 安装tensorflow 确定python版本&#xff1a; ​编辑安装tensorflow: ​编辑 为什么使用pip安装tensorflow? 激活python虚拟环境&#xff0c;更新pip 命令为python -m pip install --upgrade pip 通过pip 安装tensorf…

C语言之结构体和共用体详解

目录 结构体 结构体的定义和使用 结构体数组的使用 结构体指针的使用 结构体大小的计算 共用体 共用体的定义和使用 typedef用法详解 enum枚举类型 结构体 结构体的定义和使用 C语言的结构体&#xff08;Struct&#xff09;是一种自定义的数据类型&#xff0c;它允许…

时间、空间复杂度的例题详解

文章前言 上篇文章带大家认识了数据结构和算法的含义&#xff0c;以及理解了时间、空间复杂度&#xff0c;那么接下来来深入理解一下时间、空间复杂度。 时间复杂度实例 实例1 // 计算Func2的时间复杂度&#xff1f; void Func2(int N) {int count 0;for (int k 0; k <…

数据结构与算法之排序: 堆排序 (Javascript版)

排序 排序&#xff1a;把某个乱序的数组变成升序或降序的数组 (这里用数组来做举例) 堆排序 该排序属于 Selectionsort 选择排序的优化版本由于堆排序的查找过程从O(n)优化为O(logn)整体的排序时间复杂度为 O(nlogn)&#xff0c;这是排序算法中的最优解&#xff01;&#xf…

图的应用4.0-----关键路径(AOE网)

目录 前言 AOE网 1.基本概念 2.应用 关键路径 1.算法理论 2.代码实现&#xff08;C/C&#xff09; 前言 前面学习了图AOV网的应用&#xff0c;即拓扑排序&#xff0c;那这一期我们学习AOE网的应用&#xff0c;这是一个图的一个很广泛问题&#xff0c;也就是关键路径。那…

apisix之插件开发,包含java和lua两种方式

https://download.csdn.net/download/tiantangpw/88475630 有ppt和springboot程序包,可以运行

HCIA --- ACL(访问控制列表)

ACL访问控制列表 一、作用 访问控制 --- 在路由器流量进或出的接口上&#xff0c;匹配流量产生动作---允许、拒绝定义感兴趣流量 --- 抓取流量&#xff0c;之后给到其他的策略&#xff0c;让其他策略进行工作&#xff1b; 二、匹配规则 至上而下逐一匹配&#xff0c;上条匹…

linux查看硬件信息命令

文章目录 cpu内核版本内存硬盘主板服务器参考链接 cpu cat /proc/cpuinfo 一个物理CPU可以有1个或者多个物理内核&#xff0c;一个物理内核可以作为1个或者2个逻辑CPU。 物理CPU数就是主板上实际插入的CPU数量。 在Linux上cat /proc/cpuinfo&#xff0c;会打印每个cpu的信息 …

k8s中kubectl陈述式资源管理

目录 1、 理论 1.1、 管理k8s核心资源的三种基本方法 &#xff1a; 1.1.1陈述式的资源管理方法&#xff1a; 1.1.1.1、优点&#xff1a; 1.1.1.2、缺点&#xff1a; 1.1.2、声明式资源管理方法 1.1.3、GUI式资源管理方法 1.2、陈述式资源管理方法 2. 对资源的增、删、…

[推荐]Linux安装与配置虚拟机之虚拟机服务器坏境配置

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 越努力 &#xff0c;越幸运。 一.操作系统 1. 简介 操作系统&#xff08;perating System&#xff0c;简称OS&#xff09;是一种系统软件…

SQL server数据库单用户模式如何退出

根据网上的说法&#xff0c;用下面的方式尝试即可退出 进入ssms数据库管理软件执行下面的sql语句 -- 第一步执行USE [master] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO--建一个存储过程&#xff0c;断开所有用户连接。 create proc [dbo].[killspid] (dbn…

决定放弃uniapp开发了,因为它实在是没有taro友好

被uniapp折腾了两天&#xff0c;实在是受不了它对vue3的支持和react的支持&#xff0c;可以这么说&#xff0c;uniapp完全没有支持vue3和react&#xff0c;这么说我觉得一点也不过分。相对于折腾了两天uniapp来讲&#xff0c;我使用taro只花了1个小时不到&#xff0c;就可以完美…

【java学习—八】单例设计模式(5)

文章目录 1. 相关概念2. 单例设计模式-饿汉式3. 单例设计模式-懒汉式4. 总结 1. 相关概念 单例&#xff1a;只有一个实例&#xff08;实例化对象&#xff09; 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的…

【鸿蒙软件开发】ArkTS通用事件

文章目录 前言一、点击事件1.1 基础介绍1.2 ClickEvent对象说明1.3 示例代码 二、触摸事件2.1 基础介绍2.2 ClickEvent对象说明2.3 示例代码 二、焦点事件2.2 基础介绍3.2 示例代码 总结 前言 在我们的ArkTS中有一些通用的事件&#xff0c;他们在所有的组件中都可以用&#xf…

评价聚类的方法

inertias:inertias是K均值模型对象的属性&#xff0c;表示样本距离最近的聚类中心的总和&#xff0c;它是作为在没有真实分类结果标签下的非监督式评估指标。该值越小越好&#xff0c;值越小证明样本在类间的分布越集中&#xff0c;即类内的距离越小。 adjusted_rand_s&#x…

网工内推 | 急招网工,思科、华为认证优先,法定节假日三薪

01 江苏臻云技术 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、负责落实数据中心机房日常网络监测及巡检任务&#xff1b; 2、负责数据中心网络设备日常监控、变更、维护、巡检&#xff1b; 3、负责日常巡检报告、故障维护报告、变更申请的文档的编制&#xff1b;…