uniapp uses nfc function and detailed explanation

The company uses uniapp to add an NFC recognition function on the android mobile phone. Here is a record of the implementation process.

 

Data search

My code logic is mainly derived from this article I found:

uniapp-Android NFC Reader- I want to find my whole world- Blog Park

 The code is attached to the article. In order to prevent the invalid code of the article from disappearing, it is also recorded in this article.

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();
    }
}

There is a write function inside the code, which is commented out, and only the read function is used.

There are many kinds of NFC types that can be read. This is a better explanation I found. Most articles have the 4 types mentioned.

It is enough to understand Nfc card swiping and read this article-Knowledge

The article comes with NFC-related android official documents, because it needs to be used to analyze the code logic, so I will also post the link to the official website below.

NFC Basics | Android Developers | Android Developers  

NfcAdapter  |  Android Developers

Code using:

 Step 1: Create a new js file and copy the code into it.

Step 2: Introduce this js file on the page that involves using nfc recognition. There are three main methods: initialization, closing recognition, and recognition success callback method

Initialize initNFC in onload, closeNFC when leaving the page (the blogger himself puts it in unload), and start to recognize readNFC when a button BUTTON is clicked.

When the recognition is turned on, it will always wait for the recognition. It is recommended to add a setTimeout timer, call closeNFC to close the recognition at a fixed time, and clear it before calling it when the BUTTON is clicked. The callback method of the successful recognition should also clear this timer.

Personal understanding of code logic:

uniapp needs to enable the NFC identification permission of the mobile phone in manifest.json.

The code is also added to determine whether the mobile phone has enabled NFC recognition. The NFC recognition function calls an intent of the mobile phone itself, and then jumps back.

 The NfcAdapter adapter contains a lot of identified information, which can only be used after serialization. If you are not sure which serialization method to call, or want to know what other methods are available, you can find it in the official documentation.

These two values ​​are used in the code.

 From the start, calling the NFC recognition of the mobile phone itself means that the current intent jumps to another intent, and jumps back after reading the data.

        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);

These are some jump settings. In the second half, the jump start mode is set to Intent.FLAG_ACTIVITY_SINGLE_TOP, and the intent filter is set.

The next step is to listen for these jumps and process the returned data. So you can see the following monitoring methods in the code.

        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);

It is mainly the monitoring of "newintent", which implements the main logic.

When the mobile phone recognizes NFC and jumps back to the application, the intent will carry the returned information. Determine whether it is "android.nfc.action.TECH_DISCOVERED". Means that the information is recognized.

The __read method is the main content of processing information, and it is also the most important.

intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); Serialize the data. Applications that directly transfer data must be serialized and deserialized.

bytesToHexString converts the data.

The above content is to read the TAG tag ID value of the NFC tag card, if it is to read the MESSAGE information written by NFC. Use the method below to replace.

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's EXTRA_NDEF_MESSAGES has a write rule, the real data in the payload should be read from the third character.

In addition to the written content, the first two characters contain the encoding format of the content and the length of each character.

Guess you like

Origin blog.csdn.net/GhostPaints/article/details/127967951