利用NFC增强用户体验:HarmonyOS Next的NFC应用指南

本文旨在深入探讨华为鸿蒙HarmonyOS Next系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。

在智能设备的交互领域,NFC(Near Field Communication,近场通信)技术以其便捷、快速的特点,为用户带来了诸多便利。HarmonyOS Next中的NFC模块更是将这种便利发挥到了极致,涵盖了从标签读写到卡模拟等丰富功能,为开发者提供了广阔的创新空间。今天,我们就深入探究HarmonyOS Next中NFC模块的奇妙世界,看看如何利用它为用户打造更加智能、高效的体验。

一、NFC模块功能概述

HarmonyOS Next的NFC模块主要提供了以下几个方面的功能:

1. NFC标签读写

设备可以通过NFC通信技术与NFC标签进行交互,读取标签中存储的数据,或者向标签写入新的数据。这一功能在很多场景中都有广泛应用,比如在智能公交卡充值、图书馆书籍借阅管理、商品信息查询等方面,用户只需将设备靠近NFC标签,就能轻松完成相应操作。

2. NFC卡模拟(HCE)

应用程序可以模拟NFC卡片,与NFC读卡器进行通信,实现NFC刷卡业务。这使得电子设备能够替代传统的实体卡片,如银行卡、门禁卡等,为用户提供更加便捷的支付和门禁通行方式。例如,用户在乘坐地铁时,无需拿出实体交通卡,只需使用手机模拟的交通卡靠近闸机读卡器,即可完成刷卡进站。

二、NFC标签读写详解

1. 技术类型与应用场景

NFC标签可能支持多种通信技术,不同技术类型适用于不同的应用场景。

NFC技术类型 应用场景
NfcA(ISO 14443 - 3A) 广泛应用于门禁卡、公交卡等场景,如常见的城市公交一卡通系统。
NfcB(ISO 14443 - 3B) 在一些特定的门禁系统或会员卡系统中使用。
NfcF(JIS 6319 - 4) 主要在日本等地区用于电子钱包、交通卡等应用。
NfcV(ISO 15693) 常用于物流管理、图书管理等领域,实现物品的快速识别和信息读取。
IsoDep 支持与符合ISO 7816标准的智能卡进行通信,可用于电子护照、银行卡等安全要求较高的应用。
NDEF 用于存储和交换格式化的数据,如文本、URL等,在信息共享和传输方面有广泛应用,例如分享联系人信息、Wi-Fi密码等。
MifareClassic 常用于门禁控制、会员卡等场景,具有较高的安全性和稳定性。
MifareUltralight 适用于简单的数据存储和识别应用,如活动门票、优惠券等。

2. 前台标签读取实现

前台标签读取是指用户在触碰NFC标签之前,先打开特定的应用程序,明确使用该应用与NFC标签进行读写操作。以下是实现前台标签读取的关键步骤和API调用示例:

首先,在module.json5文件中声明NFC标签读取的权限以及相关action:

{
  "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",
            "ohos.nfc.tag.action.TAG_FOUND"
          ]
        }
      ]
    }
  ],
  "requestPermissions": [
    {
      "name": "ohos.permission.NFC_TAG",
      "reason": "$string:app_name"
    }
  ]
}

然后,在应用代码中进行以下操作:

import { tag } from '@kit.ConnectivityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

// 判断设备是否支持NFC能力
if (!canIUse("SystemCapability.Communication.NFC.Core")) {
    hilog.error(0x0000, 'testTag', 'nfc unavailable.');
    return;
}

// 调⽤tag模块中前台优先的接⼝,使能前台应⽤程序优先处理所发现的NFC标签功能
tag.enableForegroundDispatch((result) => {
    if (result === 0) {
        hilog.info(0x0000, 'testTag', 'enableForegroundDispatch success');
    } else {
        hilog.error(0x0000, 'testTag', 'enableForegroundDispatch failed with error code:'+ result);
    }
});

// 获取特定技术类型的NFC标签对象(以NfcA为例)
tag.getNfcA(tagInfo).then((nfcATag) => {
    // 执行读写接口完成标签数据的读取或写入数据到标签
    // 例如,读取标签数据
    nfcATag.read().then((data) => {
        hilog.info(0x0000, 'testTag', 'Read data from NFC tag:'+ JSON.stringify(data));
    }).catch((err) => {
        hilog.error(0x0000, 'testTag', 'Error reading NFC tag:'+ JSON.stringify(err));
    });
}).catch((err) => {
    hilog.error(0x0000, 'testTag', 'Error getting NfcA tag object:'+ JSON.stringify(err));
});

// 退出应⽤程序NFC标签页面时,调⽤tag模块退出前台优先功能
tag.disableForegroundDispatch((result) => {
    if (result === 0) {
        hilog.info(0x0000, 'testTag', 'disableForegroundDispatch success');
    } else {
        hilog.error(0x0000, 'testTag', 'disableForegroundDispatch failed with error code:'+ result);
    }
});

3. 后台标签识别实现

后台标签识别是指设备在未打开特定NFC标签应用程序的情况下,触碰发现NFC标签后,根据标签的技术类型,分发给能够处理的应用程序。如果匹配到多个应用程序,则弹出应用选择器让用户手动选择。

module.json5文件中声明NFC标签读取的权限、相关action以及应用能够处理的AID(应用程序标识符):

{
  "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",
            "ohos.nfc.tag.action.TAG_FOUND"
          ]
        ]
      },
      "metadata": [
        {
          "name": "payment-aid",
          "value": "A0000000031010"
        },
        {
          "name": "other-aid",
          "value": "A0000000031011"
        }
      ]
    }
  ],
  "requestPermissions": [
    {
      "name": "ohos.permission.NFC_TAG",
      "reason": "$string:app_name"
    }
  ]
}

在应用代码中,主要是订阅标签发现事件,当检测到符合条件的标签时,进行相应处理:

import { tag } from '@kit.ConnectivityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

// 判断设备是否支持NFC能力
if (!canIUse("SystemCapability.Communication.NFC.Core")) {
    hilog.error(0x0000, 'testTag', 'nfc unavailable.');
    return;
}

// 订阅标签发现事件
tag.on('tagFound', (tagInfo) => {
    hilog.info(0x0000, 'testTag', 'NFC tag found:'+ JSON.stringify(tagInfo));
    // 根据标签信息进行处理,例如获取标签类型并根据业务逻辑进行相应操作
    const techList = tagInfo.techList;
    if (techList.includes('NfcA')) {
        // 处理NfcA类型标签
        handleNfcATag(tagInfo);
    } else if (techList.includes('NfcB')) {
        // 处理NfcB类型标签
        handleNfcBTag(tagInfo);
    }
});

三、NFC卡模拟(HCE)实现

1. HCE应用场景

HCE在很多场景中都具有重要应用价值。例如,在移动支付领域,用户可以将银行卡信息模拟到手机中,在支持NFC支付的终端上进行刷卡消费,无需携带实体银行卡;在门禁系统中,手机模拟门禁卡,方便用户进出办公场所或住宅小区。

2. HCE卡模拟实现示例

以下是一个简单的HCE卡模拟的基本代码示例,包括前台刷卡和后台刷卡的部分实现。

前台刷卡:

module.json5文件中声明NFC卡模拟权限和HCE特定的action:

{
  "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",
            "ohos.nfc.cardemulation.action.HOST_APDU_SERVICE"
          ]
        ]
      },
      "metadata": []
    }
  ],
  "requestPermissions": [
    {
      "name": "ohos.permission.NFC_CARD_EMULATION",
      "reason": "$string:app_name"
    }
  ]
}

在应用代码中:

import { cardEmulation } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { AsyncCallback } from '@kit.BasicServicesKit';
import { AbilityConstant, UIAbility, Want, bundleManager } from '@kit.AbilityKit';

let hceElementName: bundleManager.ElementName;
let hceService: cardEmulation.HceService;

const hceCommandCb: AsyncCallback<number[]> = (error: BusinessError, hceCommand: number[]) => {
    if (!error) {
        if (hceCommand == null || hceCommand == undefined) {
            hilog.error(0x0000, 'testTag', 'hceCommandCb has invalid hceCommand.');
            return;
        }
        // 根据接收到的命令进行处理,然后发送响应
        let responseData = [0x90, 0x00]; // 根据不同命令修改响应数据
        hceService.transmit(responseData).then(() => {
            hilog.info(0x0000, 'testTag', 'hceService transmit Promise success.');
        }).catch((err: BusinessError) => {
            hilog.error(0x0000, 'testTag', 'hceService transmit Promise error ='+ JSON.stringify(err));
        });
    } else {
        hilog.error(0x0000, 'testTag', 'hceCommandCb error'+ JSON.stringify(error));
    }
};

export default class EntryAbility extends UIAbility {
    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
        // 判断设备是否支持NFC能力和HCE能力
        if (!canIUse("SystemCapability.Communication.NFC.Core")) {
            hilog.error(0x0000, 'testTag', 'nfc unavailable.');
            return;
        }
        if (!cardEmulation.hasHceCapability()) {
            hilog.error(0x0000, 'testTag', 'hce unavailable.');
            return;
        }
        hceElementName = {
            bundleName: want.bundleName?? '',
            abilityName: want.abilityName?? '',
            moduleName: want.moduleName
        };
        hceService = new cardEmulation.HceService();
    }

    onForeground() {
        // 使能前台HCE应用程序优先处理NFC刷卡功能
        let aidList = ["A0000000031010", "A0000000031011"]; // 根据实际情况修改AID
        hceService.start(hceElementName, aidList);
        // 订阅HCE APDU数据的接收
        hceService.on('hceCmd', hceCommandCb);
    }

    onBackground() {
        // 退出应用程序NFC标签页面时,退出前台优先功能
        hceService.stop(hceElementName);
    }
}

后台刷卡:

module.json5文件中声明NFC卡模拟权限、HCE特定的action以及应用能够处理的AID:

{
  "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",
            "ohos.nfc.cardemulation.action.HOST_APDU_SERVICE"
          ]
        ]
      },
      "metadata": [
        {
          "name": "payment-aid",
          "value": "A0000000031010"
        },
        {
          "name": "other-aid",
          "value": "A0000000031011"
        }
      ]
    }
  ],
  "requestPermissions": [
    {
      "name": "ohos.permission.NFC_CARD_EMULATION",
      "reason": "$string:app_name"
    }
  ]
}

在应用代码中:

import { cardEmulation } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { AsyncCallback } from '@kit.BasicServicesKit';
import { AbilityConstant, UIAbility, Want, bundleManager } from '@kit.AbilityKit';

let hceElementName: bundleManager.ElementName;
let hceService: cardEmulation.HceService;

const hceCommandCb: AsyncCallback<number[]> = (error: BusinessError, hceCommand: number[]) => {
    if (!error) {
        if (hceCommand == null || hceCommand == undefined) {
            hilog.error(0x0000, 'testTag', 'hceCommandCb has invalid hceCommand.');
            return;
        }
        // 根据接收到的命令进行处理,然后发送响应
        let responseData = [0x90, 0x00]; // 根据不同命令修改响应数据
        hceService.transmit(responseData).then(() => {
            hilog.info(0x0000, 'testTag', 'hceService transmit Promise success.');
        }).catch((err: BusinessError) => {
            hilog.error(0x0000, 'testTag', 'hceService transmit Promise error ='+ JSON.stringify(err));
        });
    } else {
        hilog.error(0x0000, 'testTag', 'hceCommandCb error'+ JSON.stringify(error));
    }
};

export default class EntryAbility extends UIAbility {
    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
        // 判断设备是否支持NFC能力和HCE能力
        if (!canIUse("SystemCapability.Communication.NFC.Core")) {
            hilog.error(0x0000, 'testTag', 'nfc unavailable.');
            return;
        }
        if (!cardEmulation.hasHceCapability()) {
            hilog.error(0x0000, 'testTag', 'hce unavailable.');
            return;
        }
        hceElementName = {
            bundleName: want.bundleName?? '',
            abilityName: want.abilityName?? '',
            moduleName: want.moduleName
        };
        hceService = new cardEmulation.HceService();
        hceService.on('hceCmd', hceCommandCb);
    }

    onForeground() {
        // 前台模式下,可进行一些界面提示或准备工作
        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
    }

    onDestroy() {
        // 退出应用程序时,取消订阅
        if (hceElementName!= undefined) {
            try {
                hceService.stop(hceElementName);
            } catch (error) {
                hilog.error(0x0000, 'testTag', 'hceService.stop error ='+ JSON.stringify(error));
            }
        }
    }
}

通过以上对HarmonyOS Next中NFC模块的标签读写和卡模拟功能的详细介绍,我们可以看到NFC技术为智能设备带来了丰富的交互方式和便捷的应用体验。无论是在便捷支付、门禁管理还是信息交互等方面,NFC都有着巨大的潜力等待开发者去挖掘。就像一把神奇的钥匙,开启了智能设备之间近场通信的新大门,让设备之间的交互变得更加自然和流畅。嘿,想象一下,以后出门只带手机,就能轻松搞定各种事情,是不是感觉生活变得更加美好了呢?哈哈!希望这篇文章能够帮助开发者们更好地理解和运用HarmonyOS Next中的NFC技术,创造出更多有趣、实用的应用程序。

posted @ 2024-11-13 09:45  SameX  阅读(8)  评论(0编辑  收藏  举报