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
由于开发环境的不同,配置文件信息也有所不同,无非就是更改的模版不一样,只需要在脚本中,换成你的环境下的配置文件内容即可。
相关文章:
HarmonyOS开发:NodeJs脚本实现组件化动态切换
前言 上篇文章,我们使用NodeJs脚本完成了HarmonyOS项目的组件化运行,但是由于脚本是基于4.0.0.400版本的DevEco Studio开发的,可能在配置文件的修改上有些许差距,那么遇到这种情况怎么办,一种是再写一套针对性的脚本文…...
基于springboot实现就业信息管理系统项目【项目源码+论文说明】计算机毕业设计
基于springboot实现就业信息管理系统演示 摘要 随着信息化时代的到来,管理系统都趋向于智能化、系统化,就业信息管理系统也不例外,但目前国内仍都使用人工管理,市场规模越来越大,同时信息量也越来越庞大,人…...
Vue组件的本质和手写通过render渲染函数渲染组件
1.组件的本质 组件就是一组 DOM 元素的封装,本质就是一个对象 (mounted函数中打印一下组件即可看到打印的是一个对象) 如何利用javascript对象来描述一个组件? const MyComponent {render() {return {tag: div,props: {onClick: () > alert(hell…...
【优选算法系列】第一节.双指针(283. 移动零和1089. 复写零)
作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:优选算法系列 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!!…...
Vue(uniapp)父组件方法和子组件方法执行优先顺序
涉及到的知识点:watch监控:先看问题,父组件从后端通过$ajax获取数据,在将父组件将值传输给子组件,使用子组件使用created钩子函数获取数据,按自己的想法应该是父组件先获取后端数据,在传入给子组…...
怎么突破反爬虫机制
在当今的数字化时代,网络爬虫已经成为了收集信息和数据的重要工具。然而,许多网站和平台都配备了反爬虫机制,以防止恶意攻击和过度访问。对于普通用户来说,如何突破这些反爬虫机制呢?本文将为你提供一些实用的技巧和建…...
CSP-J2023入门组第二轮T4:旅游巴士
题目描述 小 Z 打算在国庆假期期间搭乘旅游巴士去一处他向往已久的景点旅游。 旅游景点的地图共有 n n n 处地点,在这些地点之间连有 m m m 条道路。其中 1 1...
OS的Alarm定时器调度机制
调度表触发的任务在编译时就被静态定义,任务的触发时间和执行顺序是固定的。这种方式适用于已知的、固定的任务触发模式,例如周期性任务或事件驱动任务。而使用 Alarm 机制触发的任务具有更大的灵活性。Alarm 允许在运行时动态地设置和修改任务的触发时间…...
I2C协议
1.简介 IIC(Inter-Integrated Circuit)其实是IICBus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,半双工通信,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用…...
全栈经验总结(不间断更新)
1.当后端传回来的值为列表套字典[{"id":1,"num":"1"},{"id":2"num":"3"}],如果要在vue3里面渲染图片,可以这样操作 <el-form-item label"图片:"><el-uploa…...
什么是恶意代码?
前言:本文旨在分享交流技术,在这里对恶意代码进行全面的介绍和讲解 目录 一.什么是恶意代码 二.恶意代码的发展史 三.恶意代码的相关定义 四.恶意代码攻击机制 PE病毒 PE文件的格式 脚本病毒 脚本文件隐藏方法 宏病毒 浏览器恶意代码 U盘病毒 …...
HCL模拟器选路实验案例
此选路题目选自职业院校技能竞赛中的一道题比较考验思路,适合于参加新华三杯大赛以及网络专业的同学,当做练习题目进行解题 题目 1.S1、S2、R1、R2运行ospf进程100,区域0,R1、R2、R3、R4、R5运行ospf进程200&#…...
toluaframework中C#怎么调用Lua的方法以及无GC方法
toluaframework中C#怎么调用Lua的方法 问题Util.CallMethodLuaManager.CallFunctionLuaFunction.LazyCall 解决方案LuaFunction脚本无GC消耗的调用 用法总结 问题 用过luaframework框架的人应该都知道框架提供了Util的工具类,工具类提供了一个方法就是Util.CallMet…...
安装pandas报错
报错信息: C:\Users\Jordan>pip install pandas Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple/ Collecting pandasUsing cached https://pypi.tuna.tsinghua.edu.cn/packages/3a/6e/6c9c197ec2da861ea8c9c6848f0f887b7563f16e607bc6a35506af6…...
总有一天,你一定会很棒
晚上从一个大商场吃完饭出来,看到两个垂头丧气的男孩,他们坐在商场门口的户外台阶上,低着头,不停的搓着手,看不见他们的脸,只能看见他们不说话。在他们的面前,是一个年级大约25岁左右的女孩子&a…...
带你深入了解队列(c/cpp双版本模拟实现)
目录 一.队列的概念及结构 二.队列的实现 2.1队列的结构 2.2初始化队列 2.3队尾入队列 2.4队头出队列 2.5获取队列头部元素 2.6获取队列队尾元素 2.7获取队列中有效元素个数 2.8检测队列是否为空 2.9销毁队列 三.C 版本模拟实现队列 一.队列的概念及结构 队列…...
接口自动化测试实操
实现思路 使用excel管理用例用例信息,requests模块发送http请求,实现了记录日志,邮件发送测试报告的功能 目录结构如下: 下面直接上代码: 统筹脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24…...
Virtual DOM
目录 Virtual DOM 前言 用法 代码 理解 Virtual DOM的工作原理: 为什么使用Virtual DOM? 哪些库/框架使用Virtual DOM? 总结 Virtual DOM(虚拟DOM)是一种编程概念,它是对真实DOM的轻量级抽象表示。在前端开发中&#x…...
数据结构与算法-二叉树的遍历
🌞 “少年没有乌托邦,心向远方自明朗!” 二叉树 🎈1.二叉树的遍历🔭1.1先序遍历🔭1.2中序遍历🔭1.3后序遍历🔭1.4层次遍历🔭1.5二叉树遍历的递归算法📝1.5.1先…...
Qt之普通项目如何生成DLL(含源码+注释)
文章目录 一、示例图二、普通项目需要改造的内容三、源码(创建了一个TestDLL的项目,更改内容主要在pro文件和maindow.h文件)TestDLL.promainwindow.hmainwindow.cppmainwindow.ui 总结 一、示例图 使用不同的编译模式编译,会在对…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
Linux基础开发工具——vim工具
文章目录 vim工具什么是vimvim的多模式和使用vim的基础模式vim的三种基础模式三种模式的初步了解 常用模式的详细讲解插入模式命令模式模式转化光标的移动文本的编辑 底行模式替换模式视图模式总结 使用vim的小技巧vim的配置(了解) vim工具 本文章仍然是继续讲解Linux系统下的…...
Python第七周作业
Python第七周作业 文章目录 Python第七周作业 1.使用open以只读模式打开文件data.txt,并逐行打印内容 2.使用pathlib模块获取当前脚本的绝对路径,并创建logs目录(若不存在) 3.递归遍历目录data,输出所有.csv文件的路径…...
C# WPF 左右布局实现学习笔记(1)
开发流程视频: https://www.youtube.com/watch?vCkHyDYeImjY&ab_channelC%23DesignPro Git源码: GitHub - CSharpDesignPro/Page-Navigation-using-MVVM: WPF - Page Navigation using MVVM 1. 新建工程 新建WPF应用(.NET Framework) 2.…...
基于小程序老人监护管理系统源码数据库文档
摘 要 近年来,随着我国人口老龄化问题日益严重,独居和居住养老机构的的老年人数量越来越多。而随着老年人数量的逐步增长,随之而来的是日益突出的老年人问题,尤其是老年人的健康问题,尤其是老年人产生健康问题后&…...
MySQL基本操作(续)
第3章:MySQL基本操作(续) 3.3 表操作 表是关系型数据库中存储数据的基本结构,由行和列组成。在MySQL中,表操作包括创建表、查看表结构、修改表和删除表等。本节将详细介绍这些操作。 3.3.1 创建表 在MySQL中&#…...
