The WeChat applet is connected to NFC, and the HCE is used to simulate the host card to send the message by swiping the NFC card

I believe everyone is familiar with NFC. Access control cards, bus cards, subway cards, and meal cards that are often used in reality all use NFC functions. Did you know that NFC can also be implemented with WeChat applets. Use the WeChat applet to read/write the mobile phone into a card reader, or use the WeChat applet to simulate a host card to swipe the access control/meal card, etc. This chapter will take you to see how the NFC of the WeChat applet is different!

Table of contents

1. What is NFC

2. What can NFC do?

3. NFC of WeChat applet

4. Use steps

1. Research APIs

2. How to use

One: new project

Two: Set up a simple page and the corresponding js

Three: Build our NFC project according to the NFC life cycle sequence we have sorted out above.

Four: You need to initialize StartHCE (initialize NFC, initialize the mobile phone as a host simulation card)

Five: onHCEMEssage monitoring

Six: Use wx.sendHCEMessage to send NFC messages

Summarize


1. What is NFC

NFC is a short-range wireless communication technology that uses a 13.56MHz frequency band. Although the communication distance is only about 10cm, it is the same as the non-contact IC card technology. We only need to "touch" to switch between different electronic products. Exchange data.

Unlike contactless IC cards, NFC is different from contactless IC cards in that NFC enables two-way communication. As long as it is a product and IC card that supports NFC, data can be read or written. It can also communicate between portable products such as mobile phones. The data transmission speed is not high, and there are four speeds of 106kbit/s, 212kbit/s, 424kbit/s and 848kbit/s to choose from.

Introduction to NFC

2. What can NFC do?

NFC has three functions of "card emulation", "reader/writer emulation" and "communication between products (P2P)".

1. Card simulation: For example, we can use mobile phones to simulate access control cards, bus cards, meal cards, etc. But it should be noted that it is simulated, that is to say, a card that does not exist physically.

2. Reader simulation: It means that you can simulate a reader, and when someone comes to you with an NFC card to swipe the card, you can obtain the information on the card.

3. Communication is data communication, and data exchange will be carried out when swiping NFC cards. Used to do some things, such as: configure the network, set information, transfer files and so on.

3. NFC of WeChat applet

NFC | WeChat Open Documentation

When we open the document, we can see that for NFC, the name WeChat gave it is: Near Field Communication

First of all, it must be emphasized that because of the permissions of the Apple mobile phone, NFC only supports in the WeChat applet: Android

WeChat divides NFC into three parts

  • HCE (Host-based Card Emulation), that is, an Android phone is simulated as a physical smart card. We can use the simulated smart card to swipe the corresponding card reader to transfer data to the card reader.
  • Support NFC reading and writing, that is, use the mobile phone as a card reader. That is, we can paste some physical NFC cards on the mobile phone to read the content of the card.
  • The NFC tag opens the applet. It refers to the ability that we can touch the mobile phone through the NFC card to quickly evoke the applet page.

1. HCE (host-based card emulation) usage scenarios:

  • Use mobile phone as access control card/bus card/metro card
  • Use the mobile phone to transfer data to the card reader (network distribution, registration)

2. NFC reading and writing usage scenarios:

  • Use the mobile phone as a card reader to obtain the information of the NFC card.

3. The usage scenario of NFC tag opening applet

  • Fast network configuration of equipment
  • Quick control such as fast file transfer

The official website documents are also very complete, and you can choose different scenarios to use according to your needs.

In this chapter, I chose the HCE (host-based card emulation) scenario.

4. Use steps

1. Research APIs

wx.stopHCE(Object object) | WeChat open document

微信官方文档中,卡模拟一共有六个API。

分别为:

wx.stopHCE 关闭NFC模块。

wx.startHCE Initialize NFC

wx.sendHCEMessage send NFC message

wx.onHCEMessage listens to receive NFC device message events.

wx.offHCEMessage removes the listener function for receiving NFC device message events

wx.getHCEState Determines whether the current device supports HCE capability.

It is important to emphasize again that NFC is only supported under the Android system.

2. How to use

Students who have experience in development are actually clearer.

The above API is obviously a life cycle .

From start to destruction. How should we operate this NFCapi?

1. First call wx.getHCEState to determine whether the device supports NFC

2. Call wx.startHCE(OBJECT) to initialize the NFC module of the mobile phone;

3. After the initialization is complete, call wx.onHCEMessage to monitor the response message of the chip;

4. Click the "Enquiry" button on the page to call wx.sendHCEMessage to send the inquiry command;

5. At this time wx.onHCEMessage (should be able to receive chip response data with uid information;

6. Business processing.

7. After all operations are completed, call wx.stopHCE to stop the NFC module of the mobile phone

Well, without further ado, let's go directly to our official project.

One: new project

We need to use WeChat developer tools to create a new project. If you have APPID, you can use your own, if not, you can use the test number.

Two: Set up a simple page and the corresponding js

Three: Build our NFC project according to the NFC life cycle sequence we have sorted out above.

The order is naturally: when the page is opened and initialized, getHCEState is required to determine whether the device supports NFC. If it is not supported, it needs to be compatible.

When the errCode of the return value is 0, everything is normal, and it supports NFC.

At the same time, in order to prevent everyone from judging the code more effectively, we can declare the return code of getHCEState on the official website for later use.

Four: You need to initialize StartHCE (initialize NFC, initialize the mobile phone as a host simulation card)

 wx.startHCE receives a parameter as aid_list.

The official explanation means that it needs to be registered in the AID list of the system. The AID list is actually the unique identification of each card reader. If you are not sure, please ask your Android or fill in by default: F22222222. Similar to other APIs, it also has its own return value, and the default value is 0 for normal success.

Five: onHCEMEssage monitoring

Before talking about this, many friends on the Internet have encountered similar, wx.onHCEMessage, no matter how you adjust it, there is no return value?

I don’t know if there are any partners who read my words carefully. After the initialization is completed, onHCEMessage will actually start monitoring. As for why there is no return value. It is because wx.onHCEMessage is a listener. It needs the card reader to respond to it, that is to say, it needs to send a message to the card reader (device) through the render command, and then it can get the value.

 

It has three return values, but we only generally take the first one, which is messageType.

When the value of messageType = 1 , that is to say, the card reader responded to us, saying that it received NFC. At this time, we can call sendHCEMessage to send a message to the card reader.

When the value of messageType = 2, that is to say, the mobile phone has been removed from the card reader.

 So here we only judge that the value of messageType is 1. When it is equal to 1, we can start sending messages.

Six: Use wx.sendHCEMessage to send NFC messages

Careful friends will find that wx.sendHCEMessage is not enough to send a message. Why do I have a lot of ArrayBuffer and even comm.

This is because the documentation has the annotation:

The data of wx.sendHCEMessage must be a binary data. That is, we cannot pass ordinary JSON, string and other data to it. Otherwise, an error will be reported.

So what do we need to do at this time?

convert!

The comm in my project is an encapsulated conversion file. The content is as follows:

comm.js

const formatTime = date => {
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()
  const hour = date.getHours()
  const minute = date.getMinutes()
  const second = date.getSeconds()

  return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
/**
 * 生成指定长度随机数
 */
function genRandom(n) {
  let a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; //生成的随机数的集合  
  let res = [];
  for (let i = 0; i < n; i++) {
    let index = parseInt(Math.random() * (a.length));    //生成一个的随机索引,索引值的范围随数组a的长度而变化  
    res.push(a[index]);
    a.splice(index, 1)  //已选用的数,从数组a中移除, 实现去重复  
  }
  return res.join('');
} 
/**
    * 字符串转换为时间
    * @param  {String} src 字符串
    */
function strToDate(dateObj){
  dateObj = dateObj.replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '').replace(/(-)/g, '/')
  dateObj = dateObj.slice(0, dateObj.indexOf("."))
  return new Date(dateObj)
}
function isFunctinMethod(name) {
  if (name != undefined && typeof name === 'function') {
    return true
  }
  return false
}
const formatNumber = n => {
  n = n.toString()
  return n[1] ? n : '0' + n
}

// ArrayBuffer转16进度字符串
function ab2hex(buffer) {
  var hexArr = Array.prototype.map.call(
    new Uint8Array(buffer),
    function (bit) {
      return ('00' + bit.toString(16)).slice(-2)
    }
  )
  return hexArr.join('');
}

//十六进制字符串转字节数组  
function hex2Bytes(str) {
  var pos = 0;
  var len = str.length;
  if (len % 2 != 0) {
    return null;
  }
  len /= 2;
  var hexA = new Array();

  for (var i = 0; i < len; i++) {
    var s = str.substr(pos, 2);
    var v = parseInt(s, 16);
    hexA.push(v);
    pos += 2;
  }
  return hexA;
}
function hex2ArrayBuffer(hex){
  var pos = 0;
  var len = hex.length;
  if (len % 2 != 0) {
    return null;
  }
  len /= 2;
  var buffer = new ArrayBuffer(len)
  var dataview=new DataView(buffer)
  for (var i = 0; i < len; i++) {
    var s = hex.substr(pos, 2);
    var v = parseInt(s, 16);
    dataview.setInt16(i,v)
    pos += 2;
  }

  return buffer
}
/**
 * string转16进制
 */
function stringToHex(str) {
  var val = "";
  for (var i = 0; i < str.length; i++) {
    if (val == "")
      val = str.charCodeAt(i).toString(16);
    else
      val += str.charCodeAt(i).toString(16);
  }
  return val;
}
/**
 * 16进制转string
 */
function hexCharCodeToStr(hexCharCodeStr) {
    var trimedStr = hexCharCodeStr.trim();
    var rawStr =
      trimedStr.substr(0, 2).toLowerCase() === "0x"
        ?
        trimedStr.substr(2)
        :
        trimedStr;
    var len = rawStr.length;
    if (len % 2 !== 0) {
        alert("Illegal Format ASCII Code!");
        return "";
    }
    var curCharCode;
    var resultStr = [];
    for (var i = 0; i < len; i = i + 2) {
        curCharCode = parseInt(rawStr.substr(i, 2), 16); // ASCII Code Value
        resultStr.push(String.fromCharCode(curCharCode));
    }
    return resultStr.join("");
}

function pad(num, n) {
  var len = num.toString().length;
  while (len < n) {
    num = "0" + num;
    len++;
  }
  return num;
}

function strToHexCharCode(str) {
    if (str === "")
        return "";
    var hexCharCode = [];
    hexCharCode.push("0x");
    for (var i = 0; i < str.length; i++) {
        hexCharCode.push((str.charCodeAt(i)).toString(16));
    }
    return hexCharCode.join("");
}
/**
 * string转byte数组
 */
function stringToByteArray(str) {
  var bytes = new Array();
  var len, c;
  len = str.length;
  for (var i = 0; i < len; i++) {
    c = str.charCodeAt(i);
    if (c >= 0x010000 && c <= 0x10FFFF) {
      bytes.push(((c >> 18) & 0x07) | 0xF0);
      bytes.push(((c >> 12) & 0x3F) | 0x80);
      bytes.push(((c >> 6) & 0x3F) | 0x80);
      bytes.push((c & 0x3F) | 0x80);
    } else if (c >= 0x000800 && c <= 0x00FFFF) {
      bytes.push(((c >> 12) & 0x0F) | 0xE0);
      bytes.push(((c >> 6) & 0x3F) | 0x80);
      bytes.push((c & 0x3F) | 0x80);
    } else if (c >= 0x000080 && c <= 0x0007FF) {
      bytes.push(((c >> 6) & 0x1F) | 0xC0);
      bytes.push((c & 0x3F) | 0x80);
    } else {
      bytes.push(c & 0xFF);
    }
  }
  return bytes;
}
/**
 * byte数组转string
 */
function byteToString(bytearr) {
  if (typeof arr === 'string') {
    return arr;
  }
  var str = '',
    _arr = arr;
  for (var i = 0; i < _arr.length; i++) {
    var one = _arr[i].toString(2),
      v = one.match(/^1+?(?=0)/);
    if (v && one.length == 8) {
      var bytesLength = v[0].length;
      var store = _arr[i].toString(2).slice(7 - bytesLength);
      for (var st = 1; st < bytesLength; st++) {
        store += _arr[st + i].toString(2).slice(2);
      }
      str += String.fromCharCode(parseInt(store, 2));
      i += bytesLength - 1;
    } else {
      str += String.fromCharCode(_arr[i]);
    }
  }
  return str;
}
/**
 * 二进制转10
 */
function bariny2Ten(byte){

  return parseInt(byte, 2)
}
function bariny2Hex(a){
  return parseInt(a, 16)
}
/**
 * 10/16进制转2进制
 */
function ten2Bariny(ten){
  
  return ten.toString(2)
}
function str2Hex(str){
  return parseInt(str, 10).toString(16)
}
/**
 * 16进制转2进制
 */
function hex2bariny(hex){
  return parseInt(hex, 16).toString(2)
}
module.exports = {
  formatTime: formatTime,
  isFunctinMethod: isFunctinMethod,
  ab2hex: ab2hex,
  hex2Bytes: hex2Bytes,
  stringToByteArray: stringToByteArray,
  byteToString: byteToString,
  hex2ArrayBuffer: hex2ArrayBuffer,
  bariny2Ten: bariny2Ten,
  bariny2Hex: bariny2Hex,
  ten2Bariny: ten2Bariny,
  str2Hex: str2Hex,
  hex2bariny: hex2bariny,
  genRandom: genRandom,
  stringToHex: stringToHex,
  hexToString: hexCharCodeToStr,
  pad: pad
}

 It includes common conversion methods such as string to byte array.

As for methods such as ArrayBuffer and DataView, I believe you all know it, so I won’t explain it in detail here. Those who don't understand can search and learn on CSDN.

Since what I need to pass to the background here is a JSON, I convert the JSON to a string. The string is then converted to a byte array and passed to the message.

comm is the conversion file of the above package. comm.js 

The stringToByteArray method is the method of converting string to byte array encapsulated in the comm.js file.

When we have finished all this, use the "real device debugging" to go to the corresponding card reader and swipe the card! You will find that the front end has succeeded, and the card reader has printed the data we passed on the console.

At this point, our project is over.

Summarize

The above is the function of the WeChat applet HCE simulation host card shared with you today.

But there are some pitfalls among them. I list them for your reference!

1. wx.onHCEMessage has no return value.

This may be the most common problem I have seen. In fact, the reason why it does not return a value is that the card reader does not return information. In layman's terms, your mobile phone has NFC turned on. When you touch the card reader, the mobile phone does not know whether you have touched the card reader, so you need the card reader to tell you, you touch me, you can Send a message. Therefore, the processing of this piece needs to be handled by the corresponding client development, and the small program end has ended. If you don’t know how to develop the client, here is an article by a big guy, so that you can refer to it for client development. Wechat applet NFC HCE card simulation + AndroidNFC read Ubigo

2. My phone does not respond to card swiping. Where did I make a mistake?

If you follow the above steps and combine the official website documents, then you are basically right. If there is no response to swiping the card, and the client has already processed it at this time. Then there is only one possibility, the mobile phone compatibility is not enough. Try another android phone. (PS: I tried vivo and Huawei. There are two mobile phones in vivo that do not support it. The one currently used by Huawei does support it),

3. What is aid_list and how to find it?

In fact, the easiest way is to find your client to develop. They have a way to find the aid of your card reader. The default is generally F222222222. If not, then find your client developer and let him find it for you.

Well, that's all for the article. If you have any questions during the development process later, please ask questions and private message me.

Guess you like

Origin blog.csdn.net/qq_31281245/article/details/126937283