勒布朗
勒布朗
  • 发布:2024-03-07 11:33
  • 更新:2024-03-07 11:33
  • 阅读:1289

uni-app,NFC标签读取和写入网址,手机识别在浏览器中跳转

分类:uni-app

参考文章链接:
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 关注 分享

要回复文章请先登录注册