首先需要明确核心限制:

  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

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐