更新记录
1.0.17(2025-12-25)
- 优化鸿蒙
1.0.16(2025-12-15)
- 优化
1.0.15(2025-12-12)
- 增加Android app在杀死、前台、后台运行时获取刷卡数据的逻辑
平台兼容性
uni-app(3.6.15)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | - | - | √ | √ | 5.0 | √ | √ |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - |
uni-app x(3.6.15)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | 5.0 | √ | √ | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| √ | √ | √ |
NFC TAG NDEF读写,支持Android、iOS、harmony
- 读写文本、url、external等等
- 刷卡打开url
- 刷卡打开app应用
集成步骤
- 下载demo示例,拷贝demo里的nativeResources、harmony-configs、AndroidManifest.xml、Info.plist到项目里面
- iOS创建identifers时,要在Capabilites栏目里勾选NFC Tag Reading功能(Identifiers -> xxxx.xxx.xx(点击对应包名) -> Capabilities -> NFC Tag Reading,勾选后再生成.mobileprovision)
- 集成插件步骤请参考https://www.cnblogs.com/wenrisheng/p/18323027
- demo里为了文本转码使用了插件https://ext.dcloud.net.cn/plugin?name=wrs-uts-modbuscrchex
- 如需定制请进入交流群私聊作者
插件变量引入
import {
UTSNFCTag
} from "@/uni_modules/wrs-uts-nfc"
let nfcTag = new UTSNFCTag()
NFC读卡
先调用准备读卡接口,然后卡放到手机NFC感应区,感应到有卡以后按照下面处理
- 准备读卡
let params = {}
switch (uni.getSystemInfoSync().platform) {
case 'android': {
}
break;
case 'ios': {
params.pollingOptions = ["iso14443"] // iso14443、iso15693、iso18092、pace
params.alertMessage = "Tag 读取中..."
}
break;
case 'harmonyos': {
}
break;
}
nfcTag.beginReadNFC(params)
- Android感应到NFC卡后,会自动回调页面到onShow接口,然后调用nfcTag.readNDEF接口获取卡数据
let params = {}
nfcTag.readNDEF(params, (resp) => {
console.log("android NFC:" + JSON.stringify(resp))
let messages = resp.messages
if (messages && messages.length > 0) {
for (let i = 0; i < messages.length; i++) {
let message = messages[i]
let records = message.records
if (records && records.length > 0) {
for (let j = 0; j < records.length; j++) {
let record = records[j]
this.parseRecord(record)
}
}
}
}
})
- iOS感应到NFC卡后,会回调nfcTag.setCallback里的didDetectTags,然后调用连接tag接口connectTag后再调用nfcTag.readNDEF接口获取卡数据
let params = {}
params.tagIndex = this.tagIndex // 连接第几个tag, tag在数组中的索引位置
nfcTag.connectTag(params, (resp) => {
this.showMsg("connectTag:" + JSON.stringify(resp))
if (resp.flag) { // 连接成功
let statusParams = {}
statusParams.tagIndex = this.tagIndex
nfcTag.readNDEF(statusParams, (ndefResp) => {
nfcTag.invalidate()
this.showMsg("readNDEF:" + JSON
.stringify(
ndefResp))
let message = ndefResp.message
if (message) {
let records = message.records
if (records && records.length >
0) {
for (let i = 0; i < records
.length; i++) {
let record = records[i]
this.parseRecord(record)
}
}
}
})
} else { // tag连接失败
nfcTag.invalidate()
this.showToast("tag连接失败")
}
})
- harmony感应到NFC卡后,会回调nfcTag.setCallback里的didDetectTags,回调结果里面带有NFC卡数据
case "didDetectTags":
{
............
for (let i = 0; i < tags.length; i++) {
let tag = tags[i]
let type = tag.type
if (type == "NDEF") {
let message = tag.message
if (message) {
let records = message.records
if (records && records.length > 0) {
for (let j = 0; j < records.length; j++) {
let record = records[j]
this.parseRecord(record)
}
}
}
}
}
}
- 解析卡数据方法请参考demo里的parseRecord(record)接口
读卡数据样例子:
// ios
{
"opt": "didDetectTags",
"tags": [{
"id": [29, 219, 175, 6, 10, 16, 128], // 卡uid
"isAvailable": false,
"type": "miFare",
"historicalBytes": [],
"mifareFamily": 1
}]
}
{
"message": {
"size": 33,
"records": [{ // 卡记录数据
"id": [],
"type": [85],
"tnf": 1,
"payload": [2, 97, 105, 106, 105, 97, 110, 116, 97, 110, 46, 99, 111, 109, 63, 110, 97, 109, 101,
61, 119, 114, 115, 38, 97, 103, 101, 61, 49
]
}]
}
}
// android:
{
"tag": {
"techList": ["android.nfc.tech.NfcA", "android.nfc.tech.Ndef"],
"id": [29, -37, -81, 6, 10, 16, -128], // 卡uid
"ndef": {
"type": "org.nfcforum.ndef.type2",
"isWritable": true,
"canMakeReadOnly": true,
"maxSize": 137
}
},
"id": [29, -37, -81, 6, 10, 16, -128],
"messages": [{
"byteArray": [-111, 1, 29, 85, 2, 97, 105, 106, 105, 97, 110, 116, 97, 110, 46, 99, 111, 109, 63, 110,
97, 109, 101, 61, 119, 114, 115, 38, 97, 103, 101, 61, 49, 81, 1, 13, 85, 0, 109, 121, 97, 112,
112, 58, 47, 47, 104, 111, 115, 116
],
"records": [{ // 卡记录数据
"tnf": 1,
"type": [85],
"tnfValue": "TNF_WELL_KNOWN",
"id": [],
"typeValue": "RTD_URI",
"byteArray": [-47, 1, 29, 85, 2, 97, 105, 106, 105, 97, 110, 116, 97, 110, 46, 99, 111, 109,
63, 110, 97, 109, 101, 61, 119, 114, 115, 38, 97, 103, 101, 61, 49
],
"payload": [2, 97, 105, 106, 105, 97, 110, 116, 97, 110, 46, 99, 111, 109, 63, 110, 97, 109,
101, 61, 119, 114, 115, 38, 97, 103, 101, 61, 49
]
}, {
"tnf": 1,
"type": [85],
"tnfValue": "TNF_WELL_KNOWN",
"id": [],
"typeValue": "RTD_URI",
"byteArray": [-47, 1, 13, 85, 0, 109, 121, 97, 112, 112, 58, 47, 47, 104, 111, 115, 116],
"payload": [0, 109, 121, 97, 112, 112, 58, 47, 47, 104, 111, 115, 116]
}]
}],
"action": "android.nfc.action.NDEF_DISCOVERED"
},
// harmony
{
"opt": "didDetectTags",
"id": [29, 219, 175, 6, 10, 16, 128], // 卡uid
"technology": [1, 6],
"tags": [{
"technology": 1,
"type": "NFC_A"
}, {
"technology": 6,
"type": "NDEF",
"message": {
"records": [{ // 卡记录数据
"tnf": 1,
"type": [85],
"id": [],
"payload": [1, 98, 97, 105, 100, 117, 46, 99, 111, 109]
}]
},
"isNdefWritable": true,
"canSetReadOnly": true
}]
}
- NFC写卡
先调用准备写卡接口,然后卡放到手机NFC感应区,感应到有卡以后按照下面处理
- 准备写卡
let params = {}
switch (uni.getSystemInfoSync().platform) {
case 'android': {
// this.androidReadNFCData()
}
break;
case 'ios': {
params.pollingOptions = ["iso14443"]
params.alertMessage = "Tag 写入中..."
}
break;
case 'harmonyos': {
// let params = {}
// nfcTag.readNFC(params)
}
break;
}
nfcTag.beginWriteNFC(params)
- Android感应到NFC卡后,会自动回调页面到onShow接口,然后调用nfcTag.writeNDEF接口写入数据
- iOS感应到NFC卡后,会回调nfcTag.setCallback里的didDetectTags,然后调用连接tag接口connectTag后再调用nfcTag.writeNDEF接口写入数据
- harmony感应到NFC卡后,会回调nfcTag.setCallback里的didDetectTags,在这里调用nfcTag.writeNDEF接口写入数据
let params = this.getWriteNDEFData()
params.tagIndex = this.tagIndex //
nfcTag.writeNDEF(params, (resp) => {
console.log("writeNDEF resp:" + JSON.stringify(resp))
if (resp.flag) { // 数据写入成功
this.showMsg("数据写入成功")
} else {
this.showMsg("数据写入失败:" + JSON.stringify(resp))
}
nfcTag.invalidate()
})
- 写卡参数里record类型
- raw原始数据
{
type: "raw", // 写入原始数据
data: {
tnf: 0x00, //
type: [0x54],
id: [0x00],
payload: [0x00]
}
}
// tnf:
// 0x00: TNF_EMPTY
// 0x01: TNF_WELL_KNOWN
// 0x02: TNF_MIME_MEDIA
// 0x03: TNF_ABSOLUTE_URI
// 0x04: TNF_EXTERNAL_TYPE
// 0x05: TNF_UNKNOWN
// 0x06: TNF_UNCHANGED
// type:
// [0x54]: RTD_TEXT "T"
// [0x55]: RTD_URI "U"
// [0x53, 0x70] RTD_SMART_POSTER "Sp"
// [0x61, 0x63] RTD_ALTERNATIVE_CARRIER "ac"
// [0x48, 0x63] RTD_HANDOVER_CARRIER "Hc"
// [0x48, 0x72] RTD_HANDOVER_REQUEST "Hr"
// [0x48, 0x73] RTD_HANDOVER_SELECT "Hs"
- url数据
{
type: "url", // 写入原始数据
data: "https://www.baidu.com"
}
- external数据
{
type: "external",
data: {
domain: "android.com",
type: "pkg",
data: [0x00]
}
}
- 取消NFC卡感应
nfcTag.invalidate()
刷卡启动app业务
ios
方式1
NFC卡里写入自定义scheme,项目按照uniapp教程配置"iOS设置UrlSchemes"https://uniapp.dcloud.net.cn/tutorial/app-ios-capabilities.html,刷卡后系统会弹出横幅让用户选择打开哪个app来处理nfc
方式2
NFC卡里写入https通用链接,项目按照uniapp教程配置"iOS通用链接配置"https://uniapp.dcloud.net.cn/tutorial/app-ios-capabilities.html,刷卡后系统会弹出横幅让用户选择打开哪个app来处理nfc
android
方式1
NFC卡里写入自定义scheme,项目按照uniapp教程配置"android设置UrlSchemes"配置教程https://uniapp.dcloud.net.cn/tutorial/app-ios-capabilities.html,刷卡后系统会弹出横幅让用户选择打开哪个app来处理nfc
方式2
NFC卡里写入external类型的数据,刷卡后可以直接打开app
ndefRecords.push({
type: "external",
data: {
domain: "android.com", // 固定
type: "pkg",
data: strToArray("uni.app.UNID460C83") // 包名
}
})
android如果需要获取刷NFC卡启动app时的数据(app在杀死、前台、后台运行都能获取到),需要取消AndroidManifest.xml里面注释的代码,然后删除手机上的app,重新自定义基座运行,刷卡后会有一个一闪而过的过渡页面,如果要取消这个过渡页,需要本地离线打包,可以上面"进入交流群"联系作者
harmony
方式1
NFC卡里写入自定义scheme,项目按照鸿蒙教程配置Deep Linkinghttps://developer.huawei.com/consumer/cn/doc/harmonyos-guides/deep-linking-startup,刷卡后系统会弹框让用户选择打开哪个app来处理nfc
方式2
NFC卡里写入https通用链接,项目按照鸿蒙教程配置App Linkinghttps://developer.huawei.com/consumer/cn/doc/harmonyos-guides/applinking-preparations,刷卡后直接打开app
获取刷卡启动app时的卡数据
在app启动的时候获取nfc卡数据
onShow: function() {
console.log('App Show')
switch (uni.getSystemInfoSync().platform) {
case 'android': {
// app未启动时,刷卡启动app,通过UTSNFCTag.getLaunchNFCData接口获取nfc数据
let result = UTSNFCTag.getLaunchNFCData({})
console.log("getLaunchNFCData result:" + JSON.stringify(result))
let keySet = result.keySet
if (keySet) {
// 判断是否是刷external格式内容的卡启动的app
if (keySet.hasOwnProperty('profile')) {
// {"keySet":{"short_cut_class_name":"io.dcloud.PandoraEntry","profile":"UserHandle{0}","__intetn_orientation__":"2"},"action":"android.intent.action.MAIN"}
// model.msg = "用户点击桌面图标启动app"
// uni.$emit('updateMsg', {
// msg: model.msg
// })
console.log("用户点击桌面图标启动app")
} else {
// {"keySet":{"short_cut_class_name":"io.dcloud.PandoraEntry","__intetn_orientation__":"2"},"action":"android.intent.action.MAIN"}
// model.msg = "用户刷external卡启动app"
// uni.$emit('updateMsg', {
// msg: model.msg
// })
console.log("用户刷external卡启动app")
}
}
// 下面app在杀死时刷卡启动、前台/后台运行时,获取NFC卡数据生效的话,需要取消AndroidManifest.xml里面注释的代码,然后删除手机上的app,重新自定义基座运行,刷卡后会有一个一闪而过的过渡页面,如果要取消这个过渡页,需要本地离线打包,可以联系作者***
// 当app杀死时,通过刷卡启动app
let messages = result.messages
if (messages && messages.length > 0) {
let message = messages[0]
let records = message.records
if (records) {
let resultArray = parseRecordArray(records)
model.msg = JSON.stringify(resultArray)
console.log("UTSNFCTag.onSetCallback:" + model.msg)
uni.$emit('updateMsg', {
msg: model.msg
})
}
}
// 当app在后台或前台运行时,刷卡启动app时会回调这里
UTSNFCTag.onSetCallback((resp) => {
// console.log("UTSNFCTag.setCallback resp:" + JSON.stringify(resp))
let messages = resp.messages
if (messages && messages.length > 0) {
let message = messages[0]
let records = message.records
if (records) {
let resultArray = parseRecordArray(records)
model.msg = JSON.stringify(resultArray)
console.log("UTSNFCTag.onSetCallback:" + model.msg)
uni.$emit('updateMsg', {
msg: model.msg
})
}
}
})
let args = plus.runtime.arguments;
if (args) {
// nfc卡写入scheme时刷卡启动app,刷卡时系统会自动弹出横幅,点击横幅选择app打开
// myapp://host?name=wrs&age=15
// 处理args参数,如直达到某新页面等
model.msg = JSON.stringify(args)
uni.$emit('updateMsg', {
msg: model.msg
})
console.log("runtime arguments:" + JSON.stringify(args))
}
}
break;
case 'ios': {
// nfc卡写入scheme时刷卡启动app,刷卡时系统会自动弹出横幅,点击横幅选择app打开
let args = plus.runtime.arguments;
if (args) {
// myapp://host?name=wrs&age=15
// 处理args参数,如直达到某新页面等
model.msg = JSON.stringify(args)
uni.$emit('updateMsg', {
msg: model.msg
})
console.log("runtime arguments:" + JSON.stringify(args))
}
}
break;
case 'harmonyos': {
// deep link(自定义scheme)刷卡时会,刷卡时系统会自动弹框选择用哪个app打开,选择app打开
// app link刷卡时直接启动app
let args = plus.runtime.arguments;
if (args) {
// 处理args参数,如直达到某新页面等
let argsObj = JSON.parse(args)
if (argsObj) {
let NdefMsg = argsObj.NdefMsg
if (NdefMsg) {
let recordArray = UTSNFCTag.parseNdefMsg(NdefMsg)
let resultArray = parseRecordArray(recordArray)
model.msg = JSON.stringify(resultArray)
uni.$emit('updateMsg', {
msg: model.msg
})
}
}
}
}
break;
}
}

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 1078
赞赏 0
下载 12770857
赞赏 1833
赞赏
京公网安备:11010802035340号