鸿蒙5 NFC开发实战:一碰传功能完整实现指南

暗雨OL
发布于 2025-6-30 02:27
浏览
0收藏

鸿蒙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能力,可以创造出更多创新性的近场交互体验。

分类
标签
收藏
回复
举报
回复
    相关推荐