uniapp使用nfc功能及详解

news2025/1/12 6:15:02

公司使用uniapp在android手机端要增加一个nfc识别的功能。在此记录一下实现的过程。

资料查找

我的代码逻辑主要来源于找到的这篇文章:

uniapp-安卓NFC读取 - 我要找到我的全世界 - 博客园

 文章内附有代码,为防止文章失效代码消失,在这篇文章里面也记录一下。

var NfcAdapter;
var NdefRecord;
var NdefMessage;
var _getCardNo;
 
export default {
    initNFC() {
        if (uni.getSystemInfoSync().platform == 'android') {
            listenNFCStatus()
        }
    },
    readNFC(callback) {
        if (uni.getSystemInfoSync().platform == 'android') {
            readData(callback);
        }
    },
    closeNFC() {
        if (uni.getSystemInfoSync().platform == 'android') {
            closeReadAndWrite();
        }
    }
}
 
function listenNFCStatus() {
    try {
        var 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');
        var IntentFilter = plus.android.importClass('android.content.IntentFilter');
        NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');
        var nfcAdapter = NfcAdapter.getDefaultAdapter(main);
 
        if (nfcAdapter == null) {
            uni.showToast({
                title: '设备不支持NFC!',
                icon: 'none'
            })
            return;
        }
         
        if (!nfcAdapter.isEnabled()) {
            uni.showToast({
                title: '请在系统设置中先启用NFC功能!',
                icon: 'none'
            });
            return;
        }
 
        var intent = new Intent(main, main.getClass());
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        var pendingIntent = PendingIntent.getActivity(main, 0, intent, 0);
        var ndef = new IntentFilter("android.nfc.action.TECH_DISCOVERED");
        ndef.addDataType("*/*");
        var intentFiltersArray = [ndef];
        var techListsArray = [
            ["android.nfc.tech.IsoDep"],
            ["android.nfc.tech.NfcA"],
            ["android.nfc.tech.NfcB"],
            ["android.nfc.tech.NfcF"],
            ["android.nfc.tech.Nfcf"],
            ["android.nfc.tech.NfcV"],
            ["android.nfc.tech.NdefFormatable"],
            ["android.nfc.tech.MifareClassic"],
            ["android.nfc.tech.MifareUltralight"]
        ];
        plus.globalEvent.addEventListener("newintent",
            function() {
                setTimeout(handle_nfc_data1, 1000);
            }, false);
        plus.globalEvent.addEventListener("pause", function(e) {
            if (nfcAdapter) {
                nfcAdapter.disableForegroundDispatch(main);
            }
        }, false);
        plus.globalEvent.addEventListener("resume", function(e) {
            if (nfcAdapter) {
                //console.log('resume'); 
                nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);
            }
        }, false);
        nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);
    } catch (e) {
        console.error(e);
    }
}
 
function handle_nfc_data1() {
    NdefRecord = plus.android.importClass("android.nfc.NdefRecord");
    NdefMessage = plus.android.importClass("android.nfc.NdefMessage");
    var main = plus.android.runtimeMainActivity();
    var intent = main.getIntent();
    //console.log("action type:" + intent.getAction()); 
    if ("android.nfc.action.TECH_DISCOVERED" == intent.getAction()) {
        if (readyWriteData) {
            //__write(intent);
            readyWriteData = false;
        } else if (readyRead) {
            __read(intent);
            readyRead = false;
        }
    }
}
 
function showToast(msg) {
    plus.nativeUI.toast(msg);
}
 
// function __write(intent) {
//  try {
//      waiting.setTitle('请勿移开标签\n正在写入...');
//      var text = document.getElementById('text').value;
//      console.log("text=" + text);
//      var textBytes = plus.android.invoke(text, "getBytes");
//      var textRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA,
//          plus.android.invoke("text/plain", "getBytes"), plus.android.invoke("", "getBytes"), textBytes);
//      var message = new NdefMessage([textRecord]);
//      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()) {
//              showToast("tag不允许写入");
//              waiting.close();
//              return;
//          }
//          if (ndef.getMaxSize() < size) {
//              showToast("文件大小超出容量");
//              waiting.close();
//              return;
//          }
 
//          ndef.writeNdefMessage(message);
//          waiting.close();
//          showToast("写入数据成功.");
//          return;
//      } else {
//          var format = NdefFormatable.get(tag);
//          if (format != null) {
//              try {
//                  format.connect();
//                  format.format(message);
//                  showToast("格式化tag并且写入message");
//                  waiting.close();
//                  return;
//              } catch (e) {
//                  showToast("格式化tag失败.");
//                  waiting.close();
//                  return;
//              }
//          } else {
//              showToast("Tag不支持NDEF");
//              waiting.close();
//              return;
//          }
//      }
//  } catch (e) {
//      console.log("error=" + e);
//      waiting.close();
//      alert('写入失败');
//  }
 
// }
 
function __read(intent) {
    try {
        var content = "";
        waiting.setTitle('请勿移开标签\n正在读取数据...');
        var tag = plus.android.importClass("android.nfc.Tag");
        tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        var bytesId = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);
        waiting.close();
        var tagid = bytesToHexString(tag.getId())
        if (typeof _getCardNo === 'function') {
            _getCardNo(tagid);
        }
    } catch (e) {
        uni.showToast({
            title: e,
            icon: 'none'
        });
    }
}
 
function bytesToHexString(inarray) {
    var i, j, x;
    var hex = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
        "B", "C", "D", "E", "F"
    ];
    var out = "";
    for (j = 0; j < inarray.length; ++j) {
        x = parseInt(inarray[j]) & 0xff;
        i = (x >> 4) & 0x0f;
        out += hex[i];
        i = x & 0x0f;
        out += hex[i];
    }
    return out;
}
 
function reverseTwo(str) {
 
    var str1 = "";
    for (var i = 1; i <= str.length; i++) {
        str1 += str[i - 1];
        if (i % 2 == 0) {
            if (i == str.length) {
                break;
            }
            str1 += ":";
        }
    }
    var str2 = "";
    for (var i = str1.split(":").length - 1; i >= 0; i--) {
        str2 += str1.split(":")[i];
    }
    return str2;
}
 
if (uni.getSystemInfoSync().platform == 'android') {
    //plus.globalEvent.addEventListener('plusready', listenNFCStatus, false);
}
 
var waiting;
var readyWriteData = false;
var readyRead = false;
 
function writeData() {
    var textEle = plus.globalEvent.getElementById('text');
    if (!textEle.value) {
        uni.showToast({
            title: '请输入要写入的内容!',
            icon: 'none'
        });
        return;
    }
    readyWriteData = true;
    waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");
}
 
function readData(getCardNo) {
    readyRead = true;
    _getCardNo = getCardNo
    waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!", {
        modal: false
    });
}
 
function closeReadAndWrite() {
    readyWriteData = false;
    readyRead = false;
 
    if (waiting) {
        waiting.close();
    }
}

代码内部是存在着写入功能的,被注释掉了,单单使用读取功能。

读取到的NFC类型有比较多种,这是我找到的比较好的一篇解释,大部分文章都有提到的4种类型。

搞懂Nfc刷卡看这篇就够了 - 知乎

文章里面附带了NFC相关的android官方文档,因为解析代码逻辑需要用到,我就把官网的链接也贴在下面。

NFC 基础知识  |  Android 开发者  |  Android Developers  

NfcAdapter  |  Android Developers 

代码使用:

 第一步:新建一个js文件,复制代码进去。

第二步:在涉及到使用nfc识别的页面,引入这个js文件。主要三个方法:初始化,关闭识别,识别成功回调方法

onload里面执行初始化initNFC,在离开页面的时候closeNFC(博主本人放在unload),点击某个按钮BUTTON的时候开始识别readNFC。

开启识别的时候会一直等待识别,建议添加一个setTimeout定时器,在固定时间调用closeNFC关闭识别,点击BUTTON的时候先清除再调用,识别成功的回调方法里面也要清理这个定时器。

代码逻辑个人理解:

uniapp需要在manifest.json中开启手机的NFC识别权限。

代码中也添加了判断手机是否开启了NFC识别,NFC的识别功能是调用了手机自身的一个intent,然后跳转回来。

 NfcAdapter适配器里面包含了许多的识别到的信息,这些信息都是要经过序列化才能使用的,如果不确定该调用哪个序列化方法,或者想知道还有哪些方法,可以去官方文档 里面找。

代码中就有使用到这两个值。

 从启动开始讲起,调用手机自身的nfc识别,就意味着当前的intent跳转到另外一个intent,读取到数据之后就跳转回来。

        var 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');
        var IntentFilter = plus.android.importClass('android.content.IntentFilter');
        NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');
        var nfcAdapter = NfcAdapter.getDefaultAdapter(main);



。。。。。。。。。。。。。。。。。。。。。。。。。。。。。


        var intent = new Intent(main, main.getClass());
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        var pendingIntent = PendingIntent.getActivity(main, 0, intent, 0);
        var ndef = new IntentFilter("android.nfc.action.TECH_DISCOVERED");
        ndef.addDataType("*/*");
        var intentFiltersArray = [ndef];
        var techListsArray = [
            ["android.nfc.tech.IsoDep"],
            ["android.nfc.tech.NfcA"],
            ["android.nfc.tech.NfcB"],
            ["android.nfc.tech.NfcF"],
            ["android.nfc.tech.Nfcf"],
            ["android.nfc.tech.NfcV"],
            ["android.nfc.tech.NdefFormatable"],
            ["android.nfc.tech.MifareClassic"],
            ["android.nfc.tech.MifareUltralight"]
        ];
        nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);

这些就是一些跳转的设置,下半部分设置了跳转的启动方式为Intent.FLAG_ACTIVITY_SINGLE_TOP,并且设置了intent过滤器。

下一步就是监听这些跳转,并处理放回的数据。于是在代码中可以看到下面的这些监听方法。

        plus.globalEvent.addEventListener("newintent",
            function() {
                setTimeout(handle_nfc_data1, 1000);
            }, false);
        plus.globalEvent.addEventListener("pause", function(e) {
            if (nfcAdapter) {
                nfcAdapter.disableForegroundDispatch(main);
            }
        }, false);
        plus.globalEvent.addEventListener("resume", function(e) {
            if (nfcAdapter) {
                //console.log('resume'); 
                nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);
            }
        }, false);

主要是“newintent"的监听,里面实现了主要的逻辑。

手机识别到nfc跳转回到应用的时候,intent会携带返回的信息。进行判断是否是"android.nfc.action.TECH_DISCOVERED"。意味着识别到了信息。

__read方法就是主要的处理信息的内容了,也是最重要的。

intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);将数据进行序列化。应用与应用直接传递数据,都要进行序列化和反序列化处理的。

bytesToHexString将数据转换。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/24791.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

向中央超算平台进化 哪吒汽车发布技术品牌“浩智”

电子电气架构是汽车的“大脑和神经系统”&#xff0c;决定了智能汽车的体验上限。为了实现高阶智能&#xff0c;车企须将汽车的电子电气架构从分布式&#xff0c;向集中式转变&#xff0c;打造出中央超算平台 11月21日&#xff0c;哪吒汽车举行“浩智战略2025”全球技术品牌发布…

Mentor Xpedition VX2.11入门遇到的问题和解决方案 (1)

一、前言 平时使用AD绘制板子&#xff0c;最近又朋友强烈推荐Mentor Xpedition。说它的自动布线功能非常强。相比于pads&#xff0c;这款软件的教程很少。但好在B站还是又几个不错的视频。在相关视频的讲解下&#xff0c;慢慢入门。目前来看这款软件的易用性很差&#xff0c;操…

aws eks创建节点组的不同方式和逻辑

该问题来源于&#xff0c;eks节点组能否修改实例类型&#xff0c;不同创建方式修改节点参数的方式是否有区别。结论如下&#xff1a; eksctl创建托管节点组&#xff0c;无法通过修改启动模板修改节点类型&#xff08;在eks控制台update会报错&#xff09;&#xff0c;但是可以…

网络系统管理 - Server02配置

一、Server02系统基础环境配置 二、DISK配置服务器软RAID工作任务 三、DFS membe端配置工作任务 1.Server02系统基础环境配置 (1)请根据附件说明或提供的基础信息,配置服务器的主机名,IP 地址,创建要求的用户名及密码;

docker镜像、容器 常用命令,容器端口映射

文章目录前言一、docker基础命令二、docker镜像命令1、docker images&#xff1a;列出本地主机的镜像2、 docker search &#xff1a;查看镜像3、docker pull&#xff1a;拉取镜像4、docker rmi &#xff1a; 删除docker镜像三、docker容器命令1、环境准备2、运行容器3、启动、…

Python常见工厂函数用法

工厂函数&#xff1a;能够产生类实例的内建函数。 工厂函数是指这些内建函数都是类对象&#xff0c; 当调用它们时&#xff0c;实际上是创建了一个类实例。 Python中的工厂函数举例如下&#xff1a; int(),long(),float(),complex(),bool()aint(9.9) a 9 blong(45) b 45L ff…

JavaScript 虚拟键盘:Mindfusion JavaScript Keyboard

高度交互&#xff0c;高度可定制--JavaScript 虚拟键盘--Mindfusion JavaScript Keyboard 现在&#xff0c;您的 JavaScript 应用程序可以像本地移动应用程序一样处理屏幕输入。 特征 键盘布局 扩展、紧凑和标准布局模式。KeyboardLayout 工具可帮助您根据需要创建和排列自定义…

【Hack The Box】linux练习-- Traverxec

HTB 学习笔记 【Hack The Box】linux练习-- Traverxec &#x1f525;系列专栏&#xff1a;Hack The Box &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2022年11月21日&#x1f334; &#x…

Spark学习(5)-Spark Core之RDD

1 RDD详解 1.1 为什么需要RDD 分布式计算需要: 分区控制Shuffle控制数据存储\序列化\发送数据计算API等一系列功能 这些功能, 不能简单的通过Python内置的本地集合对象(如 List\ 字典等)去完成。我们在分布式框架中, 需要有一个统一的数据抽象对象, 来实现上述分布式计算所需…

JavaScript面向对象:类的继承

继承 现实中的继承&#xff1a;子承父业&#xff0c;比如我们都继承了父亲的姓。 程序中的继承&#xff1a;子类可以继承父类的一些属性和方法。 语法&#xff1a; class Father{ // 父类 } class Son extends Father { // 子类继承父类 } 实例&#xff1a; cla…

手把手教你开通小程序流量主

手把手教你开通小程序流量主 开通条件是累计独立访客不低于 1000。也就是1000级以上&#xff0c;其实这个不难。 接下来以防火安全知识专项学习与竞答为例&#xff0c;写一篇开通流量主、创建广告和代码嵌入的图文教程。 功能介绍 广告展示位置灵活控制&#xff0c;接入简单…

操作系统复习【面试】

操作系统复习【面试】前言推荐操作系统复习第一章 操作系统引论 11.3 操作系统的基本特性 141.3.1 并发1.3.2 共享1.3.3 虚拟1.3.4 异步1.4 操作系统的主要功能 171.4.1 处理机管理功能1.4.2 存储器管理功能1.4.3 设备管理功能1.4.4 文件管理功能1.4.5 操作系统和用户之间的接口…

目标管理利器OKR-给被各大APP抢占使用时长的你

今天聊聊好用的时间和目标管理利器OKR&#xff0c;给被各大APP抢占使用时长的你。 1、海龟的秘密 一个游泳健将&#xff0c;他发现自己竟然游不过一只海龟&#xff0c;这让他疲惫不堪&#xff0c;又失望&#xff0c;又难堪。 然后他又去不断观察&#xff0c;终于发现了海龟游…

数据结构之队列

文章目录前言一、队列二、队列应该如何实现顺序表or链表扩展了解三、队列的实现1.队列的声明2.接口&#xff08;声明&#xff09;3.接口的实现创建一个新的节点判断队列为空队头元素入队出队销毁队列注意&#xff1a;4.主函数&#xff08;测试&#xff09;四、相关习题总结前言…

【C++基础】友元

友元 定义&#xff1a;类的特点是私有成员无法在作用域外访问&#xff0c;而友元函数是特权函数&#xff0c;允许访问私有成员。 语法&#xff1a;在函数或类前加friend。 例子&#xff1a;在message中&#xff0c;published每个人都可访问&#xff0c;secret只有自己可以访问…

开放经济中的货币-中国视角下的宏观经济

开放经济中的货币 – 潘登同学的宏观经济学笔记 文章目录开放经济中的货币 -- 潘登同学的宏观经济学笔记汇率&#xff1a;复习外汇冲销下的可能三角中国的811汇改国际货币体系的现在与未来当前国际货币体系存在三个主要问题体系具有内生不稳定性美元的中心地位带来了不平等非对…

[附源码]java毕业设计校园博客系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

树莓派快速上手-远程调试图形界面

0 简述 前面的文章里介绍过通过ssh在局域网或者远程访问树莓派&#xff0c;一般而言&#xff0c;对于非图形界面的开发仅通过ssh命令行交互就能够完成的&#xff0c;但是要开发图形界面展示或交互的应用时&#xff0c;光命令行交互的方式就远远不够了。这篇文章将针对树莓派这…

Conformer测试问题

https://github.com/pengzhiliang/Conformer 抽空测试了conformer&#xff0c;训练起来很简单&#xff0c;但是会遇到一个问题&#xff1a; Loss is nan, stopping training 我用的默认配置&#xff0c;不知道为什么会有这个问题&#xff0c;知道的来探讨下。 1.数据准备 我…

华为机试 - 最长连续子序列

目录 题目描述 输入描述 输出描述 用例 题目解析 算法源码 题目描述 有N个正整数组成的一个序列。给定整数sum&#xff0c;求长度最长的连续子序列&#xff0c;使他们的和等于sum&#xff0c;返回此子序列的长度&#xff0c; 如果没有满足要求的序列&#xff0c;返回-1…