
鸿蒙5 NFC开发实战:一碰传功能完整实现指南
鸿蒙5的NFC能力为设备间快速交互提供了强大支持,其中"一碰传"是极具特色的功能。本文将基于ArkCompiler开发工具,从原理到实践全面讲解NFC一碰传功能的实现过程。
一、NFC技术基础与鸿蒙实现
1.1 鸿蒙NFC技术栈
NFC控制器:硬件抽象层
NFC服务:@ohos.nfc核心模块
NFC标签:tag读写子系统
HCE:主机卡模拟功能
1.2 一碰传工作流程
设备A触发NFC → 设备B检测到NFC信号 → 建立P2P连接 → 数据加密传输 → 自动处理内容
二、开发环境配置
2.1 权限声明
在module.json5中添加:
{
“module”: {
“requestPermissions”: [
{
“name”: “ohos.permission.NFC”,
“reason”: “用于NFC一碰传功能”
},
{
“name”: “ohos.permission.INTERNET”,
“reason”: “传输数据需要网络支持”
}
]
}
}
2.2 设备能力声明
在config.json中添加:
{
“deviceCapabilities”: [
“nfc”
]
}
三、NFC基础功能实现
3.1 检测NFC可用性
// utils/nfcUtil.ets
import nfc from ‘@ohos.nfc’
import featureAbility from ‘@ohos.ability.featureAbility’
class NfcUtil {
static isNfcSupported(): boolean {
try {
const context = featureAbility.getContext()
const support = nfc.isNfcAvailable(context)
console.log(NFC支持状态: ${support}
)
return support
} catch (error) {
console.error(‘检测NFC支持状态失败:’, error)
return false
}
}
static isNfcEnabled(): boolean {
try {
const context = featureAbility.getContext()
const enabled = nfc.isNfcOpen(context)
console.log(NFC启用状态: ${enabled}
)
return enabled
} catch (error) {
console.error(‘检测NFC启用状态失败:’, error)
return false
}
}
}
export default NfcUtil
3.2 监听NFC状态变化
// services/nfcService.ets
import nfc from ‘@ohos.nfc’
import featureAbility from ‘@ohos.ability.featureAbility’
class NfcService {
private static instance: NfcService
private context = featureAbility.getContext()
private stateListener: nfc.NfcStateListener = {
onStateChange: (state: nfc.NfcState) => {
console.log(‘NFC状态变化:’, this.getStateDescription(state))
// 这里可以添加状态处理逻辑
}
}
private getStateDescription(state: nfc.NfcState): string {
switch (state) {
case nfc.NfcState.STATE_OFF: return ‘已关闭’
case nfc.NfcState.STATE_TURNING_ON: return ‘正在开启’
case nfc.NfcState.STATE_ON: return ‘已开启’
case nfc.NfcState.STATE_TURNING_OFF: return ‘正在关闭’
default: return ‘未知状态’
}
}
private constructor() {
nfc.on(‘nfcStateChange’, this.stateListener)
}
static getInstance(): NfcService {
if (!NfcService.instance) {
NfcService.instance = new NfcService()
}
return NfcService.instance
}
destroy() {
nfc.off(‘nfcStateChange’, this.stateListener)
}
}
export default NfcService.getInstance()
四、一碰传发送端实现
4.1 创建NDEF消息
// sender/NfcSender.ets
import nfc from ‘@ohos.nfc’
import tag from ‘@ohos.nfc.tag’
class NfcSender {
async createTextRecord(text: string): Promise<tag.NdefRecord> {
const ndefRecord: tag.NdefRecord = {
tnf: tag.NdefTnf.NFC_FORUM_TYPE_1, // 类型名称格式
rtdType: tag.NdefRtdType.RTD_TEXT, // 记录类型定义
id: new Uint8Array(0), // 记录ID
payload: this.stringToUint8Array(text) // 文本内容
}
return ndefRecord
}
async createUriRecord(uri: string): Promise<tag.NdefRecord> {
const ndefRecord: tag.NdefRecord = {
tnf: tag.NdefTnf.NFC_FORUM_TYPE_1,
rtdType: tag.NdefRtdType.RTD_URI,
id: new Uint8Array(0),
payload: this.stringToUint8Array(uri)
}
return ndefRecord
}
private stringToUint8Array(str: string): Uint8Array {
const encoder = new TextEncoder()
return encoder.encode(str)
}
}
export default new NfcSender()
4.2 发送NDEF消息
// sender/NfcSender.ets
class NfcSender {
private tagSession: tag.TagSession | null = null
async prepareTagSession(): Promise<boolean> {
try {
this.tagSession = tag.getTagSession()
if (!this.tagSession) {
console.error(‘获取TagSession失败’)
return false
}
await this.tagSession.connect()
return true
} catch (error) {
console.error('准备TagSession失败:', error)
return false
}
}
async writeNdefMessage(records: tag.NdefRecord[]): Promise<boolean> {
if (!this.tagSession) {
console.error(‘TagSession未初始化’)
return false
}
try {
const ndefMessage: tag.NdefMessage = {
records: records
}
await this.tagSession.writeNdefMessage(ndefMessage)
return true
} catch (error) {
console.error('写入NDEF消息失败:', error)
return false
} finally {
this.releaseTagSession()
}
}
private releaseTagSession() {
if (this.tagSession) {
try {
this.tagSession.close()
} catch (error) {
console.error(‘关闭TagSession失败:’, error)
}
this.tagSession = null
}
}
}
五、一碰传接收端实现
5.1 注册NFC发现回调
// receiver/NfcReceiver.ets
import nfc from ‘@ohos.nfc’
import tag from ‘@ohos.nfc.tag’
class NfcReceiver {
private tagCallback: tag.TagCallback = {
onTagFound: async (foundTag: tag.Tag) => {
console.log(‘发现NFC标签’)
try {
const tagSession = tag.getTagSession(foundTag)
await tagSession.connect()
const ndefMessage = await tagSession.readNdefMessage()
this.processNdefMessage(ndefMessage)
tagSession.close()
} catch (error) {
console.error('处理NFC标签失败:', error)
}
}
}
startDiscovery() {
try {
nfc.registerTagEvent(this.tagCallback)
console.log(‘NFC发现已注册’)
} catch (error) {
console.error(‘注册NFC发现失败:’, error)
}
}
stopDiscovery() {
try {
nfc.unregisterTagEvent(this.tagCallback)
console.log(‘NFC发现已取消’)
} catch (error) {
console.error(‘取消NFC发现失败:’, error)
}
}
private processNdefMessage(ndefMessage: tag.NdefMessage) {
if (!ndefMessage || !ndefMessage.records || ndefMessage.records.length === 0) {
console.log(‘空的NDEF消息’)
return
}
ndefMessage.records.forEach(record => {
switch (record.rtdType) {
case tag.NdefRtdType.RTD_TEXT:
const text = this.uint8ArrayToString(record.payload)
console.log('接收到文本:', text)
this.handleTextContent(text)
break
case tag.NdefRtdType.RTD_URI:
const uri = this.uint8ArrayToString(record.payload)
console.log('接收到URI:', uri)
this.handleUriContent(uri)
break
default:
console.log('未知类型的NDEF记录')
}
})
}
private uint8ArrayToString(uint8Array: Uint8Array): string {
const decoder = new TextDecoder()
return decoder.decode(uint8Array)
}
}
5.2 处理接收到的内容
// receiver/NfcReceiver.ets
class NfcReceiver {
private handleTextContent(text: string) {
// 在实际应用中,这里可以触发UI更新或业务逻辑
prompt.showToast({
message: 接收到文本: ${text}
,
duration: 3000
})
// 示例:如果是JSON数据,可以解析后处理
try {
const data = JSON.parse(text)
console.log('解析后的JSON数据:', data)
// 处理业务数据...
} catch (e) {
console.log('内容不是JSON格式')
}
}
private handleUriContent(uri: string) {
prompt.showToast({
message: 接收到链接: ${uri}
,
duration: 3000
})
// 示例:直接打开网页或应用内跳转
if (uri.startsWith('http')) {
// 使用系统浏览器打开
featureAbility.startAbility({
want: {
bundleName: "com.ohos.browser",
abilityName: "com.ohos.browser.MainAbility",
uri: uri
}
})
}
}
}
export default new NfcReceiver()
六、完整的一碰传示例
6.1 发送端页面实现
// pages/SenderPage.ets
import NfcSender from ‘…/sender/NfcSender’
import NfcUtil from ‘…/utils/nfcUtil’
@Entry
@Component
struct SenderPage {
@State message: string = ‘这是一条测试消息’
@State isSending: boolean = false
@State sendStatus: string = ‘等待发送…’
async onSend() {
if (!NfcUtil.isNfcEnabled()) {
prompt.showToast({ message: ‘请先开启NFC功能’, duration: 2000 })
return
}
this.isSending = true
this.sendStatus = '准备发送中...'
try {
const prepared = await NfcSender.prepareTagSession()
if (!prepared) {
this.sendStatus = '准备NFC连接失败'
return
}
const record = await NfcSender.createTextRecord(this.message)
const success = await NfcSender.writeNdefMessage([record])
this.sendStatus = success ? '发送成功!' : '发送失败'
prompt.showToast({
message: success ? '发送成功' : '发送失败',
duration: 2000
})
} catch (error) {
console.error('发送过程中出错:', error)
this.sendStatus = '发送出错: ' + error.message
} finally {
this.isSending = false
}
}
build() {
Column() {
Text(‘一碰传发送端’)
.fontSize(24)
.margin(20)
TextInput({ text: this.message })
.onChange((value) => {
this.message = value
})
.height(100)
.width('90%')
.margin(10)
Button(this.isSending ? '发送中...' : '开始发送')
.onClick(() => this.onSend())
.width('80%')
.height(50)
.margin(20)
.enabled(!this.isSending)
Text(this.sendStatus)
.fontSize(16)
.margin(10)
}
.width('100%')
.height('100%')
}
}
6.2 接收端页面实现
// pages/ReceiverPage.ets
import NfcReceiver from ‘…/receiver/NfcReceiver’
import NfcUtil from ‘…/utils/nfcUtil’
@Entry
@Component
struct ReceiverPage {
@State receivedContent: string = ‘等待接收数据…’
@State isListening: boolean = false
onStartListen() {
if (!NfcUtil.isNfcEnabled()) {
prompt.showToast({ message: ‘请先开启NFC功能’, duration: 2000 })
return
}
NfcReceiver.startDiscovery()
this.isListening = true
this.receivedContent = '监听中...靠近NFC标签即可接收数据'
}
onStopListen() {
NfcReceiver.stopDiscovery()
this.isListening = false
this.receivedContent = ‘已停止监听’
}
build() {
Column() {
Text(‘一碰传接收端’)
.fontSize(24)
.margin(20)
Text(this.receivedContent)
.fontSize(18)
.margin(20)
.padding(10)
.border({ width: 1, color: Color.Gray })
.width('90%')
.height(100)
Button(this.isListening ? '停止监听' : '开始监听')
.onClick(() =>
this.isListening ? this.onStopListen() : this.onStartListen()
)
.width('80%')
.height(50)
.margin(20)
Button('清空内容')
.onClick(() => {
this.receivedContent = '内容已清空'
})
.width('60%')
.height(40)
}
.width('100%')
.height('100%')
}
}
七、高级功能扩展
7.1 文件传输实现
// services/FileTransferService.ets
import fs from ‘@ohos.file.fs’
import NfcSender from ‘…/sender/NfcSender’
class FileTransferService {
async sendFile(fileUri: string): Promise<boolean> {
try {
// 读取文件内容
const file = await fs.open(fileUri)
const stat = await fs.stat(fileUri)
const content = await fs.read(file.fd, { length: stat.size })
await fs.close(file.fd)
// 创建文件信息记录
const fileInfo = {
name: fileUri.split('/').pop(),
size: stat.size,
type: this.getFileType(fileUri),
content: Array.from(content.buffer)
}
// 发送JSON格式的文件信息
const record = await NfcSender.createTextRecord(JSON.stringify(fileInfo))
return await NfcSender.writeNdefMessage([record])
} catch (error) {
console.error('发送文件失败:', error)
return false
}
}
private getFileType(fileUri: string): string {
const extension = fileUri.split(‘.’).pop()?.toLowerCase() || ‘’
switch (extension) {
case ‘jpg’: case ‘jpeg’: case ‘png’: case ‘gif’:
return ‘image/’ + extension
case ‘txt’:
return ‘text/plain’
case ‘pdf’:
return ‘application/pdf’
default:
return ‘application/octet-stream’
}
}
}
export default new FileTransferService()
7.2 安全加密传输
// utils/CryptoUtil.ets
import crypto from ‘@ohos.crypto’
class CryptoUtil {
private static readonly ALGORITHM = ‘AES128’
private static readonly KEY = ‘HarmonyNfc123456’ // 实际项目中应使用更安全的密钥管理方式
static encrypt(data: string): string {
try {
const cipher = crypto.createCipher(this.ALGORITHM, this.KEY)
let encrypted = cipher.update(data)
encrypted += cipher.final()
return encrypted
} catch (error) {
console.error(‘加密失败:’, error)
return data // 失败时返回原始数据
}
}
static decrypt(encrypted: string): string {
try {
const decipher = crypto.createDecipher(this.ALGORITHM, this.KEY)
let decrypted = decipher.update(encrypted)
decrypted += decipher.final()
return decrypted
} catch (error) {
console.error(‘解密失败:’, error)
return encrypted // 失败时返回加密数据
}
}
}
export default CryptoUtil
八、调试与优化建议
8.1 常见问题排查
NFC未响应:
检查设备是否支持NFC
确认NFC功能已开启
确保应用已获取NFC权限
数据传输失败:
检查NDEF消息格式是否正确
确认两台设备NFC天线位置对准
测试不同大小的数据包
8.2 性能优化技巧
减少NDEF记录数量:合并多个小记录为一个
压缩数据:对大文本使用gzip压缩
分片传输:实现大数据的分批传输协议
缓存处理:缓存最近传输的数据
// 优化后的发送方法示例
async sendLargeData(data: string) {
// 压缩数据
const compressed = this.compressData(data)
// 分片
const chunkSize = 500 // 每个分片500字节
const chunks = []
for (let i = 0; i < compressed.length; i += chunkSize) {
chunks.push(compressed.slice(i, i + chunkSize))
}
// 发送分片信息头
const headerRecord = await this.createTextRecord(
JSON.stringify({
total: chunks.length,
checksum: this.calculateChecksum(data)
})
)
// 发送分片
for (let i = 0; i < chunks.length; i++) {
const chunkRecord = await this.createTextRecord(
JSON.stringify({
index: i,
data: chunks[i]
})
)
await this.writeNdefMessage([chunkRecord])
}
}
结语
鸿蒙5的NFC一碰传功能为设备间交互提供了便捷高效的解决方案。本文从基础实现到高级功能,完整展示了:
NFC核心API的使用:标签读写、状态监听
NDEF消息处理:文本、URI等格式的封装解析
完整业务实现:发送端与接收端的协同工作
扩展能力:文件传输、安全加密等高级特性
在实际开发中,开发者还可以进一步探索:
与分布式能力结合实现多设备协同
集成AI能力实现智能内容识别
结合ArkUI 3D实现炫酷的交互效果
优化传输协议提升大数据传输效率
通过合理利用鸿蒙5的NFC能力,可以创造出更多创新性的近场交互体验。
