SecurityException while ndef.connect() on Android 13
Asked Answered
M

2

6

I have this code (Java) to write nfc tags:

private Tag tag;

@Override
protected void onNewIntent(Intent intent) {
    if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
        tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    }
}

private boolean write(String message, Tag tag) throws IOException, FormatException {
    Ndef ndef = Ndef.get(tag);
    ndef.connect();
    if (ndef.isWritable()) {
        ndef.writeNdefMessage(message);
    }
    ndef.close();
}

Said code was working until I updated my app to be compatible with the latest versions of Android.

Now running this code on Android 13 gives me the following exception:

java.lang.SecurityException: Permission Denial: Tag ( ID: XX XX XX XX XX XX XX ) is out of date
    at android.nfc.Tag.getTagService(Tag.java:388)
    at android.nfc.tech.BasicTagTechnology.connect(BasicTagTechnology.java:73)
    at android.nfc.tech.Ndef.connect(Ndef.java:71)

I understand that there is some compatibility problem but I don't know what exactly.

I am thankful for any kind of help.

UPDATE: Thanks to your feedback and some additional research I came to a solution.

I was triggering this NFC write from the onNewIntent function. It seems that it is no longer possible due to some security issues. I solved it by triggering this NFC write from the onResume function instead.

Thank you all for your help.

Mallette answered 10/3, 2023 at 11:37 Comment(4)
Could you reveal how you receive your tag handle and where you pass it around in your code?Faeroese
I edited the code block to show how I get de Tag handler from the intent.Mallette
This Github issue about this same problem might be usefulBaseline
This seems a logical change as you should not been trying to use old Tag Objects when you should have been dispatched a new one to handle. I note the that Android Bug that @Jorn Rigter indirrect linked to has been closed as won't fix. So I've created a new documentation bug issuetracker.google.com/issues/272552420 to cover the fact that the NFC documentation does not reference this new ExceptionGesner
M
0

It seems that on Android 13 you should manage NFC writing once the onResume() was called. I resolved it moving NFC writing from onNewIntent() to onResume().

Mallette answered 15/3, 2023 at 7:42 Comment(2)
how did you get intent object in onResume?Lindstrom
I don't think the moving write method to another place is relevant. make sure you read michael answerJerkwater
F
6

This is intended by design. The problem here is that you store a tag handle and try to use it later on (maybe even after letting the user press a button or so?). You should never have done this in the first place, NFC is user interaction and you should act immediately upon scanning the tag and keep the transaction as short as possible (after all user's are not good at holding two devices constantly together for a longer period). Android finally reduced the surface of bad programming habits in that regard (see here) by making sure that your tag handle is current when you try to access a tag. This change prevents access to an invalidated tag handle once tag disconnection or a new tag discovery takes place.

Faeroese answered 12/3, 2023 at 20:18 Comment(4)
And the documentation issue I raised (issuetracker.google.com/issues/272552420) has now been marked as fixed in Android 14, so people should be aware that accessing an old Tag object won't work.Gesner
@Gesner what about android 13? Do you have any solution that no needed upgrade to Android 14?Transmute
@Anh Luu The solution is the same for 12L upwards, catch the SecurityException or generically catch all Exceptions, the issue I raised was only about documenting this new behaviour in 12L and google just took their time to release the correct documentationGesner
What is the solution?Drais
M
0

It seems that on Android 13 you should manage NFC writing once the onResume() was called. I resolved it moving NFC writing from onNewIntent() to onResume().

Mallette answered 15/3, 2023 at 7:42 Comment(2)
how did you get intent object in onResume?Lindstrom
I don't think the moving write method to another place is relevant. make sure you read michael answerJerkwater

© 2022 - 2024 — McMap. All rights reserved.