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

367 阅读8分钟

本文旨在深入探讨华为鸿蒙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技术,创造出更多有趣、实用的应用程序。