HarmonyOS之深入解析NFC的功能和使用
一、简介
- NFC(Near Field Communication,近距离无线通信技术) 是一种非接触式识别和互联技术,让移动设备、消费类电子产品、PC 和智能设备之间可以进行近距离无线通信。
- HarmonyOS 的 NFC 提供的功能有:
- NFC 基础查询:在进行 NFC 功能开发之前,开发者应该先确认设备是否支持 NFC 功能、NFC 是否打开等基本信息。
- 访问安全单元(Secure Element,简称为 SE):SE 可用于保存重要信息,应用可以访问指定 SE,并发送数据到 SE 上。
- 卡模拟:设备可以模拟卡片,替代卡片完成对应操作,如模拟门禁卡、公交卡等。
- NFC 消息通知:通过这个模块,开发者可以获取 NFC 开关状态改变的消息以及 NFC 的场强消息。
二、NFC 基础查询
- 要进行 NFC 功能开发,需要设备支持 NFC 功能。
- 开发者可以通过 NfcController 类的方法 isNfcAvailable() 来确认设备是否支持 NFC 功能。如果设备支持 NFC 功能,可通过 isNfcOpen() 来查询 NFC 的开关状态。
- 示例代码如下:
// 查询本机是否支持NFCif (context != null) {NfcController nfcController = NfcController.getInstance(context);} else {return;}boolean isAvailable = nfcController.isNfcAvailable();if (isAvailable) {// 调用查询NFC是否打开接口,返回值为NFC是否是打开的状态boolean isOpen = nfcController.isNfcOpen();}
三、访问安全单元
① 应用场景
- 安全单元(Secure Element,简称为 SE)可用于保存重要信息,应用或者其他模块可以通过接口完成以下功能:
- 获取安全单元的个数和名称。
- 判断安全单元是否在位。
- 在指定安全单元上打开基础通道。
- 在指定安全单元上打开逻辑通道。
- 发送 APDU(Application Protocol Data Unit)数据到安全单元上。
② API 说明
- NFC 访问安全单元功能的的主要接口:
类名 | 接口名 | 功能描述 |
---|---|---|
SEService | SEService() | 创建一个安全单元服务的实例 |
isConnected() | 查询安全单元服务是否已连接 | |
shutdown() | 关闭安全单元服务 | |
getReaders() | 获取全部安全单元 | |
getVersion() | 获得安全单元服务的版本 | |
OnCallback |
用于回调的内部类,用于定义回调接口。 在服务连接成功后,回调该接口通知应用 |
|
Reader | getName() | 获取安全单元的名称 |
isSecureElementPresent() | 检查安全单元是否在位 | |
openSession() | 打开当前安全单元上的session | |
closeSession() | 关闭当前安全单元上的所有session | |
Session | openBasicChannel(Aid aid) | 打开基础通道 |
openLogicalChannel(Aid aid) | 创建逻辑通道 | |
getATR() | 获得重设安全单元指令的响应 | |
closeSessionChannels() | 关闭当前session的所有通道 | |
Channel | isClosed() | 判断通道是否关闭 |
isBasicChannel() | 判断是否是基础通道 | |
transmit(byte[] command) | 发送指令到安全单元 | |
getSelectResponse() | 获得应用程序选择指令的响应 | |
closeChannel() | 关闭通道 | |
Aid | Aid(byte[] aid, int offset, int length) | 构造一个AID类的实例 |
isAidValid() | 查询AID是否有效 | |
getAidBytes() | 获取AID的字节数组形式的值 |
③ 使用流程
- 调用 SEService 类的构造函数,创建一个安全单元服务的实例,用于访问安全单元。
- 调用 isConnected() 接口,查询安全单元服务的连接状态。
- 调用 getReaders() 接口,获取本机的全部安全单元。
- 调用 Reader 类的 openSession() 接口打开 Session,返回一个打开的 Session 实例。
- 调用 Session 类的 openBasicChannel(Aid aid) 接口打开基础通道,或者调用 openLogicalChannel(Aid aid) 接口打开逻辑通道,返回一个打开通道 Channel 实例。
- 调用 Channel 类的 transmit(byte[] command),发送 APDU 到安全单元。
- 调用 Channel 类的 closeChannel() 接口关闭通道。
- 调用 Session 类的 closeSessionChannels() 接口关闭 Session 的所有通道。
- 调用 Reader 类的 closeSessions() 接口关闭安全单元的所有 Session。
- 调用 SEService 类的 shutdown() 接口关闭安全单元服务。
private static final String ESE = "eSE";private class AppServiceConnectedCallback implements SEService.OnCallback {@Overridepublic void serviceConnected() {// 应用自实现}}// 创建安全单元服务实例SEService sEService = new SEService(context, new AppServiceConnectedCallback());// 查询安全单元服务的连接状态boolean isConnected = sEService.isConnected();// 获取本机的全部安全单元,并获取指定的安全单元eSEReader[] elements = sEService.getReaders();Reader eSe = null;for (int i = 0; i < elements.length; i++) {if (ESE.equals(elements[i].getName())) {eSe = elements[i];break;}}if (eSe == null) {return;}// 查询安全单元是否在位boolean isPresent = eSe.isSecureElementPresent();// 打开SessionOptional<Session> optionalSession = eSe.openSession();Session session = optionalSession.orElse(null);if (session == null) {return;}// 打开通道if (eSe != null) {byte[] aidValue = new byte[]{(byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05};// 创建Aid实例Aid aid = new Aid(aidValue, 0, aidValue.length); // 打开基础通道Optional<Channel> optionalChannel = session.openBasicChannel(aid);Channel basicChannel = optionalChannel.orElse(null);// 打开逻辑通道optionalChannel = session.openLogicalChannel(aid);Channel logicalChannel = optionalChannel.orElse(null);// 发送指令给安全单元,返回值为安全单元对指令的响应byte[] resp = logicalChannel.transmit(new byte[]{(byte)0x00, (byte)0xa4, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x00});// 关闭通道资源if (basicChannel.isPresent()) {basicChannel.closeChannel();}if (logicalChannel.isPresent()) {logicalChannel.closeChannel();}// 关闭Session资源session.close();// 关闭安全单元资源eSe.closeSessions();// 关闭安全单元服务资源sEService.shutdown();
四、卡模拟功能
① 应用场景
- 设备可以模拟卡片,替代卡片完成对应操作,如模拟门禁卡、公交卡等。
- 应用或者其他模块可以通过接口完成以下功能:
- 查询是否支持指定安全单元的卡模拟功能,安全单元包括 HCE(Host Card Emulation)、ESE(Embedded Secure Element)和 SIM(Subscriber Identity Module)卡。
- 打开或关闭指定技术类型的卡模拟,并查询卡模拟状态。
- 获取 NFC 信息,包括当前激活的安全单元、Hisee 上电状态、是否支持RSSI(Received Signal Strength Indication)查询等。
- 根据 NFC 服务的类型获取刷卡时选择服务的方式,包括支付(Payment)类型和非支付(Other)类型。
- 动态设置和注销前台优先应用。
- NFC 应用的 AID(Application Identifier,应用标识)相关操作,包括注册和删除应用的 AID、查询应用是否是指定 AID 的默认应用、获取应用的 AID 等。
- 定义 Host 和 OffHost 服务的抽象类,应用可以通过继承抽象类来实现 NFC 卡模拟功能。
② API 说明
- NFC 卡模拟功能的主要接口说明如下,在使用对应的接口前,需要申请 ohos.permission.NFC_CARD_EMULATION 权限。
- NFC 卡模拟功能的主要接口如下表所示:
类名 | 接口名 | 功能描述 |
---|---|---|
CardEmulation | getInstance(NfcController controller) | 创建一个卡模拟类的实例 |
isSupported(int feature) | 查询是否支持卡模拟功能 | |
setListenMode(int mode) | 设置卡模拟模式 | |
isListenModeEnabled() | 查询卡模拟功能是否打开 | |
getNfcInfo(String key) | 获取NFC的信息 | |
getSelectionType(String category) | 根据NFC服务的类型获取刷卡时选择服务的方式 | |
registerForegroundPreferred(Ability appAbility, ElementName appName) | 动态设置前台优先应用 | |
unregisterForegroundPreferred(Ability appAbility) | 取消设置前台优先应用 | |
isDefaultForAid(ElementName appName, String aid) | 判断应用是否是指定AID的默认处理应用 | |
registerAids(ElementName appName, String type, List aids) | 给应用注册指定类型的AID | |
removeAids(ElementName appName, String type) | 删除应用的指定类型的AID | |
getAids(ElementName appName, String type) | 获取应用中指定类型的AID列表 | |
HostService | sendResponse(byte[] response) | 发送响应的数据到对端设备 |
handleRemoteCommand(byte[] cmd, IntentParams params) | 处理对端设备发送的命令 | |
disabledCallback(int errCode) | 连接异常的回调 |
③ 查询是否支持卡模拟功能
- 调用 NfcController 类的 getInstance(Context context) 接口,获取 NfcController 实例。
- 调用 CardEmulation 类的 getInstance(NfcController controller) 接口,获取 CardEmulation 实例,去管理本机卡模拟模块操作。
- 调用 isSupported(int feature) 接口去查询是否支持 HCE、UICC、ESE 卡模拟。
// 获取NFC控制对象NfcController nfcController = NfcController.getInstance(context);// 获取卡模拟控制对象CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);// 查询是否支持HCE、UICC、ESE卡模拟,返回值表示是否支持对应安全单元的卡模拟boolean isSupportedHce = cardEmulation.isSupported(CardEmulation.FEATURE_HCE);boolean isSupportedUicc = cardEmulation.isSupported(CardEmulation.FEATURE_UICC);boolean isSupportedEse = cardEmulation.isSupported(CardEmulation.FEATURE_ESE);
④ 开关卡模拟及查询卡模拟状态
- 调用 NfcController 类的 getInstance(Context context) 接口,获取 NfcController 实例。
- 调用 CardEmulation 类的 getInstance(NfcController controller) 接口,获取 CardEmulation 实例,去管理本机卡模拟模块操作。
- 调用 setListenMode(int mode) 接口去打开或者关闭卡模拟。
- 调用 isListenModeEnabled() 接口去查询卡模拟是否打开。
// 获取NFC控制对象NfcController nfcController = NfcController.getInstance(context);// 获取卡模拟控制对象CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);// 打开卡模拟cardEmulation.setListenMode(CardEmulation.ENABLE_MODE_ALL);// 调用查询卡模拟开关状态的接口,返回值为卡模拟是否是打开的状态boolean isEnabled = cardEmulation.isListenModeEnabled(); // 关闭卡模拟cardEmulation.setListenMode(CardEmulation.DISABLE_MODE_A_B);// 调用查询卡模拟开关状态的接口,返回值为卡模拟是否是打开的状态isEnabled = cardEmulation.isListenModeEnabled();
⑤ 获取 NFC 信息
- 调用 NfcController 类的 getInstance(Context context) 接口,获取 NfcController 实例。
- 调用 CardEmulation 类的 getInstance(NfcController controller) 接口,获取 CardEmulation 实例,去管理本机卡模拟模块操作。
- 调用 getNfcInfo(String key) 接口去获取 NFC 信息。
// 获取NFC控制对象NfcController nfcController = NfcController.getInstance(context);// 获取卡模拟控制对象CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);// 查询本机当前使能的安全单元类型String seType = cardEmulation.getNfcInfo(CardEmulation.KEY_ENABLED_SE_TYPE); // ENABLED_SE_TYPE_ESE// 查询Hisee上电状态String hiseeState = cardEmulation.getNfcInfo(CardEmulation.KEY_HISEE_READY);// 查询是否支持RSSI的查询String rssiAbility = cardEmulation.getNfcInfo(CardEmulation.KEY_RSSI_SUPPORTED);
⑥ 根据 NFC 服务的类型获取刷卡时选择服务的方式
- 调用 NfcController 类的 getInstance(Context context) 接口,获取 NfcController 实例。
- 调用 CardEmulation 类的 getInstance(NfcController controller) 接口,获取 CardEmulation 实例,去管理本机卡模拟模块操作。
- 调用 getSelectionType(Sring category) 接口去获取选择服务的方式。
// 获取NFC控制对象NfcController nfcController = NfcController.getInstance(context);// 获取卡模拟控制对象CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);// 获取选择服务的方式int result = cardEmulation.getSelectionType(CardEmulation.CATEGORY_PAYMENT); // SELECTION_TYPE_PREFER_DEFAULTresult = cardEmulation.getSelectionType(CardEmulation.CATEGORY_OTHER); // SELECTION_TYPE_ASK_IF_CONFLICT
⑦ 动态设置和注销前台优先应用
- 调用 NfcController 类的 getInstance(Context context) 接口,获取 NfcController 实例。
- 调用 CardEmulation 类的 getInstance(NfcController controller) 接口,获取 CardEmulation 实例,去管理本机卡模拟模块操作。
- 调用 registerForegroundPreferred(Ability appAbility, ElementName appName) 接口去动态设置前台优先应用。
- 调用 unregisterForegroundPreferred(Ability appAbility) 接口去取消设置前台优先应用。
// 获取NFC控制对象NfcController nfcController = NfcController.getInstance(context);// 获取卡模拟控制对象CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);// 动态设置前台优先应用Ability ability = new Ability();cardEmulation.registerForegroundPreferred(ability, new ElementName());// 注销前台优先应用cardEmulation.unregisterForegroundPreferred(ability);
⑧
五、NFC 消息通知
① 应用场景
- NFC 消息通知是 HarmonyOS 内部或者与应用之间跨进程通讯的机制,注册者在注册消息通知后,一旦符合条件的消息被发出,注册者即可接收到该消息。
② API 说明
- NFC 消息通知的相关广播介绍:
描述 | 通知名 | 附加参数 |
---|---|---|
NFC状态 | usual.event.nfc.action.ADAPTER_STATE_CHANGED | extra_nfc_state |
进场消息 | usual.event.nfc.action.RF_FIELD_ON_DETECTED | extra_nfc_transaction |
离场消息 | usual.event.nfc.action.RF_FIELD_OFF_DETECTED | - |
③ 注册并获取 NFC 状态改变消息
- 构建消息通知接收者 NfcStateEventSubscriber。
- 注册 NFC 状态改变消息。
- NfcStateEventSubscriber 接收并处理 NFC 状态改变消息。
// 构建消息接收者/注册者class NfcStateEventSubscriber extends CommonEventSubscriber {NfcStateEventSubscriber (CommonEventSubscribeInfo info) {super(info);}@Overridepublic void onReceiveEvent(CommonEventData commonEventData) {if (commonEventData == null || commonEventData.getIntent() == null) {return;}if (NfcController.STATE_CHANGED.equals(commonEventData.getIntent().getAction())) {IntentParams params = commonEventData.getIntent().getParams();int currState = commonEventData.getIntent().getIntParam(NfcController.EXTRA_NFC_STATE, NfcController.STATE_OFF);}}}// 注册消息MatchingSkills matchingSkills = new MatchingSkills();// 增加获取NFC状态改变消息matchingSkills.addEvent(NfcController.STATE_CHANGED);matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_NFC_ACTION_ADAPTER_STATE_CHANGED);CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);NfcStateEventSubscriber subscriber = new NfcStateEventSubscriber(subscribeInfo);try {CommonEventManager.subscribeCommonEvent(subscriber);} catch (RemoteException e) {HiLog.error(TAG, "doSubscribe occur exception: %{public}s" ,e.toString());}
④ 注册并获取 NFC 场强消息
- 构建消息通知接收者 NfcFieldOnAndOffEventSubscriber。
- 注册 NFC 场强消息。
- NfcFieldOnAndOffEventSubscriber 接收并处理 NFC 场强消息。
// 构建消息接收者/注册者class NfcFieldOnAndOffEventSubscriber extends CommonEventSubscriber {NfcFieldOnAndOffEventSubscriber (CommonEventSubscribeInfo info) {super(info);}@Overridepublic void onReceiveEvent(CommonEventData commonEventData) {if (commonEventData == null || commonEventData.getIntent() == null) {return;}if (NfcController.FIELD_ON_DETECTED.equals(commonEventData.getIntent().getAction())) {IntentParams params = commonEventData.getIntent().getParams();if (params == null) {HiLog.info(TAG, "Pure FIELD_ON_DETECTED");} else {HiLog.info(TAG, "Transaction FIELD_ON_DETECTED"); Intent transactionIntent = (Intent) params.getParam("transactionIntent");}} else if (NfcController.FIELD_OFF_DETECTED.equals(commonEventData.getIntent().getAction())) {HiLog.info(TAG, "FIELD_OFF_DETECTED");}HiLog.info(TAG, "NfcFieldOnAndOffEventSubscriber onReceiveEvent: %{public}s", commonEventData.getIntent().getAction());}}// 注册消息MatchingSkills matchingSkills = new MatchingSkills();// 增加获取NFC状态改变消息matchingSkills.addEvent(NfcController.FIELD_ON_DETECTED);matchingSkills.addEvent(NfcController.FIELD_OFF_DETECTED);CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);HiLog.info(TAG, "subscribeInfo permission: %{public}s", subscribeInfo.getPermission());NfcFieldOnAndOffEventSubscriber subscriber = new NfcFieldOnAndOffEventSubscriber(subscribeInfo);try {CommonEventManager.subscribeCommonEvent(subscriber);} catch (RemoteException e) {HiLog.error(TAG, "doSubscribe occur exception: %{public}s", e.toString());}
HarmonyOS之深入解析NFC的功能和使用相关推荐
- HarmonyOS之深入解析视频的功能和使用
一.基本概念 HarmonyOS 视频模块支持视频业务的开发和生态开放,开发者可以通过已开放的接口很容易地实现视频媒体的播放.操作和新功能开发. 视频媒体的常见操作有视频编解码.视频合成.视频提取.视 ...
- HarmonyOS之深入解析Ability的功能和使用
一.Ability 概述 Ability 是应用所具备能力的抽象,也是应用程序的重要组成部分.一个应用可以具备多种能力(即可以包含多个 Ability),HarmonyOS 支持应用以 Ability ...
- HarmonyOS之深入解析WLAN的功能和使用
一.WLAN 简介 无线局域网(Wireless Local Area Networks,WLAN),是通过无线电.红外光信号或者其他技术发送和接收数据的局域网,用户可以通过 WLAN 实现结点之间无 ...
- HarmonyOS之深入解析相机的功能和使用
一.简介 ① 概念 HarmonyOS 相机模块支持相机业务的开发,开发者可以通过已开放的接口实现相机硬件的访问.操作和新功能开发,最常见的操作如:预览.拍照.连拍和录像等. 相机静态能力:用于描述相 ...
- 完爆Facebook/GraphQL,APIJSON全方位对比解析(一)-基础功能
相关阅读: 完爆Facebook/GraphQL,APIJSON全方位对比解析(二)-权限控制 完爆Facebook/GraphQL,APIJSON全方位对比解析(三)-表关联查询 自APIJSON发 ...
- HarmonyOS之常用组件RoundProgressBar的功能和使用
RoundProgressBar 继承自 ProgressBar,拥有 ProgressBar 的属性,在设置同样的属性时用法和 ProgressBar 一致,用于显示环形进度. RoundProgr ...
- java在线打开xml文件_java实现简单解析XML文件功能示例
本文实例讲述了java实现简单解析XML文件功能.分享给大家供大家参考,具体如下: package demo; import java.io.File; import java.io.IOExcept ...
- html调用手机NFC,如何使用手机上NFC的功能
如何使用手机上NFC的功能 现如今,便捷的移动支付变得越来越常见了.那么如何使用手机上NFC的功能呢?下面就让jy135小编来告诉大家吧,欢迎阅读. 1.先来介绍一下什么是NFC:NFC全称Near ...
- android中NFC读写功能的实现方法
这篇文章主要为大家详细介绍了android中NFC读写功能的实现方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 本文实例为大家分享了android中NFC读写功能的 ...
最新文章
- 使用Azure Blob存储托管Maven工件
- [css] 你对响应式设计的理解是什么?知道它基本的原理是吗?要想兼容低版本的IE怎么做呢?
- 教育部推出首批490门“国家精品在线开放课程”
- 前端程序员有前途吗?
- Ajax用户名验证、服务条款加载、验证码生成
- Android4.4点击无响应,webview某些超链接点击无响应的问题
- 從零開始學 ReactJS:最完整的 React 生態系入門教程
- vue项目中通过图片url下载图片
- 如何运用时间管理四象限法则去管理时间?
- 解决Win系统cad激活安装失败问题,AutoCad 2022 中文/英文正式详细安装教程
- 虚拟机没有USB网卡选项怎么解决
- Educational Codeforces Round 121 (Rated for Div. 2) unr场 A B C
- 高德地图API实现天气查询
- 什么触控笔好用又便宜?口碑超好的触控笔推荐
- 浅析copy和deepcopy
- sobel算子原理与实践
- java小游戏-java小游戏-飞机大战
- 利用计算机Tracert,必备的网络常用测试命令(tracert命令) -电脑资料
- 爱奇艺携手HMS Core,为用户打造更流畅的沉浸式观影体验
- 尚硅谷商城购物系统 安卓App