参考文章链接:
uniapp 实现 NFC标签读取 和 写入
背景:
最近遇到一个需求,app需要对NFC标签写入网址(比如是商品链接),然后把NFC标签贴到商品上面,用户使用手机NFC感应可以直接跳转网页(商品详情)。
过程:
首先就是想到了在Dcloud社区查找文档,阅读量最高的就是吃辣条的大妖怪写的[uniapp 实现 NFC标签读取 和 写入]这篇文章。然后直接粘贴文章的代码去运行。发现确实能写入内容了,但是手机识别NFC只能显示新标签已收集。点击显示的是text/plain,没有显示具体内容,也跳转不了网站。一开始以为是TNF类型有问题,然后就把NdefRecord.TNF_MIME_MEDIA类型改成NdefRecord. TNF_ABSOLUTE_URI,结果还是不行。反正就是对new NdefRecord里面的几个参数各种修改,最后还是不行。后面想到能不能去通过原生Android的NFC写入代码来给自己一点灵感,下面找到的是一段Android原生代码。
文档链接:Android实现NFC读写
/**
* 往nfc写入数据
*/
public static void writeNFCToTag(String data, Intent intent) throws IOException, FormatException {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Ndef ndef = Ndef.get(tag);
ndef.connect();
NdefRecord ndefRecord = NdefRecord.createTextRecord(null, data);
NdefRecord[] records = {ndefRecord};
NdefMessage ndefMessage = new NdefMessage(records);
ndef.writeNdefMessage(ndefMessage);
}
通过这段代码,我发现NdefRecord.createTextRecord就可以实现NDEF创建,不需要通过new NdefRecord。然后在uniapp中直接把new NdefRecord方法改成了NdefRecord.createTextRecord。
// 创建包含 文本 的新 NDEF 记录
var ndefRecord = NdefRecord.createTextRecord(str);
写入成功!很激动的用手机去读取,发现现在是打开备忘录了。哎,有戏!但是和我想的还是不一样啊!NdefRecord类是不是还有别的方法呢?然后就去查阅Android文档,找到了CreateUri方法,它可以创建包含 URI 的新 NDEF 记录。文档链接:NdefRecord.CreateUri 方法
然后又把代码换成
// 创建包含 URI 的新 NDEF 记录
var ndefRecord = NdefRecord.createUri(str);
写入成功!用手机去读取,成功识别到写入的是一个网址,点击可以直接跳转浏览器打开!大功告成!目前试了小米、华为、1加、iPhone 11和13 等机型,除了小米都是可以成功识别并跳转浏览器的。
注:通过NdefRecord.createUri写入网址一定要加https://开头。
好了,下面贴上我所有的代码,希望可以帮助到大家,也希望大家可以多多交流。(我的代码是放在pages/main/index.vue页面下的。)
<template>
<view class="content">
<view class="uni-common-mt">
<view class="uni-form-item uni-column">
<input class="uni-input" v-model="inputValue" focus placeholder="请输入NFC要写入的内容" />
<button type="default" @click="writeData()">写入NFC</button>
<button type="default" @click="readData()">读取NFC</button>
</view>
</view>
</view>
</template>
<script>
var NfcAdapter;
var NdefRecord;
var NdefMessage;
var waiting
var readyRead = false;
var readyWriteData = false;
var nfcAdapter, main, pendingIntent, intentFiltersArray, techListsArray, IntentFilter
export default {
data() {
return {
inputValue: '',
currentNFCInfo: [], //NFC 读取消息;
bannerShow: false,
remark: "",
message: "",
count: 0,
timestampHide: "",
timestampShow: ""
};
},
methods: {
listenNFCStatus() {
try {
console.log('Init NFC...');
main = plus.android.runtimeMainActivity();
var Intent = plus.android.importClass('android.content.Intent');
var Activity = plus.android.importClass('android.app.Activity');
var PendingIntent = plus.android.importClass('android.app.PendingIntent');
IntentFilter = plus.android.importClass('android.content.IntentFilter');
NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');
nfcAdapter = NfcAdapter.getDefaultAdapter(main);
var intent = new Intent(main, main.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
pendingIntent = PendingIntent.getActivity(main, 0, intent, 0);
var ndef = new IntentFilter("android.nfc.action.TECH_DISCOVERED");
ndef.addDataType("*/*");
intentFiltersArray = [ndef];
techListsArray = [
["android.nfc.tech.IsoDep"],
["android.nfc.tech.NfcA"],
["android.nfc.tech.NfcB"],
["android.nfc.tech.NfcF"],
["android.nfc.tech.Ndef"],
["android.nfc.tech.NfcV"],
["android.nfc.tech.NdefFormatable"],
["android.nfc.tech.MifareClassic"],
["android.nfc.tech.MifareUltralight"]
];
} catch (e) {
console.error(e);
}
},
handle_nfc_data() {
NdefRecord = plus.android.importClass("android.nfc.NdefRecord");
NdefMessage = plus.android.importClass("android.nfc.NdefMessage");
// main = plus.android.runtimeMainActivity();
var intent = main.getIntent();
console.log("action type:" + intent.getAction());
if ("android.nfc.action.TECH_DISCOVERED" == intent.getAction()) {
if (readyRead) {
this.__read(intent);
readyRead = false;
}
if (readyWriteData) {
this.__write(intent);
readyWriteData = false;
}
} else {
// waiting.close();
console.log("nfc读取失败")
uni.showToast({
title: "NFC获取失败.",
icon: "none"
});
}
},
__read(intent) {
try {
var content = "";
waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");
waiting.setTitle('请勿移开标签\n正在读取数据...');
var tag = plus.android.importClass("android.nfc.Tag");
waiting.close();
var Parcelable = plus.android.importClass("android.os.Parcelable");
// var rawmsgs = intent.getParcelableArrayExtra("android.nfc.extra.NDEF_MESSAGES");
var rawmsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawmsgs != null && rawmsgs.length > 0) {
waiting.close();
console.log(JSON.stringify(rawmsgs[0]));
var records = rawmsgs[0].getRecords();
var result = records[0].getPayload();
console.log(JSON.stringify(result))
if (result != null) {
var s = plus.android.newObject("java.lang.String", result);
console.log(s);
this.currentNFCInfo = s;
uni.showModal({
title: 'NFC信息',
showCancel: false,
content: JSON.stringify(s),
});
} else {
this.currentNFCInfo = "";
}
} else {
console.log("NFC获取失败");
uni.showToast({
title: "NFC获取失败.",
icon: "none"
});
}
} catch (e) {
console.log(e);
console.log("NFC获取失败,丢出异常");
waiting.close();
uni.showToast({
title: "NFC获取失败,丢出异常.",
icon: "none"
});
//TODO handle the exception
}
},
readData() {
readyRead = true;
// waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");
setTimeout(this.handle_nfc_data, 1000);
},
__write(intent) {
try {
waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");
waiting.setTitle('请勿移开标签\n正在写入...');
// var textBytes = plus.android.invoke(this.inputValue, "getBytes");
// var typeBytes = plus.android.invoke('text/plain', 'getBytes')
// 创建 NDEF 记录
// var textRecord = new NdefRecord(
// NdefRecord.TNF_MIME_MEDIA, // TNF 类型
// typeBytes, // 类型(MIME 类型)
// null, // ID(留空以自动生成)
// textBytes, // 有效负载(文本的字节表示)
// );
// 创建包含 URI 的新 NDEF 记录
var ndefRecord = NdefRecord.createUri(this.inputValue);
var message = new NdefMessage([ndefRecord]);
console.log('messgae=' + message)
var Ndef = plus.android.importClass('android.nfc.tech.Ndef');
var NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');
var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
var ndef = Ndef.get(tag);
if (ndef != null) {
var size = message.toByteArray().length;
console.log("size=" + size);
ndef.connect();
if (!ndef.isWritable()) {
console.log("tag不允许写入");
waiting.close();
uni.showToast({
title: "tag不允许写入.",
icon: "none"
});
return;
}
if (ndef.getMaxSize() < size) {
console.log("文件大小超出容量");
waiting.close();
uni.showToast({
title: "文件大小超出容量.",
icon: "none"
});
return;
}
// console.log('写入数据:' + JSON.stringify(message) + ' __TYPE__: ' + JSON.stringify(message.__TYPE__));
console.log("message:" + message)
ndef.writeNdefMessage(message);
waiting.close();
console.log("写入数据成功.");
uni.showToast({
title: "写入数据成功.",
icon: "none"
});
return;
} else {
var format = NdefFormatable.get(tag);
if (format != null) {
try {
format.connect();
format.format(message);
console.log("格式化tag并且写入message")
waiting.close();
return;
} catch (e) {
console.log("格式化tag失败.");
waiting.close();
uni.showToast({
title: "格式化tag失败.",
icon: "none"
});
return;
}
} else {
console.log("Tag不支持NDEF");
uni.showToast({
title: "Tag不支持NDEF",
icon: "none"
});
waiting.close();
return;
}
}
} catch (e) {
console.log("error=" + e);
waiting.close();
console.log('写入失败');
}
},
writeData() {
readyWriteData = true;
// waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");
setTimeout(this.handle_nfc_data, 1000);
},
},
onLoad: function(option) {
console.log('onLoad')
this.listenNFCStatus()
},
onShow: function() {
console.log('page Show');
this.listenNFCStatus()
this.timestampShow = (new Date()).getTime();
console.log(this.timestampShow)
var TimeScale = this.timestampShow - this.timestampHide;
console.log(TimeScale, nfcAdapter, '134 line');
if (nfcAdapter == null) {
alert("设备不支持NFC!");
return;
}
if (!nfcAdapter.isEnabled()) {
alert("请在系统设置中先启用NFC功能!");
return;
}
nfcAdapter && nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);
if (this.count++ == 0) {
// this.listenNFCStatus()
return false;
} else if (TimeScale > 400) {
return false;
} else {
// this.readData();
// this.writeData();
}
},
onHide: function() {
console.log("onHide");
this.timestampHide = (new Date()).getTime();
console.log(this.timestampHide);
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>
0 个评论
要回复文章请先登录或注册