简体   繁体   中英

android NFC tag activity doesn't disappear after the NFC tag is no longer being detected

I'm detecting NFC tags for my game (made in Unity). In the game the player detects NFC tag and it shows him/her something (button, text, ...). And I would like to make that thing disappear if the player is no longer next to the tag.

The problem is that even if I remove the NFC tag from the reach of the NFC reader (put the tag away from the phone) it returns the same _mActivity as if the tag was still there.

So my question is if there is a way how to remove the once read activity? or is there better way to detect if the tag is really there?

my code:

void FixedUpdate()
{
    string newTagOutput = DetectNFCTag();
    ...
}
string DetectNFCTag()
{
    try
    {
        // Create new NFC Android object
        AndroidJavaObject _mActivity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity");
        AndroidJavaObject _mIntent = _mActivity.Call<AndroidJavaObject>("getIntent");
        string _sAction = _mIntent.Call<String>("getAction"); 

        if (_sAction == "android.nfc.action.NDEF_DISCOVERED")
        {
            AndroidJavaObject[] rawMsg = _mIntent.Call<AndroidJavaObject[]>("getParcelableArrayExtra", "android.nfc.extra.NDEF_MESSAGES");
            AndroidJavaObject[] records = rawMsg[0].Call<AndroidJavaObject[]>("getRecords");
            byte[] payLoad = records[0].Call<byte[]>("getPayload");
            string result = System.Text.Encoding.Default.GetString(payLoad);

            result = result.Remove(0, 3); // removes information about language "en..."
            return result;
        }
    }
    catch (Exception ex) {...}

    return null;
}

Android manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="preferExternal"
android:versionCode="1"
android:versionName="1.0">

<uses-permission android:name="android.permission.NFC" />

<uses-feature
  android:name="android.hardware.nfc"
  android:required="true" />

<uses-sdk android:minSdkVersion="21"/>

<supports-screens
    android:smallScreens="true"
    android:normalScreens="true"
    android:largeScreens="true"
    android:xlargeScreens="true"
    android:anyDensity="true"/>

<application
    android:theme="@style/UnityThemeSelector"
    android:icon="@drawable/app_icon"
    android:label="@string/app_name">
    <activity android:name="com.unity3d.player.UnityPlayerActivity"
              android:label="@string/app_name"
              android:launchMode="singleTask">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.nfc.action.NDEF_DISCOVERED" />
            <action android:name="android.nfc.action.TECH_DISCOVERED" />
            <action android:name="android.nfc.action.TAG_DISCOVERED" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
        <meta-data android:name="android.nfc.action.TECH_DISCOVERED" android:resource="@xml/nfc_tech_filter" android:value="true" />
    </activity>
</application>

There is no direct way to detect when a NFC Tag is removed out of range in Android (there is an indirect way).

There are a number of different ways to interact with a NFC Tag in Android but the way you seem to be doing it is the most basic.

With all methods the Android NFC system service detects the Tag and by default it will fully reads any NDEF data off the Tag.

At this point the once the Android NFC system service has read all the NDEF data off the Tag then the Tag can be moved out of range with no affect on the process as all NDef data has been extracted and stored.

The Android NFC system service then decides who to send this Ndef data to and then starts the appropriate Android Activity and passes it this static NDef data (there is no link to the Tag with the Ndef Data and no I/O operations will be performed to the Tag when you look at this static data).

Now how to do it the indirect way.

(Sorry not a Unity expert)

Instead of asking Android for the preparsed Ndef data from the Intent you can ask for a Tag object which is a direct link to the Nfc Tag.

This is in the getParcelableArrayExtra of android.nfc.extra.TAG

From this generic Tag object you can convert it to an NDef Tag object.

In Java terms this is Ndef.get(Tag) and will be non null if the Tag is of Ndef Type.

From there you can call getNdefMessage on this Ndef Tag object and this will cause an I/O operation to happen to the Tag.

If the Tag is out of range this I/O operation will fail with an Exception ( TagLostException or IOException or FormatException ) which can be caught.

Thus to detect if a Tag has been moved out of range you need to keep doing an I/O operation in a loop until you get an Exception which will mean the Tag is out of range to read.

Note you should never do Tag I/O operations on the main UI thread, especially if you are doing them in a loop as the App will freeze.

I would at the Android level use enableReaderMode instead of the Intent based method as you automatic get the Tag object in a new thread for this.

Sorry I don't know how to do enableReaderMode in Unity.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM