news 2026/4/30 14:48:53

幽冥大陆(五十四)V10酒店门锁SDK 鸿蒙(HarmonyOS)——东方仙盟筑基期

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
幽冥大陆(五十四)V10酒店门锁SDK 鸿蒙(HarmonyOS)——东方仙盟筑基期

首先需要明确核心限制:

  1. 原 C# 代码依赖Windows 平台的本地 DLL 文件proRFLV102024.dll)实现硬件交互(读卡、发卡、蜂鸣器),而鸿蒙系统(尤其是鸿蒙设备端)无法直接调用 Windows DLL
  2. 鸿蒙设备端的硬件交互需通过鸿蒙的硬件访问 API(如 USB、外设驱动)厂商提供的鸿蒙版 SDK替代原 DLL 逻辑。

因此转换方案分为两部分:

  1. 保留核心业务逻辑(协议解析、发卡 / 注销逻辑、日志记录),用ArkTS(鸿蒙主流开发语言)实现;
  2. 对于硬件交互部分,提供鸿蒙设备端的硬件访问适配方案(标注需要替换的 DLL 调用逻辑)。

一、鸿蒙开发环境准备

  1. 安装DevEco Studio(鸿蒙官方 IDE);
  2. 创建鸿蒙项目(选择Stage 模型,基于 ArkTS);
  3. 若涉及硬件交互,需配置设备的硬件权限(如 USB 权限、外设访问权限)。

二、ArkTS 转换代码(鸿蒙设备端 / 服务端)

以下代码分为核心业务类鸿蒙 UI / 服务入口,保留原有的入住发卡、退房注销、读卡等核心逻辑,适配鸿蒙的 API 和语法。

1. 工具类:协议解析与日志记录(CyberWinUtil.ets

typescript

运行

/** * 模拟原C#的CyberWinAPPProtocolPackage协议解析类 * 对应鸿蒙的工具类 */ export class Cl_CyberWinAPPProtocolPackage { private data: Record<string, string> = {}; /** * 解析参数字符串(模拟原逻辑,可根据实际协议扩展) * @param param 参数字符串,格式如"hotelsign=123&lockno=456789" */ formatString(param: string): void { // 解析键值对参数(鸿蒙中可使用URLSearchParams简化) const params = new URLSearchParams(param); params.forEach((value, key) => { this.data[key] = value; }); } /** * 获取解析后的参数 * @param key 参数名 * @returns 参数值(空字符串表示无此参数) */ get(key: string): string { return this.data[key] || ''; } } /** * 日志工具类(适配鸿蒙的文件系统API) */ export class LogUtil { /** * 写入日志(对应原C#的write_log方法) * @param capturetype 日志分类 * @param type 日志类型 * @param content 日志内容 */ public static async writeLog(capturetype: string, type: string, content: string): Promise<void> { try { // 鸿蒙中获取应用沙箱路径(需申请文件权限:ohos.permission.WRITE_USER_STORAGE) const context = getContext(this); const logDir = `${context.filesDir}/log/${capturetype}/${new Date().toLocaleDateString('zh-CN').replace(/\//g, '-')}`; // 创建目录(鸿蒙的fileio API) const fileio = require('@ohos.fileio'); if (!fileio.accessSync(logDir)) { fileio.mkdirSync(logDir, { recursive: true }); } // 日志文件路径 const logPath = `${logDir}/${type}_log.log`; // 写入日志(追加模式) const logContent = `==============================\n${new Date().toLocaleString()}<<<<<<<<<<<<<<<<<<<<<<<<<<\n${content}\n\n`; fileio.writeFileSync(logPath, logContent, { flag: 'a', encoding: 'utf-8' }); } catch (e) { console.error(`写入日志失败:${e}`); } } } /** * 酒店标识解析工具类(对应原CyberWin_LocakAPP) */ export class CyberWinLocakAPP { /** * 解析酒店标识(对应原未来之窗_美萍_getsign方法) * @param bufCard 读卡缓冲区数据 * @returns 酒店标识或提示信息 */ public static getHotelSign(bufCard: Uint8Array): string { // 转换为ASCII字符串(对应原Encoding.ASCII.GetString) const cardStr = new TextDecoder('ascii').decode(bufCard); // 检查是否为空白卡 if (this.copy(bufCard, 25, 8) === 'FFFFFFFF') { console.log('此卡是空白卡,请换一张能开门的卡'); return '此卡是空白卡,请换一张能开门的卡'; } // 解析酒店标识(保留原逻辑) const s = this.copy(bufCard, 11, 4); let i = parseInt(s, 16) % 16384; const s2 = this.copy(bufCard, 9, 2); i = i + (parseInt(s, 16) * 65536); const i2 = parseInt(this.copy(bufCard, 9, 2), 16) * 65536 + parseInt(this.copy(bufCard, 11, 4), 16) % 16383; return i2.toString(); } /** * 字符串截取(对应原Copy方法) * @param buffer 数据缓冲区 * @param start 起始位置(从1开始) * @param length 截取长度 * @returns 截取后的字符串 */ private static copy(buffer: Uint8Array, start: number, length: number): string { const cardStr = new TextDecoder('ascii').decode(buffer); start = start < 1 ? 1 : start; return cardStr.substring(start - 1, start - 1 + length); } }

2. 核心业务类:酒店门锁逻辑(HotelDoorLock.ets

typescript

运行

import { Cl_CyberWinAPPProtocolPackage, LogUtil, CyberWinLocakAPP } from './CyberWinUtil'; /** * 酒店门锁核心业务类(对应原C#的APP类) * 鸿蒙中采用单例模式(可选) */ export class HotelDoorLock { private static instance: HotelDoorLock; private cardData: Uint8Array = new Uint8Array(128); // 对应原byte[128] private idPhotoSavePath: string = ''; public static bufCard: Uint8Array = new Uint8Array(128 + 1); // 读卡缓冲区 public static bufCardV10: Uint8Array = new Uint8Array(200 + 1); // V10读卡缓冲区 public static st: number = 0; // 状态码 // 单例模式(鸿蒙中常用) public static getInstance(): HotelDoorLock { if (!this.instance) { this.instance = new HotelDoorLock(); } return this.instance; } // -------------------------- 硬件交互适配(替换原DLL调用) -------------------------- /** * 初始化USB设备(对应原initializeUSB,鸿蒙中需替换为USB API) * @param fUSB 0=有驱USB,1=proUSB * @returns 0=成功,其他=失败 */ private initializeUSB(fUSB: number): number { // 【鸿蒙硬件适配】替换为鸿蒙的USB设备初始化逻辑 // 参考:https://developer.harmonyos.com/cn/docs/documentation/doc-references/usb_device-0000001524415869 // 示例:获取USB设备列表,打开指定设备 try { // 这里模拟返回成功,实际需对接硬件SDK return 0; } catch (e) { return -1; } } /** * 蜂鸣器控制(对应原Buzzer,鸿蒙中需替换为外设API) * @param fUSB USB标识 * @param t 蜂鸣时长(ms) * @returns 0=成功,其他=失败 */ private buzzer(fUSB: number, t: number): number { // 【鸿蒙硬件适配】替换为鸿蒙的蜂鸣器控制逻辑 // 若设备支持GPIO,可通过GPIO API控制蜂鸣器 console.log(`蜂鸣器响${t}ms`); return 0; } /** * 注销卡片(对应原CardErase,鸿蒙中需替换为硬件SDK) * @param fUSB USB标识 * @param hotelSign 酒店标识 * @param cardNo 卡号缓冲区 * @returns 0=成功,其他=失败 */ private cardErase(fUSB: number, hotelSign: number, cardNo: string): number { // 【鸿蒙硬件适配】替换为鸿蒙的卡片注销逻辑(调用硬件SDK) try { // 模拟返回成功 return 0; } catch (e) { return -1; } } /** * 发卡函数(对应原GuestCard_原始,鸿蒙中需替换为硬件SDK) * @param params 发卡参数 * @returns 0=成功,其他=失败 */ private guestCard(params: { fUSB: number, hotelSign: number, cardNo: number, dai: number, lockFlag: number, pdoors: number, openTime: string, closeTime: string, lockNo: string, cardData: string }): number { // 【鸿蒙硬件适配】替换为鸿蒙的发卡逻辑(调用硬件SDK) try { // 模拟返回成功 return 0; } catch (e) { return -1; } } /** * V10读卡(对应原rdCard_v10,鸿蒙中需替换为硬件SDK) * @returns true=成功,false=失败 */ private rdCardV10(): boolean { // 【鸿蒙硬件适配】替换为鸿蒙的读卡逻辑(调用硬件SDK) try { // 模拟读卡成功,写入缓冲区 HotelDoorLock.bufCardV10 = new Uint8Array(201).fill(0x30); // 模拟数据 HotelDoorLock.st = 0; return true; } catch (e) { HotelDoorLock.st = -1; console.error(`读卡失败:${e}`); return false; } } // -------------------------- 原业务方法实现 -------------------------- /** * 启动方法(对应原start) * @param obj 参数集合 * @returns 结果字符串 */ start(obj: Record<string, string>): string { const param1 = obj['param1'] || ''; return '随机预安装插件'; } /** * 设备状态检测(对应原status) * @param obj 参数集合 * @returns 结果字符串 */ status(obj: Record<string, string>): string { this.buzzer(1, 50); // 控制蜂鸣器 return '当你听到设备蜂鸣器,说明设备已经连接'; } /** * 退房注销卡片(对应原checkingout) * @param obj 参数集合 * @returns 结果字符串 */ checkingout(obj: Record<string, string>): string { let result = '注销卡片'; const param = obj['param'] || ''; // 解析协议参数 const clApp = new Cl_CyberWinAPPProtocolPackage(); clApp.formatString(param); const hotelSign = clApp.get('hotelsign'); if (!hotelSign) { return `${result}:酒店标识为空`; } // 初始化USB设备 const usbStatus = this.initializeUSB(1); if (usbStatus !== 0) { console.log('设备打开失败'); return '打开端口失败'; } // 调用注销卡片函数 const cardNo = ''; // 模拟卡号 const st = this.cardErase(1, parseInt(hotelSign), cardNo); if (st !== 0) { result += `:注销失败${st}`; } else { result += ':成功'; } // 写入日志 LogUtil.writeLog('hotel', 'checkout', result); return result; } /** * 入住发卡(对应原checkingin) * @param obj 参数集合 * @returns 结果字符串 */ checkingin(obj: Record<string, string>): string { let result = '酒店入住发卡'; const param = obj['param'] || ''; // 解析协议参数 const clApp = new Cl_CyberWinAPPProtocolPackage(); clApp.formatString(param); const lockNo = clApp.get('lockno'); const hotelSign = clApp.get('hotelsign'); const closeTime = clApp.get('checkingouttime'); // 校验锁号长度 if (lockNo.length < 6) { LogUtil.writeLog('hotel', 'checkin', `锁号长度错误=${lockNo}`); return `${result}:锁号长度错误`; } // 初始化USB设备 const usbStatus = this.initializeUSB(1); if (usbStatus !== 0) { console.log('设备打开失败'); return '打开端口失败'; } // 构造发卡参数 const openTime = new Date().toLocaleString('zh-CN', { year: '2-digit', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', }).replace(/[^\d]/g, ''); // 格式:yyMMddHHmmss const lockFlag = 1; // 反锁标志 const dai = 1; // 房间类型标识 // 调用发卡函数 const st = this.guestCard({ fUSB: 1, hotelSign: parseInt(hotelSign), cardNo: 0, dai: dai, lockFlag: lockFlag, pdoors: 0, openTime: openTime, closeTime: closeTime, lockNo: lockNo, cardData: '' }); if (st !== 0) { result += '调用发卡函数失败'; } else { result += `制卡成功V2024${lockNo}`; } // 写入日志 LogUtil.writeLog('hotel', 'checkin', result); return result; } /** * 读取酒店标识(对应原getsign) * @param obj 参数集合 * @returns 酒店标识或提示信息 */ getsign(obj: Record<string, string>): string { // 读卡 if (!this.rdCardV10()) { LogUtil.writeLog('hotel', 'getsign', '读卡失败'); return '读卡失败'; } // 解析酒店标识 const hotelSign = CyberWinLocakAPP.getHotelSign(HotelDoorLock.bufCardV10); LogUtil.writeLog('hotel', 'getsign', `酒店标识:${hotelSign}`); return hotelSign; } }

3. 鸿蒙 UI 页面:调用示例(Index.ets

typescript

运行

@Entry @Component struct HotelDoorLockPage { private hotelLock = HotelDoorLock.getInstance(); @State result: string = ''; build() { Column() { Text('酒店门锁控制') .fontSize(30) .fontWeight(FontWeight.Bold) .margin({ bottom: 20 }); // 状态检测按钮 Button('检测设备状态') .onClick(() => { this.result = this.hotelLock.status({}); }) .margin({ bottom: 10 }); // 退房注销按钮 Button('退房注销卡片') .onClick(() => { // 模拟参数:hotelsign=123456 this.result = this.hotelLock.checkingout({ param: 'hotelsign=123456' }); }) .margin({ bottom: 10 }); // 入住发卡按钮 Button('入住发卡') .onClick(() => { // 模拟参数:hotelsign=123456&lockno=123456&checkingouttime=2501010000 this.result = this.hotelLock.checkingin({ param: 'hotelsign=123456&lockno=123456&checkingouttime=2501010000' }); }) .margin({ bottom: 10 }); // 读取酒店标识按钮 Button('读取酒店标识') .onClick(() => { this.result = this.hotelLock.getsign({}); }) .margin({ bottom: 10 }); // 结果显示 Text(this.result) .fontSize(16) .margin({ top: 20 }) .textAlign(TextAlign.Center); } .width('100%') .height('100%') .padding(20) .justifyContent(FlexAlign.Center); } }

三、关键代码解释

  1. 硬件交互适配:原 C# 的 DLL 调用逻辑被替换为鸿蒙硬件 API 的适配层,标注了需要对接的鸿蒙 USB / 外设 API(如 USB 设备初始化、蜂鸣器控制),实际使用时需根据硬件厂商提供的鸿蒙 SDK 替换。
  2. 业务逻辑保留:原有的协议解析、参数校验、发卡 / 注销、日志记录等逻辑完全保留,仅适配 ArkTS 的语法和鸿蒙的 API(如fileio写日志、TextDecoder处理字符编码)。
  3. 鸿蒙特性适配:采用鸿蒙的单例模式声明式 UI,结合@Entry@Component装饰器实现 UI 与业务逻辑的分离。

四、鸿蒙硬件交互补充说明

如果需要在鸿蒙设备上实现真实的硬件交互(读卡、发卡),需:

  1. 申请硬件权限:在module.json5中配置 USB、外设等权限(如ohos.permission.USB_DEVICE);
  2. 对接硬件 SDK:联系硬件厂商获取鸿蒙版的门锁 SDK(替代原 Windows DLL);
  3. 使用鸿蒙硬件 API:参考鸿蒙官方文档的USB 设备开发、GPIO 开发等文档。

阿雪技术观


让我们积极投身于技术共享的浪潮中,不仅仅是作为受益者,更要成为贡献者。无论是分享自己的代码、撰写技术博客,还是参与开源项目的维护和改进,每一个小小的举动都可能成为推动技术进步的巨大力量

Embrace open source and sharing, witness the miracle of technological progress, and enjoy the happy times of humanity! Let's actively join the wave of technology sharing. Not only as beneficiaries, but also as contributors. Whether sharing our own code, writing technical blogs, or participating in the maintenance and improvement of open source projects, every small action may become a huge force driving technological progrss

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/26 13:27:54

Open-AutoGLM无代码引擎深度剖析(底层逻辑全公开)

第一章&#xff1a;Open-AutoGLM无代码引擎核心定位Open-AutoGLM 是一款面向AI应用开发的无代码引擎&#xff0c;旨在降低大语言模型&#xff08;LLM&#xff09;集成与自动化流程构建的技术门槛。它通过可视化界面封装复杂的自然语言处理逻辑&#xff0c;使非技术人员也能快速…

作者头像 李华
网站建设 2026/4/30 16:55:29

Langchain-Chatchat与Thanos长期存储监控数据方案

Langchain-Chatchat 与 Thanos&#xff1a;构建安全智能问答与长期可观测性的融合架构 在企业智能化转型的浪潮中&#xff0c;如何在保障数据隐私的前提下实现知识高效利用&#xff0c;同时确保复杂 AI 系统具备长期可维护性&#xff0c;已成为技术落地的关键挑战。尤其是在金融…

作者头像 李华
网站建设 2026/4/23 11:14:55

FaceFusion开源项目设立教育公益计划

FaceFusion开源项目设立教育公益计划 在数字内容创作门槛不断降低的今天&#xff0c;人工智能正以前所未有的速度重塑我们对“视觉真实”的认知。从短视频平台上的虚拟主播&#xff0c;到影视工业中的数字替身&#xff0c;人脸替换技术已不再是实验室里的概念&#xff0c;而是逐…

作者头像 李华
网站建设 2026/4/23 11:15:15

ARM版fnOS内测在即,二手ARM小盒子又要涨价一波了?

前言 前几天一条来自知名开源作者Lean大佬透露&#xff1a;飞牛私有云系统ARM版fnOS即将开启内测&#xff0c;支持芯片覆盖多款百元级设备。 RK3399/RK3528等系列处理器&#xff0c;甚至支持斐讯N1和Radxa瑞莎全家……这就意味着覆盖的范围还是很大的&#xff0c;比如一些跑边…

作者头像 李华
网站建设 2026/4/23 4:57:35

Langchain-Chatchat如何应对模糊查询?模糊匹配算法优化

Langchain-Chatchat如何应对模糊查询&#xff1f;模糊匹配算法优化 在企业知识管理的日常场景中&#xff0c;用户很少会以结构化、精确的方式提问。更常见的情况是&#xff1a;“上次那个项目为啥延期了&#xff1f;”“年初提过的方案后来怎么样了&#xff1f;”——这类问题缺…

作者头像 李华
网站建设 2026/4/28 20:55:48

Langchain-Chatchat如何防止知识滥用?权限分级与审计日志

Langchain-Chatchat如何防止知识滥用&#xff1f;权限分级与审计日志 在企业智能化转型加速的今天&#xff0c;越来越多组织开始部署基于大语言模型&#xff08;LLM&#xff09;的本地知识库问答系统&#xff0c;用于内部知识管理、员工自助服务和智能客服等场景。然而&#xf…

作者头像 李华