更新记录
1.0.8(2024-10-31)
- 修复高版本HB只回调一次问题
1.0.7(2024-06-23)
- 重构iOS版本
1.0.6(2024-04-13)
- 重构Android数据接口
查看更多
平台兼容性
App |
快应用 |
微信小程序 |
支付宝小程序 |
百度小程序 |
字节小程序 |
QQ小程序 |
HBuilderX 3.6.8,Android:4.4,iOS:13,HarmonyNext:不确定 |
× |
× |
× |
× |
× |
× |
钉钉小程序 |
快手小程序 |
飞书小程序 |
京东小程序 |
× |
× |
× |
× |
H5-Safari |
Android Browser |
微信浏览器(Android) |
QQ浏览器(Android) |
Chrome |
IE |
Edge |
Firefox |
PC-Safari |
× |
× |
× |
× |
× |
× |
× |
× |
× |
读写NFC卡,支持Tag的nded、非ndef(mifareUltralight)
- 读写文本(写入字节)
- 刷卡打开url
- 刷卡打开app应用
- 支持Tag、NDEF、mifareUltralight等
集成步骤
- 下载demo示例,拷贝demo里的nativeResources、Info.plist到项目里面
- iOS创建identifers时,要在Capabilites栏目里勾选NFC Tag Reading功能(Identifiers -> xxxx.xxx.xx(点击对应包名) -> Capabilities -> NFC Tag Reading,勾选后再生成.mobileprovision)
- Android增加nfc权限,即 "<uses-permission android:name=\"android.permission.NFC\"/>"
- 集成插件步骤请参考https://www.cnblogs.com/wenrisheng/p/18323027
插件变量引入
import {
getNFCFrom,
cleanIntentNFCData,
enableForegroundDispatch,
disableForegroundDispatch,
initNFC,
readNFC,
writeNFCNdefRecords,
writeNFCNdefUrls,
writeNFCNdefPackages,
writeNFCMifareUltralight,
UTSNFCReaderWriter,
gotoNFCActivity,
UTSNFCTagReaderSession,
UTSNFCNDEFReaderSession
} from "@/uni_modules/wrs-uts-nfc"
let tagReaderSession = new UTSNFCTagReaderSession()
let ndefReaderSession = new UTSNFCNDEFReaderSession()
示例demo用到ascii/十六进制转换插件https://ext.dcloud.net.cn/plugin?id=12803
android NFC读写
- 读取NFC卡数据(NDEF、非NDEF),解析数据参考demo
// 读取NFC数据
var params = {}
// 非必传,如果需要读取非NDEF数据,则需要传mifareUltralight参数
// params.mifareUltralight = {
// pageOffsets: [this.pageOffset]
// }
let resp = readNFC(params)
this.showMsg(JSON.stringify(resp))
let action = resp.action
if (action) {
if (action == "android.nfc.action.TAG_DISCOVERED") {
let tag = resp.tag
if (tag) {
} else {
this.showMsg("NFC标签是没有格式化的,或者没有分区的执行此步")
}
} else if (action == "android.nfc.action.ADAPTER_STATE_CHANGED") {
} else if (action == "android.nfc.action.NDEF_DISCOVERED") {
let ndefMessagesStr = resp.ndefMessages
let ndefMessages = JSON.parse(ndefMessagesStr)
console.log(ndefMessages)
if (ndefMessages && ndefMessages.length > 0) {
let firstNdefMessages = ndefMessages[0]
let records = firstNdefMessages.records
if (records && records.length > 0) {
let firstRecord = records[0]
let typeValue = firstRecord.typeValue
switch (typeValue) {
// 文本
case "RTD_TEXT":
console.log("文本")
// 解析文本
this.parseNdefText(firstRecord)
break;
// url
case "RTD_URI":
console.log("URL")
// 解析url
this.parseUrl(firstRecord)
break
default:
break;
}
}
}
} else if (action == "android.nfc.action.TECH_DISCOVERED") {
}
}
- android NDEF数据
{
"ndefMessages": "[{\"byteArray\":[-47,1,18,84,2,122,104,78,70,67,45,78,101,119,84,101,120,116,45,49,50,51],\"records\":[{\"tnf\":1,\"type\":[84],\"id\":[],\"byteArray\":[-47,1,18,84,2,122,104,78,70,67,45,78,101,119,84,101,120,116,45,49,50,51],\"mimeType\":\"text/plain\",\"payload\":[2,122,104,78,70,67,45,78,101,119,84,101,120,116,45,49,50,51]}]}]",
"tag": {
"techList": ["android.nfc.tech.NfcA", "android.nfc.tech.MifareUltralight", "android.nfc.tech.Ndef"],
"id": [4, -75, -23, 120, -72, 42, -127],
"mifareUltralightPageDatas": "[{\"data\":[1,3,-96,12,52,3,22,-47,1,18,84,2,122,104,78,70],\"pageOffset\":4}]",
"ndef": {
"type": "org.nfcforum.ndef.type2",
"isWritable": true,
"canMakeReadOnly": true,
"maxSize": 137
}
},
"id": [4, -75, -23, 120, -72, 42, -127],
"action": "android.nfc.action.NDEF_DISCOVERED"
}
- android Tag(非NDEF)数据
{
"tag": {
"techList": ["android.nfc.tech.NfcA", "android.nfc.tech.MifareUltralight", "android.nfc.tech.NdefFormatable"],
"id": [4, -15, -120, -110, 94, 17, -112],
"mifareUltralightPageDatas": "[{\"data\":[-79,-79,-66,-87,-55,-49,-70,-93,-71,-29,-42,-35,-52,-20,-67,-14],\"pageOffset\":4}]"
},
"id": [4, -15, -120, -110, 94, 17, -112],
"action": "android.nfc.action.TAG_DISCOVERED"
}
// ASCIIUtils工具类有插件(https://ext.dcloud.net.cn/plugin?id=12803)提供,请前往市场插件页面(https://ext.dcloud.net.cn/plugin?id=12803)下载集成
let text = "NFC-NewText-123";
let language = "zh"
let langBytes = ASCIIUtils.encodeUtf8(language)
// 文本转换为UTF-8格式
let textBytes = ASCIIUtils.encodeUtf8(text)
// 状态字节编码最高位数为0
let utfBit = 0
// 状态字节
let status = utfBit + langBytes.length
// byteArray为字节数组
let payload = []
payload.push(status)
payload.push(...langBytes)
payload.push(...textBytes)
console.log(status)
console.log(langBytes)
console.log(textBytes)
console.log(payload)
var ndefRecords = []
let tnf = 0x01
// 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
let type = [0x54]
// 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"
// "android.com:pkg".getBytes(): RTD_ANDROID_APP
let id = [0x00]
ndefRecords.push({
tnf: tnf, //
type: type,
id: id,
payload: payload
})
var params = {
"records": ndefRecords
}
let result = writeNFCNdefRecords(params)
this.showMsg(JSON.stringify(result))
var urls = []
urls.push("http://www.baidu.com")
var params = {
"urls": urls
}
let result = writeNFCNdefUrls(params)
this.showMsg(JSON.stringify(result))
- NFC写入包名package数据,刷卡即可打开app,(仅支持Android)
var packages = []
// 要打开的app包名,如打开短信:com.android.mms
packages.push("com.android.mms")
var params = {
"packages": packages
}
let result = writeNFCNdefPackages(params)
this.showMsg(JSON.stringify(result), this.isFormat)
var datas = []
datas.push({
pageOffset: this.pageOffset,
data: [0x00, 0x01, 0x02, 0x03]
})
var params = {
"datas": datas
}
let result = writeNFCMifareUltralight(params)
this.showMsg(JSON.stringify(result))
- 清除app获取到的NFC数据(仅支持Android,清除后需要再次刷卡才能识别到NFC)
cleanIntentNFCData();
ios NFC读写
ios里nfc的接口分为2种,一种是Tag,一种是NDEF,分别对应:
let tagReaderSession = new UTSNFCTagReaderSession()
let ndefReaderSession = new UTSNFCNDEFReaderSession()
- 设置Tag回调,读写tag的代码都在这个回调里,参考demo
tagReaderSession.setCallback((resp) => {
this.showMsg(JSON.stringify(resp))
let opt = resp.opt
switch (opt) {
case "didBecomeActive":
break;
case "didInvalidate":
// 结束操作
tagReaderSession.invalidate()
break;
case "didDetectTags":
let tags = resp.tags
if (tags.length > 0) {
// 连接tag
let params = {}
params.tagIndex = this.tagIndex // 连接第几个tag, tag在数组中的索引位置
tagReaderSession.connectTag(params, (resp) => {
this.showMsg("connectTag:" + JSON.stringify(resp))
if (resp.flag) { // 连接成功
let statusParams = {}
statusParams.tagIndex = this.tagIndex
// 读数据
tagReaderSession.readNDEF(statusParams, (ndefResp) => {
tagReaderSession.invalidate()
this.showMsg("readNDEF:" + JSON.stringify(ndefResp))
})
// 查询状态
// tagReaderSession.queryNDEFStatus(statusParams, (statusResp) => {
// this.showMsg("queryNDEFStatus:" + JSON.stringify(resp))
// if (statusResp.flag) { // 状态查询成功
// // 1: NotSupported 2: ReadWrite 3:ReadOnly
// let status = statusResp.status
// if (status == 2) {
// // 根据业务需要,往卡里写入数据
// let writeParams = this.getWriteNDEFData()
// writeParams.tagIndex = this.tagIndex
// tagReaderSession.writeNDEF(writeParams, (
// writeResp) => {
// if (writeResp.flag) { // 数据写入成功
// this.showMsg("数据写入成功")
// }
// tagReaderSession.invalidate()
// })
// } else {
// tagReaderSession.invalidate()
// }
// } else {
// tagReaderSession.invalidate()
// }
// })
} else { // 连接失败
tagReaderSession.invalidate()
}
})
} else {
tagReaderSession.invalidate()
}
break;
default:
break;
}
})
- 设置NDEF回调,读写ndef的代码都在这个回调里,参考demo
ndefReaderSession.setCallback((resp) => {
this.showMsg(JSON.stringify(resp))
let opt = resp.opt
switch (opt) {
case "didBecomeActive":
break;
case "didInvalidate":
// 结束操作
ndefReaderSession.invalidate()
break;
case "didDetectNDEFs":
ndefReaderSession.invalidate()
break;
case "didDetectTags":
let tags = resp.tags
if (tags.length > 0) {
ndefReaderSession.invalidate()
// 连接tag
let params = {}
params.tagIndex = this.tagIndex // 连接第几个tag, tag在数组tags中的索引位置
// ndefReaderSession.connectTag(params, (resp) => {
// if (resp.flag) { // 连接成功
// // 查询状态
// // this.iosQueryStatus()
// let writeParams = this.getWriteNDEFData()
// writeParams.tagIndex = this.tagIndex
// ndefReaderSession.writeNDEF(writeParams, (writeResp) => {
// if (writeResp.flag) { // 数据写入成功
// this.showMsg("数据写入成功")
// }
// ndefReaderSession.invalidate()
// })
// } else { // 连接失败
// ndefReaderSession.invalidate()
// }
// })
} else {
ndefReaderSession.invalidate()
}
break
default:
break;
}
})
let readingAvailable = UTSNFCReaderWriter.readingAvailable()
if (readingAvailable) {
}
// 初始化
tagReaderSession.initSession({
pollingOptions: 1 // 1: ISO14443 2: ISO15693 4: ISO18092 8: PACE
})
// 设置提示语
tagReaderSession.setAlertMessage("Tag 读取中...")
// 开始识别
tagReaderSession.begin()
tagReaderSession.invalidate()
let params = {}
params.tagIndex = this.tagIndex // 连接第几个tag, tag在数组中的索引位置
tagReaderSession.connectTag(params, (resp) => {
})
let statusParams = {}
statusParams.tagIndex = this.tagIndex
// 读数据
tagReaderSession.readNDEF(statusParams, (ndefResp) => {
tagReaderSession.invalidate()
this.showMsg("readNDEF:" + JSON.stringify(ndefResp))
})
tagReaderSession.queryNDEFStatus(statusParams, (statusResp) => {})
let writeParams = this.getWriteNDEFData()
writeParams.tagIndex = this.tagIndex
tagReaderSession.writeNDEF(writeParams, (
writeResp) => {
if (writeResp.flag) { // 数据写入成功
this.showMsg("数据写入成功")
}
tagReaderSession.invalidate()
})
// 初始化
ndefReaderSession.initSession({
invalidateAfterFirstRead: false,
alertMessage: "NDEF 读取中..."
})
// 开始识别
ndefReaderSession.begin()
ndefReaderSession.invalidate()
let params = {}
params.tagIndex = this.tagIndex // 连接第几个tag, tag在数组tags中的索引位置
ndefReaderSession.connectTag(params, (resp) => {})
let params = {}
params.tagIndex = this.tagIndex
tagReaderSession.queryNDEFStatus(params, (resp) => {
if (resp.flag) { // 状态查询成功
// 1: NotSupported 2: ReadWrite 3:ReadOnly
let status = resp.status
if (status == 2) {
// 根据业务需要,往卡里写入数据
this.iosWriteData()
} else {
tagReaderSession.invalidate()
}
} else {
tagReaderSession.invalidate()
}
})
let writeParams = this.getWriteNDEFData()
writeParams.tagIndex = this.tagIndex
ndefReaderSession.writeNDEF(writeParams, (writeResp) => {
if (writeResp.flag) { // 数据写入成功
this.showMsg("数据写入成功")
}
ndefReaderSession.invalidate()
})