gpt4 book ai didi

javascript - 为 NfcV 标签创建自定义 Cordova 插件

转载 作者:行者123 更新时间:2023-11-29 18:05:39 24 4
gpt4 key购买 nike

我需要从 NfcV (ISO 15693) 标签中读取数据,我已经尝试过 Chariotsolution 的 Phonegap-Nfc 插件,但似乎这个插件只能读取 NfcV 标签中的 TagId 和 Type,所以我决定我可以创建我自己的自定义插件,我首先找到了 echo Hello World Plugin 教程,它运行良好且没有问题,所以我寻找 Java NfcV 阅读器并找到了这个 Java NfcV Reader .

据我目前的理解,我需要调用 cordova.exec 函数并从 CordovaPlugin 扩展我的 Java 类,它正在运行。

我不了解 Java,因为我是 Web 开发人员,这对我来说有点困难。

这实际上看起来不错,但我尝试以 Hello World 回显示例的方式实现它,但没有按计划进行。

我现在有一个插件文件夹

你好.java

    package org.apache.cordova.plugin;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;


/**
* This class echoes a string called from JavaScript.
*/
public class Hello extends CordovaPlugin
{
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if (action.equals("hello")) {
String message = args.getString(0);
this.hello(message, callbackContext);
return true;
}
return false;
}

private void hello(String message, CallbackContext callbackContext) {
if (message != null && message.length() > 0) {
callbackContext.success(message);
} else {
callbackContext.error("Expected one non-empty string argument.");
}
}
}

从上面的链接读取NfcV.java

    package org.apache.cordova.plugin;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;

import org.apache.http.util.ByteArrayBuffer;

import android.nfc.Tag;
import android.nfc.TagLostException;
import android.nfc.tech.NfcV;
import android.nfc.tech.TagTechnology;
//import android.os.Parcelable;
import android.util.Log;

/**
* @author uhahn
*
*/
public class ReadNfcV extends CordovaPlugin implements TagTechnology {
protected NfcV mynfcv;
// protected Tag mytag; // can be retrieved through mynfcv

private final String TAG=this.getClass().getName();
protected final int maxtries=3;

protected boolean isTainted=true; // Tag info already read?
protected byte[] mysysinfo=null; // NfcV SystemInformation - or generated
protected byte[] myuserdata=null; // buffer user content
protected boolean[] blocktainted; // true when block is to be uploaded to tag
protected byte[] blocklocked; // 0 means writable

protected byte afi=0;
public byte nBlocks=0;
public byte blocksize=0;
public byte[] Id;
public byte[] UID; // becomes valid when a real tag is contacted
public byte DSFID = -1;
public int maxtrans=0; // tag dependent max transceive length
public byte lastErrorFlags=-1; // re-set by each transceive
public byte lastErrorCode=-1; // re-set by each transceive
public byte manuByte=0;

public static final byte BYTE_IDSTART=(byte)0xe0;
public static final byte MANU_TAGSYS=0x04;
public static final HashMap<Byte,String> manuMap = new HashMap<Byte, String>();

static{
manuMap.put(MANU_TAGSYS, "TagSys");
}

/**
* read new NfcV Tag from NFC device
*/
public ReadNfcV(Tag t) {
UID = t.getId(); // sysinfo holds the UID in lsb order - Id will be filled lateron from sysinfo!
// Log.d(TAG,"getId: "+toHex(t.getId()));
mynfcv=NfcV.get(t);
try {
mynfcv.connect();
mysysinfo=getSystemInformation();
// explore Nfcv properties..
//initfields(); // done by getSys..

maxtrans=mynfcv.getMaxTransceiveLength();
DSFID=mynfcv.getDsfId();
Log.d(TAG,nBlocks + " x " + blocksize + " bytes");
blocklocked=new byte[nBlocks]; // init the lock shadow
getMultiSecStatus(0, nBlocks); // and fill from tag

blocktainted=new boolean[nBlocks];
taintblock(0,nBlocks);

// Log.d(TAG,"maxtrans "+maxtrans);
// init space for userdata ?
myuserdata= new byte[nBlocks*blocksize];
} catch (IOException e) {
// TODO Auto-generated catch block
lastErrorFlags=-1;
Log.d(TAG, "MyNfcV failed: "+e.getMessage());
e.printStackTrace();
}
}

/**
* recreate NfcV Tag from log
* @param sysinfo: the logged system info only
*/
public ReadNfcV(String sysinfo){
int startat=0;
sysinfo.toLowerCase(); // ignore case
if(sysinfo.startsWith("0x")){ // lets believe in HEX
startat=2;
}
mysysinfo=hexStringToByteArray(sysinfo.substring(startat));
initfields();
// init space for userdata TODO limit size?
//myuserdata= new byte[nBlocks*blocksize];
isTainted=false;
// TODO fake Tag? mytag = Tag.CREATOR.createFromParcel(???);
}

/**
* recreate NfcV Tag from log
* @param sysinfo: the logged system info
* @param userdata: the logged userdata
*/
public ReadNfcV(String sysinfo, String userdata){
this(sysinfo);
// TODO fake userdata
int startat=0;
userdata.toLowerCase(); // ignore case
if(userdata.startsWith("0x")){ // lets believe in HEX
startat=2;
}
myuserdata=hexStringToByteArray(userdata.substring(startat));
}

/**
* parse system information byte array into attributes
* with respect to the flags found
* DSFID
* AFI
* memsize values (block count and length)
*/
private void initfields(){
byte[] read=mysysinfo;
if((null!=read)&&(12<read.length)&&(0==read[0])){// no error
char flags=(char)read[1]; //s.charAt(1);

// String s=new String(read);
//s.substring(2, 9).compareTo(Id.toString()) // the same?
//set the Id from mysysinfo
int pos=2;
boolean forwardId=false; // the Id field is in lsb order
if(BYTE_IDSTART==read[pos]){
forwardId=true;
manuByte=read[pos+1];
}else if(BYTE_IDSTART==read[pos+7]){
manuByte=read[pos+6];
forwardId=false;
}else
Log.e(TAG,"Id start byte not found where expected");
if(null==Id){ // dont overwrite, if given
Id=new byte[8];
for(int i=0;i<8;i++)
// TODO decide if Id to be reversed (Zebra needs msb order, that is Id[7] changes between tags)
Id[i]=(forwardId? read[pos+i] : read[pos + 7 - i]); //reverse?!
Log.d(TAG,"Id from sysinfo (reversed): "+toHex(Id));
}

pos=10; // start after flags, Infoflags and Id TODO: change if transceive should eat up the error byte
if(0<(flags&0x1)){ // DSFID valid
pos++; // already implemented
}
if(0<(flags&0x2)){ // AFI valid
afi=(byte)read[pos++];//s.charAt(pos++);
}
if(0<(flags&0x4)){ // memsize valid
nBlocks=(byte)(read[pos++]+1);//(s.charAt(pos++)+1);
blocksize=(byte)(read[pos++]+1); //((s.charAt(pos++)&0x1f)+1);
}
}
}

/**
* @return the stored afi byte
*/
public byte getAFI(){
if(isTainted){ // system info not read yet
getSystemInformation(); // fill in the fields
}
return afi;
}

public byte getDsfId(){
// return mynfcv.getDsfId(); // avoid re-reading
return DSFID;
}

public int getblocksize(){
return (int)blocksize;
}

public int getnBlocks(){
return (int)nBlocks;
}

public byte[] getSystemInformation(){
if(isTainted){ // dont reread
mysysinfo=transceive((byte)0x2b);
isTainted=false; // remember: we have read it and found it valid
if(0==lastErrorFlags){// no error
isTainted=false; // remember: we have read it and found it valid
initfields(); // analyze
}}
return mysysinfo;
}

/**
* overload method transceive
* @return resulting array (or error?)
*/
protected byte[] transceive(byte cmd){
return transceive(cmd, -1, -1, null);
}

protected byte[] transceive(byte cmd, int m){
return transceive(cmd, m, -1, null);
}

protected byte[] transceive(byte cmd, int m ,int n){
return transceive(cmd, m, n, null);
}

/**
* prepare and run the command according to NfcV specification
* @param cmd command byte
* @param m command length
* @param n
* @param in input data
* @return
*/
protected byte[] transceive(byte cmd,int m, int n, byte[] in){
byte[] command;
byte[] res="transceive failed message".getBytes();

ByteArrayBuffer bab = new ByteArrayBuffer(128);
// flags: bit x=adressed,
bab.append(0x00);
bab.append(cmd); // cmd byte
// 8 byte UID - or unaddressed
// bab.append(mytag.getId(), 0, 8);
// block Nr
if(-1!=m)bab.append(m);
if(-1!=n)bab.append(n);
if(null!=in)bab.append(in, 0, in.length);

command=bab.toByteArray();
Log.d(TAG,"transceive cmd: "+toHex(command));
// Log.d(TAG,"transceive cmd length: "+command.length);

// TODO background!
try {
if(!mynfcv.isConnected()) return res;
for(int t=maxtries;t>0;t++){ // retry reading
res=mynfcv.transceive(command);
if(0==res[0]) break;
}
}
catch (TagLostException e){ //TODO roll back user action
Log.e(TAG, "Tag lost "+e.getMessage());
try {
mynfcv.close();
} catch (IOException e1) {
e1.printStackTrace();
}
return e.getMessage().getBytes();
}
catch (IOException e) {
Log.d(TAG, "transceive IOEx: "+e.getMessage()+toHex(res));
// e.printStackTrace();
return e.getMessage().getBytes();
}
finally{
Log.d(TAG,"getResponseFlags: "+mynfcv.getResponseFlags());
lastErrorFlags=res[0];
Log.d(TAG,"Flagbyte: "+String.format("%2x", lastErrorFlags));
if(0!=lastErrorFlags){
lastErrorCode=res[1];
Log.d(TAG,"ErrorCodebyte: "+String.format("%2x", lastErrorCode));
}
}

if(0==mynfcv.getResponseFlags())
return (res);
else
// return new String("response Flags not 0").getBytes();
return res;
}


public void taintblock(int i, int n){
for(int j=0;j<n;j++)
setblocktaint(j,true);
}

public void taintblock(int i){
setblocktaint(i,true);
}

protected void setblocktaint(int i, boolean b){
blocktainted[i]=b;
}


/* (non-Javadoc)
* @see android.nfc.tech.TagTechnology#getTag()
*
*/
@Override
public Tag getTag() {
// TODO Auto-generated method stub
//return mytag;
return mynfcv.getTag();
}

/* (non-Javadoc)
* @see android.nfc.tech.TagTechnology#close()
*/
@Override
public void close() throws IOException {
try {
mynfcv.close();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d(TAG, "close failed: "+e.getMessage());
e.printStackTrace();
}
}

/* (non-Javadoc)
* @see android.nfc.tech.TagTechnology#connect()
*/
@Override
public void connect() throws IOException {
try {
mynfcv.connect();
} catch (IOException e) {
lastErrorFlags=-1; // TODO discriminate error states
Log.d(TAG,"connect failed: "+e.getMessage());
e.printStackTrace();
}
}

/* (non-Javadoc)
* @see android.nfc.tech.TagTechnology#isConnected()
*/
@Override
public boolean isConnected() {
// TODO Auto-generated method stub
// mynfcv.getDsfId();
return mynfcv.isConnected(); // better?
}

public byte[] readSingleBlock(int i){
byte[] read=transceive((byte)0x20,i);

setblocktaint(i,false); // remember we read this block
if(0!=lastErrorFlags)return read; // TODO not so ignorant..

byte[] res=new byte[read.length-1]; // drop the (0) flag byte TODO: in transceive?
for (int l = 0; l < read.length-1; l++) {
res[l]=read[l+1];
myuserdata[i*blocksize+l]=res[l]; // sort block into our buffer
}

return res;

}

/**
*
* @param i starting block number
* @param j block count
* @return block content concatenated
*/
public byte[] readMultipleBlocks(int i,int j){
if(0==blocksize){
Log.e(TAG,"readMult w/o initfields?");
getSystemInformation(); // system info was not read yet
}

byte[] read = transceive((byte)0x23,i,j);
if(0!=read[0])return read; // error flag set: TODO left as exercise..

byte[] res=new byte[read.length-1]; // drop the (0) flag byte
for (int l = 0; l < read.length-1; l++) {
res[l]=read[l+1];
myuserdata[i*blocksize+l]=res[l]; // sort block into our buffer
}

if(res.length<j*blocksize) return read; // da fehlt was
for (int k = i; k < j; k++) { // all blocks we read
setblocktaint(k, false); // untaint blocks we read
// @TODO reverting block order should be done on demand - or under user control (done again in DDMData)
// reverse(res,k*blocksize,blocksize); // swap string positions
}
return res;
}

public byte[] getMultiSecStatus(int i,int n){
byte[] read = transceive((byte)0x2c,i,n-1);
Log.d(TAG,"secstatus "+toHex(read));
if(0!=read[0])return read;
int startat=1; // TODO transceive will skip the error field soon

for(int j=0;j<nBlocks;j++)
blocklocked[j]=read[startat+i+j];

return read;
}



/**
* move anywhere to utils
* @param s
* @return
*/

public static String toHex(byte[] in){
String text=String.format("0x");
for (byte element : in) {
text=text.concat(String.format("%02x", element));
}
return text;
}


public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}

我的 hello.js 文件

        var hello = {
world: function(str, callback) {
cordova.exec(callback, function(err) {
callback('Nothing to hello.');
}, "Hello", "hello", [str]);
}
}

var ReadNfcV = {
read: function (str, callback) {
cordova.exec(callback, function (err) {
callback('Nothing to hello.');
}, "Hello", "hello", [str]);
}
}

module.exports = hello;
module.exports = ReadNfcV;

和我的 plugin.xml

  <?xml version="1.0" encoding="UTF-8"?>

<plugin xmlns="http://cordova.apache.org/ns/plugins/1.0"
id="org.apache.cordova.plugin"
version="0.1.0">


<js-module src="hello.js" name="hello">
<clobbers target="hello" />
</js-module>

<!-- Android -->
<platform name="android">
<source-file src="Hello.java" target-dir="src/org/apache/cordova/plugin" />
<source-file src="ReadNfcV.java" target-dir="src/org/apache/cordova/plugin" />

<config-file target="res/xml/config.xml" parent="/*">
<feature name="Hello" >
<param name="android-package" value="org.apache.cordova.plugin.Hello"/>
</feature>
</config-file>
</platform>
</plugin>

我能够部署该应用程序,因此我可以进行一些测试,我的问题是我不太了解如何通过 javascript 从我的应用程序中调用 ReadNfcV.java 文件中的 ReadNfc 类。我只是做了与教程中相同的操作,但现在 hello.World 函数不再是一个函数,所以我想我在我的 hello.js 文件中做错了。如果有人可以帮助并解释我如何通过 javascript 调用我的 java 类,然后将 java 类的结果返回给我的 javascript,我将非常感激。我花了 2 天时间寻找一个已经存在的插件,但除了 phonegap-nfc 插件外,没有找到任何关于该主题的内容。

亲切的问候克里斯托弗

更新第一天

我将 tech.NfcV 添加到导入列表

import android.nfc.tech.NfcV;

按照建议更改了执行函数

@Override
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {

Log.d(TAG, "execute " + action);

if (!getNfcStatus().equals(STATUS_NFC_OK)) {
callbackContext.error(getNfcStatus());
return true; // short circuit
}

createPendingIntent();


if (action.equals(REGISTER_DEFAULT_TAG)) {
addTechList(new String[]{NfcV.class.getName()}); //changed this form Mifare to NfcV
registerDefaultTag(callbackContext);


} else if (action.equalsIgnoreCase(INIT)) {
init(callbackContext);

} else {
// invalid action
return false;
}

return true;
}

问题似乎是我现在返回了无效的操作,所以这里出了点问题

我将 registerDefault 函数更改为

private void registerDefaultTag(CallbackContext callbackContext) {
addTechFilter();
callbackContext.success();
}

我将解析消息函数更改为

void parseMessage() {
cordova.getThreadPool().execute(new Runnable() {
@Override
public void run() {
Log.d(TAG, "parseMessage " + getIntent());
Intent intent = getIntent();
String action = intent.getAction();
Log.d(TAG, "action " + action);
if (action == null) {
return;
}
if (action.equals(NfcAdapter.ACTION_TECH_DISCOVERED) || action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)){

Tag tagFromIntent = (Tag)intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
NfcV mfc = NfcV.get(tagFromIntent);
fireTagEvent(tag);

}

/*if (action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)) {
Ndef ndef = Ndef.get(tag);
fireNdefEvent(NDEF_MIME, ndef, messages);

} else if (action.equals(NfcAdapter.ACTION_TECH_DISCOVERED)) {
for (String tagTech : tag.getTechList()) {
Log.d(TAG, tagTech);
if (tagTech.equals(NdefFormatable.class.getName())) {
fireNdefFormatableEvent(tag);
} else if (tagTech.equals(Ndef.class.getName())) { //
Ndef ndef = Ndef.get(tag);
fireNdefEvent(NDEF, ndef, messages);
}
}
}

if (action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)) {
fireTagEvent(tag);
}*/

setIntent(new Intent());
}
});
}

因此,目前我在单击开始监听并在 Javascript atm 中调用 Taglisteners 时立即收到错误无效操作,我使用所有 4 个不同的监听器来查看是否有任何工作。看来我需要编写一个特定于 NfcV 的新 fireEvent 函数,因为现有函数无法正常工作

更新 2

我已经成功地编译了插件并部署了应用程序,但是没有任何反应,我没有得到 Tag 对象

解析消息函数

void parseMessage() {
cordova.getThreadPool().execute(new Runnable() {
@Override
public void run() {
Log.d(TAG, "parseMessage " + getIntent());
Intent intent = getIntent();
String action = intent.getAction();
Log.d(TAG, "action " + action);
if (action == null) {
return;
}
if (action.equals(NfcAdapter.ACTION_TECH_DISCOVERED) || action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)){
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if(tag != null){
byte[] id = tag.getId();
// set up read command buffer
byte blockNo = 0; // block address
byte[] readCmd = new byte[3 + id.length];
readCmd[0] = 0x20; // set "address" flag (only send command to this tag)
readCmd[1] = 0x20; // ISO 15693 Single Block Read command byte

System.arraycopy(id, 0, readCmd, 2, id.length); // copy ID
readCmd[2 + id.length] = blockNo; // 1 byte payload: block address

NfcV tech = NfcV.get(tag);
if (tech != null) {
// send read command
try {
tech.connect();
byte[] data = tech.transceive(readCmd);
fireTagEvent(data);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
tech.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

setIntent(new Intent());
}


}
});
}

我的 fireTagEvent

private void fireTagEvent(byte[] data) {

String s2 = new String(data);
String command = MessageFormat.format(javaScriptEventTemplate, TAG_DEFAULT, s2);
Log.v(TAG, s2);
this.webView.sendJavascript(s2);

}

执行函数

@Override
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {

Log.d(TAG, "execute " + action);

if (!getNfcStatus().equals(STATUS_NFC_OK)) {
callbackContext.error(getNfcStatus());
return true; // short circuit
}

createPendingIntent();


if (action.equals(REGISTER_DEFAULT_TAG)) {
addTechList(new String[]{NfcV.class.getName()});
registerDefaultTag(callbackContext);


} else if (action.equalsIgnoreCase(INIT)) {
init(callbackContext);

} else {
// invalid action
return false;
}

return true;
}

应用程序启动时差不多就是这样,“addTagDiscoveredListener”已注册,但我没有取回任何对象,所以要么 nfcv 标签未被读取,要么我只是没有取回任何东西,我不太确定...

最佳答案

我使用 Chariotsolution 插件作为构建我自己的 nfc 阅读插件的开始。如果您不从头开始,我认为这会为您节省很多时间。

有很多东西你可以删除,因为原始插件只处理 NDEF 标签,但是删除行比重新发明轮子要快。

我的脑子有点老了,所以我不确定我是否能正确解释所有事情......我需要阅读 Mifare 经典标签中的信息,但也许您可以根据自己的需要进行调整...因此,如果您查看 NfcPlugin.java,在执行函数中,我只保留了 REGISTER_DEFAULT_TAG 和 INIT 操作的代码。

更新了 REGISTER_DEFAULT_TAG 中的代码以注册监听 mifare 经典标签。并修改了 registerDefaultTag 函数以调用 addTechFilter 而不是 addTagFilter。

所以这给我们留下了public boolean execute(String action, JSONArray data, CallbackContext callbackContext) 抛出 JSONException {

    Log.d(TAG, "execute " + action);

if (!getNfcStatus().equals(STATUS_NFC_OK)) {
callbackContext.error(getNfcStatus());
return true; // short circuit
}

createPendingIntent();


if (action.equals(REGISTER_DEFAULT_TAG)) {
addTechList(new String[]{MifareClassic.class.getName()});
registerDefaultTag(callbackContext);


} else if (action.equalsIgnoreCase(INIT)) {
init(callbackContext);

} else {
// invalid action
return false;
}

return true;
}
private void registerDefaultTag(CallbackContext callbackContext) {
addTechFilter();
callbackContext.success();
}

现在您需要了解的是,一旦您从 js 调用了 init 函数,每次设备看到 nfc 标签时都会调用插件的 parseMessage 函数。

所以在parseMessage函数中我有一个测试

if (action.equals(NfcAdapter.ACTION_TECH_DISCOVERED) || action.equals(NfcAdapter.ACTION_TAG_DISCOVERED))

我拥有处理我的标签的所有代码。

在该代码中,可以使用如下内容从意图中的标签获取信息:

            Tag tagFromIntent  = (Tag)intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
MifareClassic mfc = MifareClassic.get(tagFromIntent);

然后根据您的处理,您可以调用 fireErrorEvent 或 fire...您自己的事件,使用 webView.sendJavascript 函数将数据返回到 javascript。

我没时间详细介绍 js 部分了。

不确定它是否对您有帮助,或者它是否是您想要的方式(不知道您使用的标签是如何工作的)。让我知道它是否对您有帮助,以及您是否需要更多详细信息。

关于javascript - 为 NfcV 标签创建自定义 Cordova 插件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31455480/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com