top of page
Search
Travis Willis

NFC in Unity (2018)

This is a paper written for a project I did for my work with the York Regional Police. It is from 2018, and as far as I know the project no longer uses this method as they don't use Unity anymore. The info to get this to actually work was difficult to find, but I used these resources:


Android Development Documentation https://developer.android.com/


Pablo Martinez of Twinsprite, also the code this plugin is based on.


This code by Francesco Azzola. He came up in many different places as well.


I do not know Java, so muddling through that code and the Android Development Documentation, I made this write up to explain the code, how it works, and what we planned to do with it. Plus the data it collected. I'm absolutely certain there is a better way to do this.


Project Summary

AWDAWDCEWW is a metagame platform that contains many minigames linked together under the theme of superheroes. The project is being created for the York Regional Police in Ontario, Canada. Together we are trying to promote community engagement and communication between children and police officers. A main pillar to this project is NFC capability. This technology will allow us to initiate “agents” into a “league” and issue membership cards to them. This card holds their agent number and a point value. These points are gathered by playing minigames. They are then brought to a central location to put them toward a community goal. The card can also be used for many other things, such as registering event participation for special bonus in games, or a digital version of police officer “baseball cards”.


What is NFC?

So what is NFC[1] ? Near Field Communication is a technology that allows for quick, local, wireless data transmission between two devices. In some places, it has already seen use as a payment method, such as “Tapping” your bank card onto a terminal to process your card info. Apple Pay is a similar system. We also see NFC get used on public transit, where passengers tap their transit passes on and off.


This works when a terminal emits a wireless field. When the chip, or “tag” enters the field it becomes activated and the electronics emit a signal. This signal is picked up by the terminal and magic happens. For example, you have a bus pass with an NFC chip in it. You hop on the bus and press the card against the terminal. The chip is charged by the terminal’s wireless field and it sends out a signal. This signal contains a unique chip ID, a format ID, and a package of data. This could be your pass number, or your account number with the transit organization. The terminal detects the signal and takes all the data, finds the account linked to your pass in a database, subtracts funds, registers the event, then gives you some indication the transaction happened. This interaction happens in less than a second; it’s quick, easy, and best of all it is simple.


How We Use NFC

For our purposes NFC hits all the marks. Its simplicity makes it easy for children to understand. Widespread use means they have likely seen it before. We also aren’t transferring large amounts of data, and the playspace could possibly be different every time for this project. We also unfortunately are not allowed to use any networking functionality as not all possible play spaces will have Wi-Fi.


NFC in our application will be a chip within a membership card. The card itself will have the agent ID printed on it and that ID will be held in the chip as well, plus other data like their current points. The basic operation of NFC in this metagame will be: kids tap at “HQ,” a central terminal, to register event participation. Then they are set loose in a defined play area to find games and interact. When a game is found, the agent taps their card on a tablet to log in. The game takes in their agent number and their point value. It is then played and finished, earning the agent more points. The card must then be tapped again to “charge” or have the points transferred to it. Later, the agent taps on the HQ terminal and their points are added to a community pool, which can represent some sort of community goal that encourages the whole group to cooperate. For example, charging the super heroes power.


Reading From NFC Tags In Unity

Let us take an in depth look at how the code works. Reading a tag is easier than writing to one within unity, so we will start there. The code itself is very easy to follow. Firstly, you do not need a Java plugin for this to function. However, you will need an android manifest so the program has the proper permissions and knows how to react to behaviors in unity. Now to walk through the code:




How It Works/Code Walkthrough

The program starts and declares all variables and sets up the byte arrays for known data. It then sets up the extra records lists for overflow data/unknown data and pulls in the read interval from the inspector. Once it is done initializing, it writes a wait message to the output text variable (tag_output_text).


Known data is the information we know will be on the card, in this case the agent ID number, the amount of points they have, and some form of other data like event registration status. Anything else is placed in “ extra records” which is an unknown amount of data/records. It will write what it can into the lists. The read interval controls the minimum time the game takes before it will read another tag. This is in case we need processing time of any data before we can accept more tag inputs, or just to slow the children down so they aren’t all trying to tap at once.


Every frame the game adds the time delta to the timer, then checks if the timer is greater than the read interval. If this is the case it clears the extra records and the tag Found boolean. The extra records must be cleared as it is uncertain how many there would be from tag to tag. They are also added to a string so the string must be cleared as well. Otherwise it will just get longer and longer, taking up more memory.


Afterward we start the code proper with a platform check. We use this to determine iOS or Android. From there it checks the tag boolean, if false it runs the rest of the code, if true the check runs again until a tag is found.


The rest of the code instances the activity Unity is running, the intent of the activity, what it is doing, and then gets the current action of the intent, or what just happened within the intent. If the action is that an NDEF tag has been discovered it does nothing. I am not certain this check is necessary, however I recall reading that it was. If the tag is not NDEF it checks if the tag is a supported type from an external tech list. If not, it moves on to throw an error, “this tag is unsupported.”


If it is supported, the game begins the magic. It will connect with the tag and get its message array. In the past, this call was not an array, however due to future proofing the standard was changed so that tags have message arrays instead of a single message. Eventually tags will be able to have multiple messages, but for now this is an array of one.


Records are then extracted from the message. They contain an ID, a Type Name Field, and a payload. We want the payload, so we pull that out with the getPayload method we can call from the record. It is a byte array but unlike older tutorials it cannot just be converted into a string. Doing so outputs it directly, giving you a string of byte values. They need to be encoded in UTF-8 and then output to a string. They will have some extra data on the front, for this an “en” at the beginning of each string, so that gets trimmed off. The strings get concatenated and output to the tag_output_text.text variable which then gets printed to the screen.


Finally at the end of the script we need to do some maintenance. The timer is zeroed out, the action needs to be nulled and the tagFound boolean is set to true. These actions are necessary as the timer decides if the script is ready for a tag. The action will not change otherwise, which for some reason continues to run the code forever even if the bool is true, so it must be set to a different value. The value itself is irrelevant, as long as it is valid.


Limitations

Some limitations exist for this. For example, you cannot read multiple tags simultaneously. This is an inherent limitation as NFC is a half-duplex signal. Another limitation to the current iteration is that it does not check to see if a tag has been scanned before, which if not addressed means one player can log in multiple times. This will be handled per game however. Lastly, the android manifest has to exist. I am unsure if there is a new or better way of doing this, as of June 2018, but it tells unity how to behave with android. It will not use the one in the java plugin, though I supposed you could allow it to.


Methods Used

This section covers specific methods used in this script.

mActivity=new AndroidJavaClass(“com.unity3d.player.UnityPlayer”)GetStatic<AndroidJavaObject> (“currentActivity”);



mActivity is the current activity used by the Unity player


AndroidJavaClass is a generic class used by C# in Unity to interact with Java


AndroidJavaObject is like the above, but for everything not a class.


UnityPlayer is Unity’s activity name for its player app.


currentActivity is the method call to get the activity name from the Unity Player


mIntent = mActivity.Call<AndroidJavaobject>(“getIntent”);


mIntent is the intent of the activity define above it. Intents are what the activity is doing/wanting to do.


Call and CallStatic are the functions that call java methods from C# in Unity.


sAction = mIntent.Call<String>(“getAction”);


sAction is what has happened in the intent.


The Call method needs a type, shown in brackets and it calls a method named in the string within the parenthesis. Spelling is important since it is calling that exact string.


AndroidJavaObject[] NDEFMessage = mIntent.Call<AndroidJavaObject[]>(“getParcelableArrayExtra”, “android.nfc.extra.NDEF_MESSAGES”);


NDEFMessage is the message array. It is called from the intent.


getParcelableArrayExtra is a parcel that holds the extra commands for the NFC adapter. This parcel is for extra arrays. In our case “NDEF_MESSAGES” it is called with its whole path as an argument. Returns an array of messages.


AndroidJavaObject[] NDEFRecord = NDEFMessage[0].Call<AndroidJavaObject[]>("getRecords");


NDEFRecord is the records contained within our message.


getRecords pulls those records from the message. It is called from NDEFMessage(Or your variable name for your message)


AgentID = NDEFRecord[i].Call<byte[]>("getPayload");


getPayload is the method call for extracting payloads from records.



mIntent = mIntent.Call<AndroidJavaObject>("setAction", "");

sAction = mIntent.Call<String>("getAction");


setAction will change the current intent’s action to whatever is in the argument if it is valid. Can be a null value. We then need to get the action again to fully null the value in the script.




How It Fits In

Now we have the ability to read NFC tags from within unity. This functionality will allow games to read agent numbers from their ID cards. If needed this can be the only function done by a game(no writing) and the specifics of the metagame can change, but still give agents the same experience.




Writing To NFC Tags In Unity



How It Works/Code Walkthrough

Writing to tags is a little trickier. Here we introduce our Java plugin; this will take care of the actual writing to the tag. Let’s go through it.


The script starts and declares our plugin variable and defines our java classes in unity. Here, for now, we also define our records, of which the Payload array is split into. The major difference here is that we also define our activity. This can probably be moved down to the rest of the code like it is in the read script.


For every frame the timer counts up and its value is checked. This controls the write interval- How fast do we want people logging out? Do we need to process data? Those are the questions the timer answers. If the timer is greater than the write interval, the script checks the current platform then a boolean (NFCgo) to see if it is allowed to go. If true, it runs the rest of the code. If false the code does nothing.


The code starts by getting our intent, action, and plugin. When the action discovers supported tech, the script instances the tag and sends that data, along with the records, over to the Java plugin. Lastly, we perform a maintenance cycle to zero out the timer, change the boolean check to false, and null the action.


Over in our Java plugin, it receives the records and tag data. First it combines the records into a message. Individual records can’t be sent to tags, also you currently cannot send an array of records to the plugin. They must be sent individually.


Once the records are combined they are immediately passed to the “pushMessageToTag” custom method (do you have to write this method yourself). This method gets the tech list from the tag instance, gets the tag from the tag instance, and finally it connects to the tag and overwrites the message on the tag with the new one. It then closes the connection. The user can then move the card away from the terminal.


Limitations

Limitations in this script are mostly, I feel, from my own inexperience. Only 3 records can be sent in a message because I can’t find a way to send arrays, although it should work. Static methods are the only type that can be used, but we see in the unity specific side of things they use non-static methods. There is a lot of room for improvement, just not enough time to explore them. Security is also a concern as tags can just be written to without any sort of check. Many devices only have specific areas in which NFC tags may be read. Tablets, as an example, only read when the tag is tapped onto a small area on the back .




Methods Used

This section covers specific methods used in this script.


NDEFrecordsArray[0] = NDEFrecordclass.CallStatic<AndroidJavaObject>("createTextRecord", "en", Payloads[0]);

NDEFrecordclass is the instance of the android class “NDEFRecord”

“createTextRecord” is the method that generates a basic text record. It takes 2 arguments, a language code and a text string.


PluginTest = new AndroidJavaClass(“com.x.y.z.library/activity”);

Instance in C# of the Java plugin. Defined by the whole path.


AndroidJavaObject ndefTag = mIntent.Call<AndroidJavaObject>("getParcelableExtra", "android.nfc.extra.TAG");

This is similar to getting the messages in the read script. “getParcelableExtra” is the non-array version of getting access to the extra commands in the adapter. It takes one argument, which is a string for the method constant call.


public static void PutRecordsTogether(Tag tag, NdefRecord rec1, NdefRecord rec2, NdefRecord rec3)

“PutRecordsTogether” is a custom method. The only thing it does it take the records in and calls the message constructor, combining the records into a message. It also takes in the tag, but simply passes it along.


public static void pushMessageToTag(NdefMessage _newMsg, Tag tag)

This is where the magic happens. pushMessageToTag can be called from unity, however, for our purposes it is called within “PutRecordsTogether.” It takes 2 arguments, an NDEFmessage and a tag instance. It also instances the tech list from the tag, and gets the tag itself from the tag instance. Then it connects to the tag and overwrites the message.


public static void SendToUnity(String gameobject, String methodToCall, String message)

Sends a message back to unity. Takes 3 strings as argument. The name of a gameobject that has the script. The method in the script you want to call, and the message you are sending to that method. This exists so I could send debug messages to unity from non-static methods.


How It Fits In

With writing done, we can now do more advanced things with our NFC cards, like pass data, a weird basic networking analog, register event data, and interact better with other games. The NFC card becomes much more integral to the design of the metagame as well.


How To Use

Steps to use the reading script:

  1. Set up read interval in the inspector

  2. Build to android device

  3. Tap tag onto device


Steps to use the writing script:

  1. Set up the records in the inspector

  2. Set up write interval and “processing” time

  3. Build to an android device

  4. Tap tag onto device


Project Recap/Future

We want to use NFC to promote interactions between people, and in this case, especially children and police officers. The technology is simple to understand and easy to use. It is wireless and portable. We use the tech as a platform to give children agency and a feeling of satisfaction for being a part of something that helps the community, as well as making new friends. Anything is possible here, as the potential applications for this technology are endless.

2 views0 comments

Comments


Post: Blog2 Post
bottom of page