uniapp使用nfc功能及详解

Posted GhostPaints

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uniapp使用nfc功能及详解相关的知识,希望对你有一定的参考价值。

公司使用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将数据转换。

上面内容是读取NFC标签卡的TAG标签ID值,如果是要读取NFC写入的MESSAGE信息。使用下面的方法进行替换。

function __read(intent) 
    try 
        var content = "";
		waiting.setTitle('正在读取数据...');
		var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
		var messages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
		console.log(messages)
		for (var i = 0; i < messages.length; i++) 
		  var message = messages[i];
		  if (message != null) 
			var records =  message.getRecords();
			
			// Loop through all NDEF records in the current NDEF message
			for (var j = 0; j < records.length; j++) 
			  var recordType = String(records[j].getType());
			  var payload = String(records[j].getPayload());
			  
			  // Decode payload to readable text
			  payload = decodeURIComponent(escape(payload));
			  // TPIM00010141
			  // Print out result
			  console.log("Record type: " + recordType);
			  // String.fromCharCode(parseInt(payload[i]))
			  // var Realpayload = payload.split(',').map(strItem => String.fromCharCode(parseInt(strItem))).join('')
			  let textEncoding = (payload[0] & 0x80) === 0 ? "UTF-8" : "UTF-16";
			  let languageCodeLength = payload[0] & 0x3F;
			  let textStartIndex = 1 + languageCodeLength;
			  let text = payload.split(',').slice(textStartIndex).map(strItem => String.fromCharCode(parseInt(strItem))).join('')
			  content = text
			
		  
		
		waiting.close();
		var tagid = String(content)
        if (typeof _getCardNo === 'function') 
            _getCardNo(tagid);
        
     catch (e) 
		console.log(e)
        uni.showToast(
            title: e,
            icon: 'none'
        );
    

NFC的EXTRA_NDEF_MESSAGES有一个写入规则,payload中的真实数据,要从第三个字符开始读取。

除了写入的内容外,前面两个的字符包含了内容的编码格式,每个字符的长度这些信息。

1,uniapp功能之—NFC

参考技术A

在 根目录 的static中新建nfc.js文件
nfc.js

在需要的页面里面引入这个js

没了,结束了,是不是很简单呐,如有问题,欢迎留言。
最后:如果此篇博文对您有帮助,还请动动小手点点关注点点赞呐~,谢谢 ~ ~

以上是关于uniapp使用nfc功能及详解的主要内容,如果未能解决你的问题,请参考以下文章

uni-app打开地图及打开权限设置

使用uni-app制作支持小程序,H5及移动端app的个人简历

uni-app 代码

uni-app复制功能

uniapp基础知识学习笔记

uniapp基础知识学习笔记