NfcA.transceive(byte [] data)throws TagLostException

问题描述:

它全部开始here。那边的问题解决了,现在我面临使用收发方法的问题。NfcA.transceive(byte [] data)throws TagLostException

我的代码如下所示:

private void writeAndProtectTag(final Intent intent, final String message) { 
    // Run the entire process in its own thread as NfcA.transceive(byte[] data); 
    // Should not be run in main thread according to <https://developer.android.com/reference/android/nfc/tech/NfcA.html#transceive(byte[])> 
    (new Thread(new Runnable() { 
     // Password has to be 4 characters 
     // Password Acknowledge has to be 2 characters 
     byte[] pwd  = "-_bA".getBytes(); 
     byte[] pack  = "cC".getBytes(); 

     @Override 
     public void run() { 
      // Store tag object for use in NfcA and Ndef 
      Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 
      // Using NfcA instead of MifareUltralight should make no difference in this method 
      NfcA nfca = null; 

      // Whole process is put into a big try-catch trying to catch the transceive's IOException 
      try { 
       nfca = NfcA.get(tag); 

       nfca.connect(); 

       byte[] response; 

       // Authenticate with the tag first 
       // In case it's already been locked 
       try { 
        response = nfca.transceive(new byte[]{ 
          (byte) 0x1B, // PWD_AUTH 
          pwd[0], pwd[1], pwd[2], pwd[3] 
        }); 

        // Check if PACK is matching expected PACK 
        // This is a (not that) secure method to check if tag is genuine 
        if ((response != null) && (response.length >= 2)) { 
         byte[] packResponse = Arrays.copyOf(response, 2); 
         if (!(pack[0] == packResponse[0] && pack[1] == packResponse[1])) { 
          Toast.makeText(ctx, "Tag could not be authenticated:\n" + packResponse.toString() + "≠" + pack.toString(), Toast.LENGTH_LONG).show(); 
         } 
        } 
       }catch(TagLostException e){ 
        e.printStackTrace(); 
       } 

       // Get Page 2Ah 
       response = nfca.transceive(new byte[] { 
         (byte) 0x30, // READ 
         (byte) 0x2A // page address 
       }); 
       // configure tag as write-protected with unlimited authentication tries 
       if ((response != null) && (response.length >= 16)) { // read always returns 4 pages 
        boolean prot = false;        // false = PWD_AUTH for write only, true = PWD_AUTH for read and write 
        int authlim = 0;         // 0 = unlimited tries 
        nfca.transceive(new byte[] { 
          (byte) 0xA2, // WRITE 
          (byte) 0x2A, // page address 
          (byte) ((response[0] & 0x078) | (prot ? 0x080 : 0x000) | (authlim & 0x007)), // set ACCESS byte according to our settings 
          0, 0, 0                   // fill rest as zeros as stated in datasheet (RFUI must be set as 0b) 
        }); 
       } 
       // Get page 29h 
       response = nfca.transceive(new byte[] { 
         (byte) 0x30, // READ 
         (byte) 0x29 // page address 
       }); 
       // Configure tag to protect entire storage (page 0 and above) 
       if ((response != null) && (response.length >= 16)) { // read always returns 4 pages 
        int auth0 = 0;         // first page to be protected 
        nfca.transceive(new byte[] { 
          (byte) 0xA2, // WRITE 
          (byte) 0x29, // page address 
          response[0], 0, response[2],    // Keep old mirror values and write 0 in RFUI byte as stated in datasheet 
          (byte) (auth0 & 0x0ff) 
        }); 
       } 

       // Send PACK and PWD 
       // set PACK: 
       nfca.transceive(new byte[] { 
         (byte)0xA2, 
         (byte)0x2C, 
         pack[0], pack[1], 0, 0 // Write PACK into first 2 Bytes and 0 in RFUI bytes 
       }); 
       // set PWD: 
       nfca.transceive(new byte[] { 
         (byte)0xA2, 
         (byte)0x2B, 
         pwd[0], pwd[1], pwd[2], pwd[3] // Write all 4 PWD bytes into Page 43 
       }); 

       // Generate NdefMessage to be written onto the tag 
       NdefMessage msg = null; 
       try { 
        NdefRecord r1 = NdefRecord.createMime("text/plain", message.getBytes("UTF-8")); 
        NdefRecord r2 = NdefRecord.createApplicationRecord("com.example.alex.nfcapppcekunde"); 
        msg = new NdefMessage(r1, r2); 
       } catch (UnsupportedEncodingException e) { 
        e.printStackTrace(); 
       } 

       byte[] ndefMessage = msg.toByteArray(); 

       nfca.transceive(new byte[] { 
         (byte)0xA2, // WRITE 
         (byte)3, // block address 
         (byte)0xE1, (byte)0x10, (byte)0x12, (byte)0x00 
       }); 

       // wrap into TLV structure 
       byte[] tlvEncodedData = null; 

       tlvEncodedData = new byte[ndefMessage.length + 3]; 
       tlvEncodedData[0] = (byte)0x03; // NDEF TLV tag 
       tlvEncodedData[1] = (byte)(ndefMessage.length & 0x0FF); // NDEF TLV length (1 byte) 
       System.arraycopy(ndefMessage, 0, tlvEncodedData, 2, ndefMessage.length); 
       tlvEncodedData[2 + ndefMessage.length] = (byte)0xFE; // Terminator TLV tag 

       // fill up with zeros to block boundary: 
       tlvEncodedData = Arrays.copyOf(tlvEncodedData, (tlvEncodedData.length/4 + 1) * 4); 
       for (int i = 0; i < tlvEncodedData.length; i += 4) { 
        byte[] command = new byte[] { 
          (byte)0xA2, // WRITE 
          (byte)((4 + i/4) & 0x0FF), // block address 
          0, 0, 0, 0 
        }; 
        System.arraycopy(tlvEncodedData, i, command, 2, 4); 
        try { 
         response = nfca.transceive(command); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
       } 
       runOnUiThread(new Runnable() { 
        @Override 
        public void run() { 
         //UI related things, not important for NFC 
         btn.setImageResource(R.drawable.arrow_red); 
         tv.setText(""); 
        } 
       }); 
       curAction = "handle"; 

       try { 
        nfca.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 

      } catch (IOException e) { 
       //Trying to catch any ioexception that may be thrown 
       e.printStackTrace(); 
      } catch (Exception e) { 
       //Trying to catch any exception that may be thrown 
       e.printStackTrace(); 
      } 

     } 
    })).start(); 
} 

,所用Ndef类写上,我没有这个问题的标签我的旧代码版本。现在,我改变了一些东西,我获得两个TagLostException S:

  • 一个从线PWD_AUTH命令失败,但它的异常被捕获,这实际上是打算作为标签我扫描没有密码尚未设置。
  • 另一个来自读取配置的收发器。

在第二个TagLostException之后,该方法当然结束。阅读配置时,我不应该得到TagLostException。有人知道那里发生了什么吗?

这里的例外:

android.nfc.TagLostException: Tag was lost. 
          at android.nfc.TransceiveResult.getResponseOrThrow(TransceiveResult.java:48) 
          at android.nfc.tech.BasicTagTechnology.transceive(BasicTagTechnology.java:151) 
          at android.nfc.tech.NfcA.transceive(NfcA.java:129) 
          at com.example.alex.nfcapppce.MainActivity$2.run(MainActivity.java:134) 
          at java.lang.Thread.run(Thread.java:761) 
    android.nfc.TagLostException: Tag was lost. 
          at android.nfc.TransceiveResult.getResponseOrThrow(TransceiveResult.java:48) 
          at android.nfc.tech.BasicTagTechnology.transceive(BasicTagTechnology.java:151) 
          at android.nfc.tech.NfcA.transceive(NfcA.java:129) 
          at com.example.alex.nfcapppce.MainActivity$2.run(MainActivity.java:155) 
          at java.lang.Thread.run(Thread.java:761) 

解决:

当试图与不具有保护尚未通信刚刚崩溃抛出一个适当的异常赶上,而不是一个标签进行身份验证,因为我我没有注意到应用程序继续尝试收发数据的异常,但标签“丢失了”,因为现在称为Exception是告诉我的。

要知道,如果标签已受到保护,检查Auth0为集保护:

byte[] response; 

//Read page 41 on NTAG213, will be different for other tags 
response = mifare.transceive(new byte[] { 
     (byte) 0x30, // READ 
     41   // page address 
}); 
// Authenticate with the tag first 
// only if the Auth0 byte is not 0xFF, 
// which is the default value meaning unprotected 
if(response[3] != (byte)0xFF) { 
    try { 
     response = mifare.transceive(new byte[]{ 
       (byte) 0x1B, // PWD_AUTH 
       pwd[0], pwd[1], pwd[2], pwd[3] 
     }); 
     // Check if PACK is matching expected PACK 
     // This is a (not that) secure method to check if tag is genuine 
     if ((response != null) && (response.length >= 2)) { 
      final byte[] packResponse = Arrays.copyOf(response, 2); 
      if (!(pack[0] == packResponse[0] && pack[1] == packResponse[1])) {runOnUiThread(new Runnable() { 
       @Override 
       public void run() { 
        Toast.makeText(ctx, "Tag could not be authenticated:\n" + packResponse.toString() + "≠" + pack.toString(), Toast.LENGTH_LONG).show(); 
       } 
      }); 
      }else{ 
       runOnUiThread(new Runnable() { 
        @Override 
        public void run() { 
         Toast.makeText(ctx, "Tag successfully authenticated!", Toast.LENGTH_SHORT).show(); 
        } 
       }); 
      } 
     } 
    } catch (TagLostException e) { 
     e.printStackTrace(); 
    } 
}else{ 
    // Protect tag with your password in case 
    // it's not protected yet 

    // Get Page 2Ah 
    response = mifare.transceive(new byte[] { 
      (byte) 0x30, // READ 
      (byte) 0x2A // page address 
    }); 
    // configure tag as write-protected with unlimited authentication tries 
    if ((response != null) && (response.length >= 16)) { // read always returns 4 pages 
     boolean prot = false;        // false = PWD_AUTH for write only, true = PWD_AUTH for read and write 
     int authlim = 0;         // 0 = unlimited tries 
     mifare.transceive(new byte[] { 
       (byte) 0xA2, // WRITE 
       (byte) 0x2A, // page address 
       (byte) ((response[0] & 0x078) | (prot ? 0x080 : 0x000) | (authlim & 0x007)), // set ACCESS byte according to our settings 
       0, 0, 0                   // fill rest as zeros as stated in datasheet (RFUI must be set as 0b) 
     }); 
    } 
    // Get page 29h 
    response = mifare.transceive(new byte[] { 
      (byte) 0x30, // READ 
      (byte) 0x29 // page address 
    }); 
    // Configure tag to protect entire storage (page 0 and above) 
    if ((response != null) && (response.length >= 16)) { // read always returns 4 pages 
     int auth0 = 0;         // first page to be protected 
     mifare.transceive(new byte[] { 
       (byte) 0xA2, // WRITE 
       (byte) 0x29, // page address 
       response[0], 0, response[2],    // Keep old mirror values and write 0 in RFUI byte as stated in datasheet 
       (byte) (auth0 & 0x0ff) 
     }); 
    } 

    // Send PACK and PWD 
    // set PACK: 
    mifare.transceive(new byte[] { 
      (byte)0xA2, 
      (byte)0x2C, 
      pack[0], pack[1], 0, 0 // Write PACK into first 2 Bytes and 0 in RFUI bytes 
    }); 
    // set PWD: 
    mifare.transceive(new byte[] { 
      (byte)0xA2, 
      (byte)0x2B, 
      pwd[0], pwd[1], pwd[2], pwd[3] // Write all 4 PWD bytes into Page 43 
    }); 
} 

您尝试读取任何数据之前进行身份验证的标签。根据您使用的特定Android设备,如果身份验证失败,您将收到NACK响应或IOException(通常但不总是(?),TagLostException)。在你目前忽略此错误两种情况下(你放下例外,你只处理成功的结果((response != null) && (response.length >= 2)),因此,您的代码(并保持)处于错误状态时,认证失败。

因此,您需要妥善处理。这些错误条件通常情况下,你将要关闭并重新打开后,每一个错误的连接(NACK响应,响应nullIOException),你可以很容易地实现这在您的代码:

nfca.connect(); 

byte[] response; 
boolean authError = true; 

// Authenticate with the tag first 
try { 
    response = nfca.transceive(new byte[]{ 
      (byte) 0x1B, // PWD_AUTH 
      pwd[0], pwd[1], pwd[2], pwd[3] 
    }); 

    // Check if PACK is matching expected PACK 
    if ((response != null) && (response.length >= 2)) { 
     authError = false; 

     [...] 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
} 

if (authError) { 
    try { 
     nfca.close(); 
    } catch (Exception ignored) {} 
    nfca.connect(); 
} 

// Get Page 2Ah 
response = nfca.transceive(new byte[] { 
     (byte) 0x30, // READ 
     (byte) 0x2A // page address 
}); 

[...]