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的开关状态。示例代码如下:
代码语言:javascript复制// 查询本机是否支持NFC
if (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)数据到安全单元上。
接口说明
类名 | 接口名 | 功能描述 |
---|---|---|
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 {
@Override
public void serviceConnected() {
// 应用自实现
}
}
// 创建安全单元服务实例
SEService sEService = new SEService(context, new AppServiceConnectedCallback());
// 查询安全单元服务的连接状态
boolean isConnected = sEService.isConnected();
// 获取本机的全部安全单元,并获取指定的安全单元eSE
Reader[] 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();
// 打开Session
Optional<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 (optionalChannel.isPresent()) {
basicChannel.closeChannel();
}
if (optionalChannel .isPresent()) {
logicalChannel.closeChannel();
}
// 关闭Session资源
session.close();
// 关闭安全单元资源
eSe.closeSessions();
// 关闭安全单元服务资源
sEService.shutdown();