HarmonyOS 鸿蒙应用开发(十、第三方开源js库移植适配指南)

在前端和nodejs的世界里,有很多开源的js库,通过npm(NodeJS包管理和分发工具)可以安装使用众多的开源软件包。但是由于OpenHarmony开发框架中的API不完全兼容V8运行时的Build-In API,因此三方js库大都需要适配下才能用。

移植前准备

建议在适配JS三方库前,使用[js-e2e]扫描三方库,检查是否存在node.js/web内置模块的依赖。

js-e2e工具时基于eslint进行封装,可分析出JS库代码对node.js/web浏览器的内置模块、对象的依赖及兼容ES标准版本,使用该工具,可以快速知道该库是否依赖node.js/web内置模块。

如果扫描结果不依赖node.js/web内置模块,那么,这个库将比较轻松地适配。如果大量依赖node.js/web内置组件,这时可能需要fork源库代码,进行侵入式修改,或者再找是否存在更适合的其他三方库。

JS三方库扫描工具介绍

js-e2e是基于eslint进行封装、配置规则,用于分析JS库代码对NodeJS和Web浏览器的内置模块、对象的依赖及兼容ES标准版本的工具,支持检查指定源码目录和指定三方库的兼容性。

1 使用git工具同步js-e2e代码

image.png

2 安装npm依赖包

image.png

3 安装自定义的eslint输出报告formatter,包含csv、csvsimple、vscode、vscodesimple

image.png

4 执行检查命令

image.png

注意事项

模块规范

注意将要移植使用的三方js库的模块规范,AMD、CMD、CommonJS、ES Module等模块规范,看你需要的三方库所使用的规范是哪种。

CommonJS规范主要是为了弥补JavaScript没有标准的缺陷,已达到像Python、Ruby和Java那样具备开发大型应用的基础能力,而不是停留在开发浏览器端小脚本程序的阶段。使用CommonJS规范进行开发,需要依赖Node.js环境。(例如浏览器不兼容CommonJS的根本原因,在于缺少四个Node.js环境的变量:module、exports、require、global)

AMD规范(异步模块定义)是 RequireJS 在推广过程中对模块定义的规范化产出,不是JavaScript原生支持。使用AMD规范进行开发时,需要引入RequireJS这个第三方函数库,通过define()来定义模块,采用require()语句来加载模块。

CMD(通用模块定义)是 SeaJS 在推广过程中对模块定义的规范化产出。使用CMD规范进行开发时,需要引入SeaJS这个第三方函数库。在CMD规范中,一个模块就是一个文件,使用define()语句定义模块,使用seajs.use()加载模块。

三者的区别

CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。

AMD是异步加载模块,核心是预加载,先对依赖的全部文件进行加载,加载完了再进行处理。

CMD也是异步加载模块,是按需加载。AMD和CMD最大的区别是对依赖模块的执行时机不同,而不是加载时机不同,二者皆为异步加载模块。

AMD是前置依赖,在定义模块的时候就要声明其依赖的模块。

CMD是就近依赖,只有在用到某个模块的时候再去require。

模块(关键字module)

“内部模块”现在称作“命名空间”,“外部模块”现在简称为“模块”。

内部外部为一个相对概念,在ES6和Nodejs中,引入了模块的概念,即一个文件就是一个模块;“内部模块”即当前文件内的模块,“外部模块”即当前文件外的其他模块。

例如我们在TS工程下新建一个ts文件声明一个变量a,在另一个文件同样声明一个变量a,这时候会出现错误信息:

原因:因为该文件内容是对全局可见的。
解决方案:只需要通过import || export引入模块系统即可。

ES6:(TS也适用)
导出模块:export;(默认导出 export default)
导入模块:import;

CommonJS和AMD:
导出模块:module.exports 或 exports;
导入模块:require( );

为了支持CommomJS和AMD的exports,TS提供了export=语法:

ArkTS语言

HarmonyOS的ArkTS语言是一种基于TypeScript开发的语言,它专为HarmonyOS系统开发而设计。ArkTS语言结合了JavaScript的灵活性和TypeScript的严谨性,使得开发者能够快速、高效地开发出高质量的HarmonyOS应用程序。

ArkTS语言使用TypeScript语法,TypeScript是一种由微软开发的JavaScript超集语言,它支持JavaScript的所有语法,但添加了一些新的特性和语法,使开发更加可靠和高效。TypeScript最大的特点是引入了静态类型,开发者可以在编译时发现类型错误,提高代码的可维护性和可读性。

TypeScript基础知识包括基本类型、变量声明、函数、类、接口、泛型等。另外,TypeScript还支持模块化开发,可以使用ES模块规范或者CommonJS规范导入和导出模块。在实际项目开发中,统一指定采用一种模块规范,标准的ES模块规范。虽然AekTS使用了TypeScript的语法,但是也是有区别的,并不完全支持TypeScript的所有特性。

关于从TypeScript到ArkTS的适配规则,参见官方文档:

从TypeScript到ArkTS的适配规则typescript-to-arkts-migration-guide.md · OpenHarmony/docs - Gitee.com

注意在移植三方的js软件时,模块的导入导出是可能需要修改三方库源码的。

鸿蒙(HarmonyOS)的ArkTS(Ark TypeScript)使用的模块规范是ES6模块规范,而不是CommonJS模块规范。

ES6模块规范(也称为ECMAScript 2015模块规范)是一种现代的模块系统,它使用importexport关键字来导入和导出模块成员。ES6模块规范支持静态导入和导出,具有更好的树摇(tree shaking)和代码拆分(code splitting)特性,有助于优化应用程序的性能和大小。

相比之下,CommonJS模块规范是一种较旧的模块系统,它使用requiremodule.exports来导入和导出模块成员。CommonJS模块规范主要用于Node.js环境,并且在一些旧的浏览器环境中也有支持。

移植范例

鸿蒙官方的三方库地址:OpenHarmony三方库中心仓

移植很简单,成功移植了几个开源三方js库,jsbn和sm-crypto,并且编写了鸿蒙的arkUI的单元测试, 测试已通过。注意老的一些js库,在ts中使用时,需要d.ts类型声明文件。这个文件可以自己编写,也可以从网址找有没有对应的参考。一些常用的js三方库几乎都有现成的d.ts类型定义文件。可以在这里找下:GitHub - DefinitelyTyped/DefinitelyTyped: The repository for high quality TypeScript type definitions.

sm-crypto仓库地址:一缕阳光116/sm-crypto

jsbn仓库地址: 一缕阳光116/jsbn

sm-crypto移植

找到d.ts对应的声明文件并根据需要修改。比如依赖了yyz116/jsbn的大数库。

//index.d.ts
import jsbn from '@yyz116/jsbn';
export interface KeyPairHex {privateKey: string;publicKey: string;
}export interface KeyPairPoint extends KeyPairHex {k: jsbn.BigInteger;x1: jsbn.BigInteger;
}/*** Cipher Mode* - `0`:C1C2C3* - `1`:C1C3C2*/
export type CipherMode = 0 | 1;export namespace sm2 {// TODO Type of parameter of jsbn.BigInteger constructorfunction generateKeyPairHex(): KeyPairHex;function doEncrypt(msg: string | ArrayLike<number>, publicKey: string, cipherMode?: CipherMode): string;function doDecrypt(encryptData: string, privateKey: string, cipherMode?: CipherMode, outputType?: {output?: "string" | "array";}): string;function doSignature(msg: string | number[], privateKey: string, options?: {pointPool?: KeyPairPoint[] | undefined;der?: boolean | undefined;hash?: boolean | undefined;publicKey?: string | undefined;userId?: string | undefined;}): string;function doVerifySignature(msg: string | number[], signHex: string, publicKey: string, options?: {der?: boolean | undefined;hash?: boolean | undefined;userId?: string | undefined;}): boolean;function getPoint(): KeyPairPoint;
}export function sm3(input: string | ArrayLike<number>, hmac?: {key: HexString | ArrayLike<number>;mode?: "hmac";
}): string;// SM4.encrypt() expects UTF8 strings (such as "hello"), while SM4.decrypt() expects hex strings (such as "8d0a1f").
export type HexString = string;
export type UTF8String = string;export interface SM4ModeBase {padding?: "none" | "pkcs#5" | "pkcs#7";mode?: "cbc";iv?: number[] | HexString;
}export interface SM4Mode_StringOutput extends SM4ModeBase {output: "string";
}export interface SM4Mode_ArrayOutput extends SM4ModeBase {output: "array";
}export namespace sm4 {function encrypt(inArray: number[] | UTF8String,key: number[] | HexString,mode?: SM4ModeBase | SM4Mode_StringOutput,): string;function encrypt(inArray: number[] | UTF8String, key: number[] | HexString, mode: SM4Mode_ArrayOutput): number[];function decrypt(inArray: number[] | HexString,key: number[] | HexString,mode?: SM4ModeBase | SM4Mode_StringOutput,): string;function decrypt(inArray: number[] | HexString, key: number[] | HexString, mode: SM4Mode_ArrayOutput): number[];
}

对应的index.js文件,修改如下,es6的模块引入方式:

//index.js
import * as Sm2 from './sm2/index.js';
import {sm3}  from './sm3/index.js';
import * as Sm4 from './sm4/index.js';export { Sm2 as sm2 };
export { sm3 };
export { Sm4 as sm4 };

注意引入方式的区别,那个sm3为什么单独的{sm3} 呢?其实它导出的函数模块,而其它的Sm2和Sm4只是命名空间。 

sm3.js中的原有的CommonJS模块规范,需要修改,如下:

//sm3.jsimport  {sm3 as Sm3, hmac } from '../sm2/sm3'
......
/*
module.exports = function (input, options) {input = typeof input === 'string' ? utf8ToArray(input) : Array.prototype.slice.call(input)if (options) {const mode = options.mode || 'hmac'if (mode !== 'hmac') throw new Error('invalid mode')let key = options.keyif (!key) throw new Error('invalid key')key = typeof key === 'string' ? hexToArray(key) : Array.prototype.slice.call(key)return ArrayToHex(hmac(input, key))}return ArrayToHex(sm3(input))
}
* */
export function sm3 (input, options) {input = typeof input === 'string' ? utf8ToArray(input) : Array.prototype.slice.call(input)if (options) {const mode = options.mode || 'hmac'if (mode !== 'hmac') throw new Error('invalid mode')let key = options.keyif (!key) throw new Error('invalid key')key = typeof key === 'string' ? hexToArray(key) : Array.prototype.slice.call(key)return ArrayToHex(hmac(input, key))}return ArrayToHex(Sm3(input))
}

jsbn使用举例:

import jsbn from '@yyz116/jsbn'
var BigInteger = jsbn.BigInteger;
var bi = new BigInteger('91823918239182398123');
console.log(bi.bitLength()); // 67

 sm-crypto使用举例:

import {sm2} from '@yyz116/sm-crypto'
const cipherMode = 1 // 1 - C1C3C2,0 - C1C2C3,默认为1let encryptData = sm2.doEncrypt(msgString, publicKey, cipherMode) // 加密结果
let decryptData = sm2.doDecrypt(encryptData, privateKey, cipherMode) // 解密结果encryptData = sm2.doEncrypt(msgArray, publicKey, cipherMode) // 加密结果,输入数组
decryptData = sm2.doDecrypt(encryptData, privateKey, cipherMode, {output: 'array'}) // 解密结果,输出数组// 纯签名 + 生成椭圆曲线点
let sigValueHex = sm2.doSignature(msg, privateKey) // 签名
let verifyResult = sm2.doVerifySignature(msg, sigValueHex, publicKey) // 验签结果// 纯签名
let sigValueHex2 = sm2.doSignature(msg, privateKey, {pointPool: [sm2.getPoint(), sm2.getPoint(), sm2.getPoint(), sm2.getPoint()], // 传入事先已生成好的椭圆曲线点,可加快签名速度
}) // 签名
let verifyResult2 = sm2.doVerifySignature(msg, sigValueHex2, publicKey) // 验签结果// 纯签名 + 生成椭圆曲线点 + der编解码
let sigValueHex3 = sm2.doSignature(msg, privateKey, {der: true,
}) // 签名
let verifyResult3 = sm2.doVerifySignature(msg, sigValueHex3, publicKey, {der: true,
}) // 验签结果// 纯签名 + 生成椭圆曲线点 + sm3杂凑
let sigValueHex4 = sm2.doSignature(msg, privateKey, {hash: true,
}) // 签名
let verifyResult4 = sm2.doVerifySignature(msg, sigValueHex4, publicKey, {hash: true,
}) // 验签结果// 纯签名 + 生成椭圆曲线点 + sm3杂凑(不做公钥推导)
let sigValueHex5 = sm2.doSignature(msg, privateKey, {hash: true,publicKey, // 传入公钥的话,可以去掉sm3杂凑中推导公钥的过程,速度会比纯签名 + 生成椭圆曲线点 + sm3杂凑快
})
let verifyResult5 = sm2.doVerifySignature(msg, sigValueHex5, publicKey, {hash: true,publicKey,
})

其他资源

TS模块化规范与命名空间_ts命名空间不需要导入-CSDN博客

【坚果派】JS开源库适配OpenHarmony系列——第一期实操-电子发烧友网

node之sm-crypto模块,浏览器和 Node.js 环境中SM国密算法库-CSDN博客

sm-crypto: JavaScript对SM2、SM3、SM4的支持。

GitHub - JuneAndGreen/sm-crypto: 国密算法js版

TS模块化规范与命名空间_ts命名空间不需要导入-CSDN博客

GitHub - wechat-miniprogram/sm-crypto: miniprogram sm crypto library

鸿蒙HarmonyOS实战-ArkTS语言(基本语法) - 知乎

arkui_napi: Development framework for extending the JS Native Module | 原生模块扩展开发框架

OpenHarmony三方库中心仓

Codelabs: 分享知识与见解,一起探索HarmonyOS的独特魅力。 - Gitee.com

华为集成开发环境IDE DevEco Device Tool下载 | HarmonyOS设备开发

zh-cn/application-dev/quick-start/typescript-to-arkts-migration-guide.md · OpenHarmony/docs - Gitee.com

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

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

相关文章

【开源】JAVA+Vue.js实现计算机机房作业管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 登录注册模块2.2 课程管理模块2.3 课时管理模块2.4 学生作业模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 课程表3.2.2 课时表3.2.3 学生作业表 四、系统展示五、核心代码5.1 查询课程数据5.2 新增课时5.3 提交作…

React18原理: Fiber架构下的单线程CPU调度策略

概述 React 的 Fiber 架构, 它的整个设计思想就是去参考CPU的调度策略CPU现在都是多核多进程的&#xff0c;重点研究的是 CPU是单核单线程&#xff0c;它是如何调度的?为什么要去研究单线程的CPU&#xff1f; 浏览器中的JS它是单线程的JS 的执行线程和浏览器的渲染GUI 是互斥…

倒计时61天

M-智乃的36倍数(normal version)_2024牛客寒假算法基础集训营3 (nowcoder.com) //非ac代码,超时了,54.17/100#include<bits/stdc.h> using namespace std; const int N1e55; const int inf0x3f3f3f3f; #define int long long int n; string s1[N]; void solve() {cin>…

STM32的ADC电压采集

时间记录&#xff1a;2024/2/9 一、ADC相关知识点 &#xff08;1&#xff09;STM32的ADC时钟不要超过14MHz&#xff0c;不然结果的准确率将下降 &#xff08;2&#xff09;ADC分为规则组和注入组&#xff0c;规则组相当于正常运行的程序&#xff0c;注入组相当于中断可以打断…

随机MM引流源码PHP开源版

引流源码最新随机MM开源版PHP源码&#xff0c;非常简洁好看的单页全解代码没任何加密 直接上传即可用无需数据库支持主机空间

RabbitMQ-4.MQ的可靠性

MQ的可靠性 4.MQ的可靠性4.1.数据持久化4.1.1.交换机持久化4.1.2.队列持久化4.1.3.消息持久化 4.2.LazyQueue4.2.1.控制台配置Lazy模式4.2.2.代码配置Lazy模式4.2.3.更新已有队列为lazy模式 4.MQ的可靠性 消息到达MQ以后&#xff0c;如果MQ不能及时保存&#xff0c;也会导致消…

如何使用websocket

如何使用websocket 之前看到过一个面试题&#xff1a;吃饭点餐的小程序里&#xff0c;同一桌的用户点餐菜单如何做到的实时同步&#xff1f; 答案就是&#xff1a;使用websocket使数据变动时服务端实时推送消息给其他用户。 最近在我们自己的项目中我也遇到了类似问题&#xf…

全功能的屏幕截图工具 - PicPick

全功能的屏幕截图工具 - PicPick 1. PicPick1.1. PicPick 中文1.2. Hot keys References 1. PicPick https://picpick.app/zh/ https://picpick.app/en/ A full-featured screen capture and recording tool, Intuitive image editor, color picker, color palette, pixel-ru…

re:从0开始的CSS学习之路 9. 盒子水平布局

0. 写在前面 过年也不能停止学习&#xff0c;一停下就难以为继&#xff0c;实属不应 1. 盒子的水平宽度 当一个盒子出现在另一个盒子的内容区时&#xff0c;该盒子的水平宽度“必须”等于父元素内容区的宽度 盒子水平宽度&#xff1a; margin-left border-left padding-lef…

使用Qt创建项目 Qt中输出内容到控制台 设置窗口大小和窗口标题 Qt查看说明文档

按windows键&#xff0c;找到Qt Creator &#xff0c;打开 一.创建带模板的项目 新建项目 设置项目路径QMainWindow是带工具栏的窗口。 QWidget是无工具栏的窗口。 QDuakig是对话框窗口。创建好的项目如下&#xff1a; #include "widget.h"// 构造函数&#xff…

Go内存优化与垃圾收集

Go提供了自动化的内存管理机制&#xff0c;但在某些情况下需要更精细的微调从而避免发生OOM错误。本文介绍了如何通过微调GOGC和GOMEMLIMIT在性能和内存效率之间取得平衡&#xff0c;并尽量避免OOM的产生。原文: Memory Optimization and Garbage Collector Management in Go 本…

回归预测 | Matlab实现POA-CNN-LSTM-Attention鹈鹕算法优化卷积长短期记忆网络注意力多变量回归预测(SE注意力机制)

回归预测 | Matlab实现POA-CNN-LSTM-Attention鹈鹕算法优化卷积长短期记忆网络注意力多变量回归预测&#xff08;SE注意力机制&#xff09; 目录 回归预测 | Matlab实现POA-CNN-LSTM-Attention鹈鹕算法优化卷积长短期记忆网络注意力多变量回归预测&#xff08;SE注意力机制&…

在windows的控制台实现贪吃蛇小游戏

欢迎来到博主的文章 博主id&#xff1a;代码小豪 前言&#xff1a;看懂这篇文章需要具有C语言基础&#xff0c;还要对单链表具有一定的理解。如果你只是想要试玩这个游戏&#xff0c;可以直接在文章末尾找到源码 由于实现贪吃蛇需要调用Win32 API函数&#xff0c;这些函数我会…

JVM 性能调优 - Java 虚拟机内存体系(1)

Java 虚拟机我们简称为 JVM&#xff08;Java Virtual Machine&#xff09;。 Java 虚拟机在执行 Java 程序的过程中&#xff0c;会管理几个不同的数据区域。如下图所示&#xff1a; 下面我会介绍这几个数据区的特点。 堆 堆区的几个特点&#xff1a; 线程共享。启动时创建堆…

滑块识别验证

滑块识别 1. 获取图片 测试网站&#xff1a;https://www.geetest.com/adaptive-captcha-demo 2. 点击滑块拼图并开始验证 # 1.打开首页 driver.get(https://www.geetest.com/adaptive-captcha-demo)# 2.点击【滑动拼图验证】 tag WebDriverWait(driver, 30, 0.5).until(la…

Spring Boot 整合 Redis 使用教程

作为开发者&#xff0c;相信大家都知道 Redis 的重要性。Redis 是使用 C 语言开发的一个高性能键值对数据库&#xff0c;是互联网技术领域使用最为广泛的存储中间件&#xff0c;它是「Remote Dictionary Service」的首字母缩写&#xff0c;也就是「远程字典服务」。 Redis 以超…

Mac电脑清空特别大型旧文件如何一键清理?

在我们的数字生活中&#xff0c;Mac电脑常常承载着大量个人资料和重要文件。但当我们决定把自己的Mac送给亲人或朋友使用时&#xff0c;面临的首要任务便是彻底且高效地清空所有个人数据&#xff0c;以保证隐私安全。传统的删除方法虽然简单&#xff0c;但往往不能彻底清除所有…

WebSocket+Http实现功能加成

WebSocketHttp实现功能加成 前言 首先&#xff0c;WebSocket和HTTP是两种不同的协议&#xff0c;它们在设计和用途上有一些显著的区别。以下是它们的主要特点和区别&#xff1a; HTTP (HyperText Transfer Protocol): 请求-响应模型&#xff1a; HTTP 是基于请求-响应模型的协…

VXLAN:虚拟化网络的强大引擎

1.什么是VXLAN VXLAN&#xff08;Virtual eXtensible Local Area Network&#xff0c;虚拟扩展局域网&#xff09;&#xff0c;是由IETF定义的NVO3&#xff08;Network Virtualization over Layer 3&#xff09;标准技术之一&#xff0c;是对传统VLAN协议的一种扩展。VXLAN的特…

嵌入式系统:挑战与机遇并存的领域

嵌入式系统&#xff1a;挑战与机遇并存的领域嵌入式系统是一个既具有挑战性又充满前景的领域。要成为一名合格的嵌入式系统工程师&#xff0c;需要经过大量的学习和实践。然而&#xff0c;进入这个领域时&#xff0c;刚入行可能会面临许多困境。让我们一起探讨一下嵌入式系统工…