在Android中使用MifareUltralight.transceive设置NTAG213密码会崩溃,不引发任何异常 [英] Setting NTAG213 password in Android with MifareUltralight.transceive crashes, no exception thrown

查看:178
本文介绍了在Android中使用MifareUltralight.transceive设置NTAG213密码会崩溃,不引发任何异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在空的NTAG213标签上设置密码,但是当我写PACK和PWD时,我的应用程序崩溃了,没有抛出异常.我确实使我的应用程序足够远,可以编写有效的NDEF消息并阅读它们,看来我也可以写入其他配置页(用于配置密码保护的2Ah和29h).但是,当我开始编写PACK时,我的应用程序崩溃了,但没有抛出MifareUltralight.transceive(byte [] data)所期望的IOException.

I'm trying to set a password on my empty NTAG213 tags, but when I get to writing the PACK and PWD my app just crashes, with no exception thrown. I did get my app far enough to write valid NDEF messages and read those, it seems I can also write to other configuration pages(2Ah and 29h for configurating the password protection). When I get to writing PACK though, my app crashes but doesn't throw the IOException I would expect from MifareUltralight.transceive(byte[] data).

这是我的writeAndProtect方法的源代码:

Here is the souce code for my writeAndProtect method:

private void writeAndProtectTag(final Intent intent, final String message) {
    // Run the entire process in its own thread as MifareUltralight.transceive(byte[] data);
    // Should not be run in main thread according to <https://developer.android.com/reference/android/nfc/tech/MifareUltralight.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 MifareUltralight and Ndef
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            MifareUltralight mifare = null;
            int debugCounter = 0;

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

                mifare.connect();
                while(!mifare.isConnected());
                byte[] response;

                // Authenticate with the tag first
                // In case it's already been locked
                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)) {
                        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(IOException e){
                    e.printStackTrace();
                }

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

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

            // 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.myname.myapplication");
                msg = new NdefMessage(r1, r2);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            // Generate Ndef object from tag object
            Ndef ndef = Ndef.get(tag);

            // Connect NDEF, write message and close connection
            try {
                ndef.connect();
                ndef.writeNdefMessage(msg);
                ndef.close();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (FormatException e) {
                e.printStackTrace();
            } catch (Exception e) {
                //Trying to catch any exception that may be thrown
                e.printStackTrace();
            }
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    btn.setImageResource(R.drawable.arrow_red);
                    tv.setText("");
                }
            });
            curAction = "handle";
        }
    })).start();
}

编辑:我不知道昨天Android Studio是否出了问题,或者您的解决方案是否确实改变了情况,但是我更新了代码,现在得到了以下异常:

EDIT: I don't know if something was wrong with Android Studio yesterday or if your solution actually changed the situation, but I updated the code and now get the following exception:

E/AndroidRuntime: FATAL EXCEPTION: Thread-4
                       Process: com.example.alex.nfcapppce, PID: 25918
                       java.lang.IllegalStateException: Close other technology first!
                           at android.nfc.Tag.setConnectedTechnology(Tag.java:458)
                           at android.nfc.tech.BasicTagTechnology.connect(BasicTagTechnology.java:78)
                           at android.nfc.tech.Ndef.connect(Ndef.java)
                           at com.example.alex.nfcapppce.MainActivity$2.run(MainActivity.java:194) //The line saying ndef.connect()
                           at java.lang.Thread.run(Thread.java:761)

我不太明白为什么会这样,因为首先我连接了mifare,等到它连接好之后,进行收发,关闭mifare,然后调用ndef.connect()块.这是否意味着我的收发块中的某处出现异常,因此我没有正确关闭mifare并无法打开ndef?这很奇怪,因为即使我只用Exception替换了IOException,也没有得到异常,所以无论类型如何,我都能捕获到每个异常.

I don't quite understand why this happpens, because first I connect the mifare, wait until it's connected, do my transceiving, close my mifare and after that the block with ndef.connect() is called. Does this mean somewhere in my transceiving block I get an Exception, therefore I'm not closing the mifare correctly and cannot open the ndef? That would be weird as I am not getting an exception even though I swapped out the IOException with just Exception so I catch every exception no matter the exact type.

编辑2 :现在,我了解了为什么应用程序在此异常中结束.该代码实际上有效,并且我的标签现在受密码保护,当我再次尝试使用同一标签时,我不首先进行身份验证,因此收发失败,从而导致try-catch块破裂,该块也包含close函数.我通过在整个Thread中使MifareUltralight对象可用并在运行ndef.connect()的部分之前将其关闭来解决此问题.

EDIT 2: I now get why the application is ending in this exception. The code actually works and my tag is now protected with the password, when I try to use the same tag again I dont authenticate first so the transceive fails, leading to a breaking of the try-catch block that would also contain the close function. I solved this by making the MifareUltralight object available in the whole Thread and closing it before running the ndef.connect()'s section.

现在(希望)我的最后一个问题是:我可以使用Ndef类进行身份验证吗?我的Ndef对象似乎没有身份验证方法,因此我将不得不再次使用MifareUltralight进行此操作.但是,当我关闭用于打开Ndef连接的MifareUltralight连接时,身份验证不会丢失吗?或者是我唯一的可能使用来在密码保护的标签上写Ndef消息 字符串,将它们切成4个字节的页面,然后使用MifareUltralight.writepage(byte [] addr,byte [] data)依次写入.当我使用上面的更新时,我从ndef.writeNdefMessage()得到IOException,我想这意味着关闭mifare连接也会导致我未经身份验证.

Now my (hopefully) last question is: Can I authenticate using the Ndef class? My Ndef object doesnt seem to have an authenticate method, so I would have to use MifareUltralight for this again. But when I close the MifareUltralight connection for opening the Ndef connection is the authentication not lost? Or is my only possibility to write Ndef messages on a password protected tag using Strings, cutting them into 4-byte pages and writing them one after the other using MifareUltralight.writepage(byte[] addr, byte[] data)? When I use the updated above I get an IOException from ndef.writeNdefMessage(), I guess this means closing the mifare connection also unauth'd me.

谢谢.

推荐答案

使用MifareUltralight技术时,您永远不会连接到标签.因此,调用mifare.transceive()将导致异常.您的应用程序崩溃,因为该异常可能不是IOException的实例(您会在代码中捕获到它).

You never connect to the tag when using the MifareUltralight technology. Consequently, calling mifare.transceive() will result in an exception. Your app crashes because this exception is probably not an instance of IOException (which you would have caught in your code).

因此,请务必致电

mifare.connect();

在收发任何命令之前,还请确保在此之后再次关闭该实例:

before you transceive any commands and also make sure to close the instance again after that:

try {
    mifare.close();
} catch (Exception ignored) {}

这篇关于在Android中使用MifareUltralight.transceive设置NTAG213密码会崩溃,不引发任何异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆