HarmonyOS学习路之开发篇—网络与连接(NFC开发 二)

news/2024/7/21 9:42:33 标签: harmonyos, 学习, 华为, java, NFC, 网络与连接

卡模拟功能

场景介绍

设备可以模拟卡片,替代卡片完成对应操作,如模拟门禁卡、公交卡等。应用或者其他模块可以通过接口完成以下功能:

  1. 查询是否支持指定安全单元的卡模拟功能,安全单元包括HCE(Host Card Emulation)、ESE(Embedded Secure Element)和SIM(Subscriber Identity Module)卡。
  2. 打开或关闭指定技术类型的卡模拟,并查询卡模拟状态。
  3. 获取NFC信息,包括当前激活的安全单元、Hisee上电状态、是否支持RSSI(Received Signal Strength Indication)查询等。
  4. 根据NFC服务的类型获取刷卡时选择服务的方式,包括支付(Payment)类型和非支付(Other)类型。
  5. 动态设置和注销前台优先应用。
  6. NFC应用的AID(Application Identifier,应用标识)相关操作,包括注册和删除应用的AID、查询应用是否是指定AID的默认应用、获取应用的AID等。
  7. 定义Host和OffHost服务的抽象类,应用可以通过继承抽象类来实现NFC卡模拟功能。

接口说明

NFC卡模拟功能的主要接口说明如下,在使用对应的接口前,需要申请ohos.permission.NFC_CARD_EMULATION权限。

表1 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<String> 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)

连接异常的回调。

查询是否支持卡模拟功能

  1. 调用NfcController类的getInstance(Context context)接口,获取NfcController实例。
  2. 调用CardEmulation类的getInstance(NfcController controller)接口,获取CardEmulation实例,去管理本机卡模拟模块操作。
  3. 调用isSupported(int feature)接口去查询是否支持HCE、UICC、ESE卡模拟。
java">// 获取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);

开关卡模拟及查询卡模拟状态

  1. 调用NfcController类的getInstance(Context context)接口,获取NfcController实例。
  2. 调用CardEmulation类的getInstance(NfcController controller)接口,获取CardEmulation实例,去管理本机卡模拟模块操作。
  3. 调用setListenMode(int mode)接口去打开或者关闭卡模拟。
  4. 调用isListenModeEnabled()接口去查询卡模拟是否打开。
java">// 获取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信息

  1. 调用NfcController类的getInstance(Context context)接口,获取NfcController实例。
  2. 调用CardEmulation类的getInstance(NfcController controller)接口,获取CardEmulation实例,去管理本机卡模拟模块操作。
  3. 调用getNfcInfo(String key)接口去获取NFC信息。
java">// 获取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服务的类型获取刷卡时选择服务的方式

  1. 调用NfcController类的getInstance(Context context)接口,获取NfcController实例。
  2. 调用CardEmulation类的getInstance(NfcController controller)接口,获取CardEmulation实例,去管理本机卡模拟模块操作。
  3. 调用getSelectionType(Sring category)接口去获取选择服务的方式。
java">// 获取NFC控制对象
NfcController nfcController = NfcController.getInstance(context);
// 获取卡模拟控制对象
CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);
// 获取选择服务的方式
int result = cardEmulation.getSelectionType(CardEmulation.CATEGORY_PAYMENT); // SELECTION_TYPE_PREFER_DEFAULT
result = cardEmulation.getSelectionType(CardEmulation.CATEGORY_OTHER); // SELECTION_TYPE_ASK_IF_CONFLICT

动态设置和注销前台优先应用

  1. 调用NfcController类的getInstance(Context context)接口,获取NfcController实例。
  2. 调用CardEmulation类的getInstance(NfcController controller)接口,获取CardEmulation实例,去管理本机卡模拟模块操作。
  3. 调用registerForegroundPreferred(Ability appAbility, ElementName appName)接口去动态设置前台优先应用。
  4. 调用unregisterForegroundPreferred(Ability appAbility)接口去取消设置前台优先应用。
java">// 获取NFC控制对象
NfcController nfcController = NfcController.getInstance(context);
// 获取卡模拟控制对象
CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);
// 动态设置前台优先应用
Ability ability = new Ability();
cardEmulation.registerForegroundPreferred(ability, new ElementName());
// 注销前台优先应用
cardEmulation.unregisterForegroundPreferred(ability);

NFC应用的AID相关操作

静态注册AID

  1. 在配置文件config.json注册HCE服务,具体可参考Ability。
  2. 在配置文件的module中,添加metaData对象,并配置customizeData。
    • 使用paymentAid字段静态注册支付类型的AID,多个支付类型的AID使用‘|’符号隔开。
    • 使用otherAid字段静态注册其他类型的AID,多个其他类型的AID使用‘|’符号隔开。

    示例代码如下:

"metaData": {
  "customizeData": [
    {
      "name": "paymentAid",
      "value": "325041592E5359532E4444463031"    
    },
    {
      "name": "otherAid",
      "value": "0123456789|535558494E2E4D46|1234567890"
     }  
  ]
}

动态注册AID

  1. 调用NfcController类的getInstance(Context context)接口,获取NfcController实例。
  2. 调用CardEmulation类的getInstance(NfcController controller)接口,获取CardEmulation实例,去管理本机卡模拟模块操作。
  3. 调用registerAids(ElementName appName, String type, List<String> aids)接口去给应用注册指定类型的AID。
  4. 调用removeAids(ElementName appName, String type)接口去删除应用的指定类型的AID。
java">// 获取NFC控制对象
NfcController nfcController = NfcController.getInstance(context);
// 获取卡模拟控制对象
CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);
// 给应用注册指定类型的AID
List<String> aids = new ArrayList<String>();
aids.add(0, "A0028321901280");
aids.add(1, "A0028321901281");
Element element = new ElementName();
try {
    cardEmulation.registerAids(element, CardEmulation.CATEGORY_PAYMENT, aids);
} catch (IllegalArgumentException e) {
    HiLog.error(TAG, "IllegalArgumentException when registerAids");
}
// 删除应用的指定类型的AID
cardEmulation.removeAids(element, CardEmulation.CATEGORY_PAYMENT);
cardEmulation.removeAids(element, CardEmulation.CATEGORY_OTHER);

AID查询

调用isDefaultForAid(ElementName appName, String aid)接口,可判断应用是否是指定AID的默认处理应用:

java">// 判断应用是否是指定AID的默认处理应用
String aid = "A0028321901280";
cardEmulation.isDefaultForAid(element, aid);

调用getAids(ElementName appName, String type)接口去获取应用中指定类型的AID列表:

java">// 获取应用中指定类型的AID列表
try {
    cardEmulation.getAids(element, CardEmulation.CATEGORY_PAYMENT);
} catch (IllegalArgumentException e) {
    HiLog.error(TAG, "IllegalArgumentException when getAids");
}

Host服务的抽象类

  1. 应用的服务继承HostService,实现HCE卡模拟功能。
  2. 应用自定义实现抽象方法handleRemoteCommand(byte[] cmd, IntentParams params)和disabledCallback()。
  3. 应用自定义功能。
java">// HCE应用的服务继承HostService,实现HCE卡模拟功能
public class AppService extends HostService {
    @Override
    public byte[] handleRemoteCommand(byte[] cmd, IntentParams params) {
        HiLog.info(TAG, "handleRemoteCommand" );
        if (Arrays.equals(SELECT_PPSE, cmd)) {
            HiLog.info(TAG, "Matched PPSE select" );
            return PPSE_RESP;
        } else if (Arrays.equals(SELECT_MASTERCARD, cmd)) {
            HiLog.info(TAG, "Matched Mastercard select" );
            return SELECT_MASTERCARD_RESP;
        } else if (Arrays.equals(GET_PROC_OPT, cmd)) {
            HiLog.info(TAG, "Matched get processing options" );
            return GET_PROC_OPT_RESP;
        } else if (Arrays.equals(READ_REC, cmd)) {
            HiLog.info(TAG, "Matched read rec" );
            return READ_REC_RESP;
        } else if (cmd.length >= 5 && cmd[0] == (byte)0x80 && cmd[1] == (byte)0x2a
            && cmd[2] == (byte)0x8e && cmd[3] == (byte)0x80 && cmd[4] == 0x0f) {
            return COMPUTE_CHECKSUM_RESP;
        } else {
            return new byte[] {(byte)0x90, 0x00};
        }
    }
    
    @Override
    public void disabledCallback(int errCode) {
    // 应用自定义接口实现。
    }

    // 应用自定义功能
}

NFC消息通知

场景介绍

NFC消息通知是HarmonyOS内部或者与应用之间跨进程通讯的机制,注册者在注册消息通知后,一旦符合条件的消息被发出,注册者即可接收到该消息。

接口说明

表1 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状态改变消息

  1. 构建消息通知接收者NfcStateEventSubscriber。
  2. 注册NFC状态改变消息。
  3. NfcStateEventSubscriber接收并处理NFC状态改变消息。
java">// 构建消息接收者/注册者
class NfcStateEventSubscriber extends CommonEventSubscriber {
    NfcStateEventSubscriber (CommonEventSubscribeInfo info) {
        super(info);
    }

    @Override
    public 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场强消息

  1. 构建消息通知接收者NfcFieldOnAndOffEventSubscriber。
  2. 注册NFC场强消息。
  3. NfcFieldOnAndOffEventSubscriber接收并处理NFC场强消息。
java">// 构建消息接收者/注册者
class NfcFieldOnAndOffEventSubscriber extends CommonEventSubscriber {
    NfcFieldOnAndOffEventSubscriber (CommonEventSubscribeInfo info) {
        super(info);
    }

    @Override
    public 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());
}

http://www.niftyadmin.cn/n/1003980.html

相关文章

想知道PDF转高清图片软件哪个好?

张琳是一名设计师&#xff0c;她经常需要将自己的设计作品整理成PDF文档&#xff0c;以便向客户展示和交付。然而&#xff0c;有时客户需要对设计进行更详细的审查&#xff0c;而PDF格式的文件并不方便进行缩放和查看细节。这一问题让张琳感到非常困扰&#xff0c;她希望能够找…

访问学者申请英语口语怎样顺利通关

想要成功申请成为访问学者&#xff0c;英语口语的流利表达是非常重要的。下面知识人网小编整理的一些帮助你顺利通关的建议&#xff1a; 1. 提前准备&#xff1a;在面试之前&#xff0c;充分准备各种常见问题的回答。练习口语表达&#xff0c;加强词汇和语法的掌握。可以通过与…

UI设计指南-布局作者麓言信息

布局是元素在特定区域内的放置。屏幕使用的布局应充分表示服务的抽象空间的结构以及静态屏幕平衡。它们还显示在各种屏幕上&#xff0c;因此应将它们设计为在任何环境中的类似上下文中使用。 UI设计指南-布局   格式塔理论   格式塔理论是放置颜色&#xff0c;文本&a…

8、Redis哨兵(sentinel)

是什么? 吹哨人巡查监控后台master主机是否故障&#xff0c;如果故障了根据投票数 \textcolor{red}{投票数}投票数自动将某一个从库转换为新主库&#xff0c;继续对外服务 作用&#xff1a;俗称无人值守运维 能干嘛? 主从监控&#xff1a;监控主从redis库运行是否正常 消息…

超级实用!详解Node.js中的mongodb模块和socket.io模块

文章目录 9. mongodb 模块安装和引入连接数据库操作集合获取集合插入文档查询文档更新文档删除文档 关闭连接 10. socket.io 模块安装和引入监听连接事件监听自定义事件在服务器端监听事件在客户端触发事件 广播消息在服务器端广播消息在客户端监听广播消息 断开连接完整示例 9…

Spring创建Bean源码 - 解析配置类: 延迟导入选择器DeferredImportSelector

简介 DeferredImportSelector延迟导入选择器是Spring提供的一个扩展导入器&#xff0c;该导入器是ImportSelector的一个变体&#xff0c;该导入器是在处理配置类上Import注解的时候注册的&#xff0c;当所有{code Configuration}配置类解析完成后才会运行所有被注册的Deferred…

使用CRM系统如何让你的企业受益

随着市场的竞争日益加剧&#xff0c;企业需要更好地管理客户关系和提高销售。为此&#xff0c;很多企业已经开始使用CRM系统。CRM系统是一种管理客户关系的工具&#xff0c;可以帮助企业更好地了解客户需求&#xff0c;提高销售效率&#xff0c;提高客户满意度和忠诚度等。在这…

ES-索引的增删改查

1.索引 目的&#xff1a;存储学生的分数信息&#xff0c;且支持 搜索 “姓名、课程名、分数” -- 示例数据 -- {"username":"zs","courses": [{"course":"数学","grade": 99},{"course":"英语&q…