OpenHarmony之有源NFC-connected_nfc_tag模块详解
1. 模块概述
Connected NFC Tag模块是OpenHarmony NFC子系统的一部分,专门用于处理有源NFC标签的读写操作。与基础NFC模块不同,该模块专注于与已连接的有源NFC标签进行交互,提供更高层次的API供应用层使用。
设备必须具备有源NFC标签芯片,才能使用有源NFC标签的读和写服务
1.1 模块功能
- 提供有源NFC标签的初始化和去初始化功能
- 支持有源NFC标签的NDEF数据读写操作
- 提供事件回调机制,通知应用层标签状态变化
1.2 模块架构
Connected NFC Tag模块采用分层架构设计,从上到下分为:
- 应用层接口:为应用提供访问有源NFC标签的API
- 服务层:实现核心业务逻辑,包括权限检查、HDI适配等
- HDI层:与硬件抽象层交互,实现具体的读写操作
关于NFC通信技术的讲解可以参考我的文章:- 深度拆解OpenHarmony NFC服务:从开关到卡模拟掌握近场通信技术
2. 关键类及函数调用流程
2.1 服务启动流程
2.2 NFC标签初始化流程
2.3 NFC标签读取流程
2.4 NFC标签写入流程
2.5 事件回调注册流程
3. 关键接口及实现
3.1 INfcTagService接口
INfcTagService是Connected NFC Tag模块对外提供的核心接口,定义了有源NFC标签的基本操作。
接口定义文件:foundation/communication/connected_nfc_tag/interfaces/inner_api/include/infc_tag_service.h
主要方法:
Init(): 初始化NFC标签服务Uninit(): 去初始化NFC标签服务ReadNdefTag(std::string &response): 读取NFC标签的NDEF数据WriteNdefTag(const std::string &data): 向NFC标签写入NDEF数据ReadNdefData(std::vector<uint8_t> &data): 读取NFC标签的原始数据WriteNdefData(const std::vector<uint8_t> &data): 向NFC标签写入原始数据RegListener(const sptr<INfcTagCallback> &callback): 注册事件回调UnregListener(const sptr<INfcTagCallback> &callback): 注销事件回调
3.2 INfcTagCallback接口
INfcTagCallback是Connected NFC Tag模块的事件回调接口,用于通知应用层标签状态变化。
接口定义文件:foundation/communication/connected_nfc_tag/interfaces/inner_api/include/infc_tag_callback.h
主要方法:
OnNotify(int nfcRfState): 当NFC标签状态发生变化时调用
3.3 NfcTagService实现类
NfcTagService是INfcTagService接口的具体实现类,负责处理业务逻辑。
实现文件:foundation/communication/connected_nfc_tag/services/src/nfc_tag_service.cpp
关键方法实现:
OnStart(): 服务启动入口ServiceInit(): 服务初始化Init(): 初始化NFC标签服务,包含权限检查ReadNdefTag(): 读取NFC标签的NDEF数据,包含权限检查WriteNdefTag(): 写入NFC标签的NDEF数据,包含权限检查RegListener(): 注册事件回调
3.4 NfcTagHdiAdapter实现类
NfcTagHdiAdapter是HDI适配器类,负责与HDI层交互。
实现文件:foundation/communication/connected_nfc_tag/services/src/hdi/src/nfc_tag_hdi_adapter.cpp
关键方法实现:
Init(): 调用HDI层的初始化方法ReadNdefTag(): 调用HDI层的读取方法WriteNdefTag(): 调用HDI层的写入方法RegisterCallBack(): 注册回调到HDI层
4. 模块间关系
Connected NFC Tag模块与基础NFC模块的关系:
- Connected NFC Tag模块是基础NFC模块的扩展,专注于有源NFC标签的处理
- 两个模块都使用了HDI层进行硬件交互,但处理的设备类型不同
- Connected NFC Tag模块通过系统能力ID
NFC_CONNECTED_TAG_ABILITY_ID注册到系统中
5. 设计模式与最佳实践
5.1 使用的设计模式
-
单例模式:
NfcTagHdiAdapter使用单例模式确保全局只有一个实例- 通过
GetInstance()方法获取实例
-
Pimpl惯用法:
NfcTagHdiAdapter使用Pimpl惯用法隐藏实现细节- 通过
Impl类封装具体实现,降低编译依赖
-
代理模式:
NfcTagHdiAdapter作为HDI服务的代理- 隐藏了与HDI服务交互的复杂性
-
观察者模式:
- 通过
INfcTagCallback接口实现事件回调机制 NfcTagCallBackManager管理多个观察者
- 通过
5.2 最佳实践
-
权限检查:
- 在每个对外接口中都进行了权限检查
- 使用
VerifyPermissionsBeforeEntry()方法统一处理权限验证
-
线程安全:
- 使用
std::mutex保护共享资源 - 在回调管理器和HDI适配器中都有锁保护
- 使用
-
错误处理:
- 定义了详细的错误码
nfc_tag_errcode.h - 每个方法都有明确的错误返回值
- 定义了详细的错误码
-
资源管理:
- 使用智能指针管理对象生命周期
- 在析构函数中释放资源
-
日志记录:
- 使用
HILOG记录关键操作和错误信息 - 便于调试和问题定位
- 使用
5. 底层数据传输原理
Connected NFC Tag模块的数据传输基于HDI(Hardware Device Interface)机制:
- 服务层通过HDI代理获取HDI服务实例
- 调用HDI服务的方法执行具体的读写操作
- HDI层负责与硬件驱动交互,完成实际的数据传输
- 通过回调机制将硬件事件通知到服务层
5.1 数据传输时序图
5.2 回调机制时序图
6. 关键数据结构
6.1 NfcTagService
服务类,包含服务状态、回调管理器等信息。该类继承自系统能力框架,负责管理Connected NFC Tag服务的生命周期。
关键成员变量:
published_: 服务发布状态,标识服务是否已成功发布到系统能力管理器state_: 服务运行状态,标识服务当前是否处于运行状态callbackManager_: 回调管理器实例,用于管理所有注册的事件回调监听器
关键方法:
OnStart(): 系统能力启动入口,当系统能力被激活时调用OnStop(): 系统能力停止入口,当系统能力被停用时调用ServiceInit(): 服务初始化,负责发布服务到系统能力管理器VerifyPermissionsBeforeEntry(): 权限检查,在每个对外接口调用前验证调用者权限
构造函数与析构函数:
NfcTagService(): 构造函数,初始化成员变量~NfcTagService(): 析构函数,清理资源并注销所有回调监听器
实现细节:
OnStart()方法首先调用ServiceInit()进行服务初始化,然后将服务发布到系统能力管理器OnStop()方法负责清理资源,包括注销回调监听器和停止服务ServiceInit()方法通过调用Publish(this)将服务实例发布到系统能力管理器VerifyPermissionsBeforeEntry()方法使用系统权限检查API验证调用者是否具有访问NFC功能的权限
6.2 NfcTagCallBackManager
回调管理器,负责管理注册的回调监听器。该类使用线程安全的映射表存储回调监听器,并提供注册、注销和通知功能。
关键成员变量:
listenerMap_: 回调监听器映射表,使用std::map存储回调监听器,键为监听器ID,值为监听器实例listenerMapLock_: 回调监听器映射表锁,使用std::mutex保护映射表的线程安全访问
关键方法:
RegisterListener(): 注册回调监听器,将回调监听器添加到映射表中UnRegisterListener(): 注销回调监听器,从映射表中移除指定的回调监听器OnNotify(): 通知所有注册的监听器,遍历映射表并调用每个监听器的回调方法
构造函数与析构函数:
NfcTagCallBackManager(): 构造函数,初始化成员变量~NfcTagCallBackManager(): 析构函数,清理资源
实现细节:
RegisterListener()方法首先获取映射表锁,然后将回调监听器添加到映射表中UnRegisterListener()方法首先获取映射表锁,然后从映射表中移除指定的回调监听器OnNotify()方法首先获取映射表锁,复制映射表以避免在遍历过程中修改映射表,然后释放锁并遍历复制的映射表调用每个监听器的回调方法
6.3 NfcTagHdiAdapter
HDI适配器,负责与HDI层交互。该类使用单例模式和Pimpl惯用法,隐藏了与HDI服务交互的复杂性。
关键成员变量:
pimpl_: 指向Impl类的智能指针,封装了具体的HDI服务交互逻辑implMutex_: Impl类实例锁,确保多线程环境下Impl类实例的安全访问
关键方法:
GetInstance(): 获取单例实例,确保全局只有一个NfcTagHdiAdapter实例Init(): 初始化HDI适配器,获取HDI服务代理并调用HDI层的初始化方法Uninit(): 去初始化HDI适配器,释放HDI服务代理并调用HDI层的去初始化方法ReadNdefTag(): 读取NDEF标签数据,通过HDI服务代理调用HDI层的读取方法WriteNdefTag(): 写入NDEF标签数据,通过HDI服务代理调用HDI层的写入方法RegisterCallBack(): 注册回调,将上层回调注册到HDI服务UnRegisterCallBack(): 注销回调,从HDI服务注销上层回调
构造函数与析构函数:
NfcTagHdiAdapter(): 构造函数,初始化Impl类实例~NfcTagHdiAdapter(): 析构函数,释放Impl类实例
实现细节:
GetInstance()方法使用双重检查锁定模式确保线程安全的单例实例获取,避免了不必要的加锁开销Init()方法首先获取Impl类实例锁,然后调用Impl类的Init()方法,确保多线程环境下Impl类实例的安全访问ReadNdefTag()和WriteNdefTag()方法通过Impl类实例与HDI服务交互,确保所有HDI操作都在保护下进行RegisterCallBack()方法将上层回调传递给Impl类,由Impl类负责注册到HDI服务,实现了回调机制的分层处理
线程安全考虑:
- 使用
implMutex_保护Impl类实例的访问,防止多个线程同时操作Impl类实例 - 在所有对外接口方法中都获取了Impl类实例锁,确保方法执行的原子性
- Impl类内部也使用了锁机制保护HDI服务代理和回调接口的访问
6.4 NfcTagHdiAdapter::Impl
HDI适配器的具体实现类,负责与HDI服务交互。该类封装了所有与HDI服务直接交互的逻辑,包括获取服务代理、调用服务方法以及处理回调事件。
关键成员变量:
nfcTagProxy_: HDI服务代理,通过HDI框架获取的IConnectedNfcTagV1_1接口实例proxyMutex_: HDI服务代理锁,确保多线程环境下代理实例的安全访问upperCallBack_: 上层回调,保存注册的上层回调接口callbackMutex_: 上层回调锁,确保多线程环境下回调接口的安全访问inited: 初始化状态,标识HDI服务是否已成功初始化
关键方法:
GetProxy(): 获取HDI服务代理,通过HDI框架获取IConnectedNfcTagV1_1接口实例Init(): 初始化HDI服务,获取服务代理并调用HDI层的初始化方法Uninit(): 去初始化HDI服务,释放服务代理并调用HDI层的去初始化方法ReadNdefTag(): 读取NDEF标签数据,通过服务代理调用HDI层的读取方法WriteNdefTag(): 写入NDEF标签数据,通过服务代理调用HDI层的写入方法RegisterCallBack(): 注册回调到HDI服务,将上层回调注册到HDI服务UnRegisterCallBack(): 从HDI服务注销回调,从HDI服务注销上层回调OnChipEvent(): 处理芯片事件回调,接收来自HDI服务的事件通知并转发给上层回调
构造函数与析构函数:
Impl(): 构造函数,初始化成员变量~Impl(): 析构函数,释放资源并注销回调
实现细节:
GetProxy()方法使用HDI框架的HdiGetProxy函数获取IConnectedNfcTagV1_1接口实例,并检查获取结果以确保代理有效Init()方法首先调用GetProxy()获取服务代理,检查代理有效性后调用代理的Init()方法,并更新初始化状态ReadNdefTag()和WriteNdefTag()方法通过服务代理调用相应的HDI服务方法,处理返回结果并转换为上层需要的格式OnChipEvent()方法作为HDI服务回调函数,接收硬件事件并转发给上层回调接口,在转发前会检查回调接口的有效性
线程安全考虑:
- 使用
proxyMutex_保护HDI服务代理的访问,防止多个线程同时操作代理实例 - 使用
callbackMutex_保护上层回调接口的访问,确保回调注册和注销操作的线程安全 - 在所有涉及共享资源的方法中都正确使用了锁机制
7. 附录
7.1 相关源码文件
-
接口定义:
foundation/communication/connected_nfc_tag/interfaces/inner_api/include/infc_tag_service.hfoundation/communication/connected_nfc_tag/interfaces/inner_api/include/infc_tag_callback.h
-
服务实现:
foundation/communication/connected_nfc_tag/services/src/nfc_tag_service.cppfoundation/communication/connected_nfc_tag/services/src/nfc_tag_service.h
-
HDI适配器:
foundation/communication/connected_nfc_tag/services/src/hdi/include/nfc_tag_hdi_adapter.hfoundation/communication/connected_nfc_tag/services/src/hdi/src/nfc_tag_hdi_adapter.cpp
7.2 参考文档
- OpenHarmony NFC子系统设计文档
- HDI开发指南
- OpenHarmony系统能力开发指南
7.3 错误码
Connected NFC Tag模块定义了详细的错误码,用于标识各种错误情况。错误码定义在nfc_tag_errcode.h文件中,主要包括:
NFC_TAG_ERR_PERMISSION_DENIED: 权限不足,无法执行操作NFC_TAG_ERR_NOT_INITIALIZED: 模块未初始化,无法执行操作NFC_TAG_ERR_ALREADY_INITIALIZED: 模块已初始化,重复初始化NFC_TAG_ERR_IO_ERROR: IO错误,与硬件通信失败NFC_TAG_ERR_INVALID_PARAM: 参数无效NFC_TAG_ERR_NO_TAG: 未检测到标签NFC_TAG_ERR_TAG_LOST: 标签丢失NFC_TAG_ERR_NOT_SUPPORTED: 不支持的操作
所有对外接口方法都应正确处理这些错误码,并在发生错误时返回相应的错误值。
更多推荐

所有评论(0)