Working with NFC in Flutter
Enter our career fair project
For the latest career fair at?MatFyz, we wanted to build something interesting: from one side, it should be more than just "here is our merch, come work with us"; from another side, it should showcase the products we were working on at Mews.
Since one of our products is a kiosk for self-service check-ins at hotels, we decided to emulate a hotel check-in experience with guests entering their details into a registration card, cutting their "key" with an emulated key cutter, and later taking part in a lottery with randomly selecting winning room numbers.
What is a key cutter?
If you google "key cutter" images, it will show you something like this:
This is definitely not the device hotel guests are supposed to use to check into their rooms.
A hotel key cutter is basically an RFID-card encoder: an electronic device that looks like a payment terminal. During "traditional" check-in, a receptionist takes an empty RFID-card and uses this device to write some information on the card. Later, the room door lock reads this information and opens the door for you. This process of "cutting" the key card is usually not visible, often cards are prepared in advance before check-in.
When using the self-service kiosk, you can do this on your own: following instructions on the screen, you take a new RFID-card from the pile and place it on the key cutter:
There can be more complex devices (e.g., with automatic card dispensers), but we will emulate exactly this type, which is pretty popular.
How did we go about it?
This article will be about this "key cutting" process. At first, we wanted to set up a real key cutter, but there are a lot of technical and legal problems associated with them, so we decided to create a simple mobile app that will write a room number on an NFC-card. Later, a user can just come up with this card so that we can read their room number and match it with the winning numbers.
Let’s talk about this overall process of key cutting and how it works in production for a real hotel kiosk:
In our setup, Kiosk doesn’t communicate directly with Key Cutter. Instead, when the guest presses the "Cut key" button, Kiosk issues a command to our Web Server, and Server creates a command in the special queue. In the hotel, there is a separate desktop application (Connector) that listens to this queue and communicates with the hardware Key Cutter. When the key is cut, Key Cutter notifies Connector, and Connector sends the confirmation back to Server. After that, Server notifies Kiosk via Websocket that the key is ready.
It sounds like a complex setup (and it is), but it allows us to completely decouple Kiosk from Key Cutters – and since Kiosk is not the only client that deals with Key Cutters (and other peripherals), we keep all the knowledge on how to work with peripherals in one place.
In our "emulated" version, both the Key Cutter and Connector roles are fulfilled by the mobile app. The good thing is that Kiosk already uses our public API, the same one that is used by the Connector desktop app. That means that we already have the API implementation in Dart and can reuse it for our "key cutter".
So the emulated workflow looks like this:
In fact, we’re just merging two entities, Key Cutter and Connector, into one mobile app. Kiosk still communicates with Server, but all the logic of receiving the key cutting command and "cutting" the key now happens in the custom app.
Now let’s discuss this app in detail. For that, we will need to know more about NFC.
What is NFC?
Let’s start with another question: "What is RFID?"
Imagine you’re sitting on your porch at night. You turn on the porch light, and you can see your neighbor as they pass close to your house because the light reflects off them back to your eyes. That’s passive RFID. […]
Now imagine you turn on your porch light, and your neighbor in their home sees it and flicks on their porch light so that you can see them waving hello from their porch. That’s active RFID. […]
RFID is a lot like those two porches. You and your neighbor know each other’s faces, but you don’t really learn a lot about each other that way. You don’t exchange any meaningful messages. RFID is not a communications technology; rather, it’s designed for identification. RFID tags can hold a small amount of data, and you can read and write to them from RFID readers, but the amount of data we’re talking about is trivial, a thousand bytes or less.
Beginning NFC?by Tom Igoe, Don Coleman, Brian Jepson
RFID and NFC are often conflated, but they’re not the same thing. Though NFC readers can read from and write to some RFID tags, NFC has more capabilities than RFID, and enables a greater range of uses. You can think of NFC as an extension of RFID, building on a few of the many RFID standards to create a wider data exchange platform.
So, what is NFC?
领英推荐
Near Field Communication (NFC) is a contactless communication technology based on a radio frequency (RF) field using a base frequency of 13.56 MHz. It is designed to exchange data between two devices through a simple touch gesture.?https://nfc-forum.org/what-is-nfc/
Different standards
We decided to go with the?nfc_manager?plugin. It’s a wrapper around platform specific NFC?(or rather RFID)?capabilities.
It provides the following platform-tag-classes:
As you can see, the only type that is available on both platforms is NDEF. And that is expectable, as this is the standardized format for NFC Forum Tags.
NFC Forum Tags are contactless memory cards hosting a so-called NDEF message (NDEF stands for NFC Data Exchange Format) defined by an NFC Forum Specification. NFC Forum has currently defined five different NFC Forum Tag types to allow the usage of many different existing memory card implementations as NFC Forum Tags. These different NFC Forum Tag types differ in the underlying communication protocol and data structure to store NDEF messages, but the resulting overall behavior of NFC Forum Tags is identical.
That means if we want to go cross-platform, we should use NDEF-compatible cards. This can be a problem on its own – when we were looking for the cards for our project, we failed to find them.
At least we managed to find Mifare Desfire EV1 which can be formatted to NDEF format, but it can only be done with Android. So it’s either formatting the cards in advance and then using any mobile phone for writing NDEF messages, or using Android for?writing?the data (later both iPhone and Android can be used for?reading?the data).
We decided to choose the second way, as Android has some other advantages for serving as an improvised key cutter.
iOS vs Android – UX, custom behavior
If you have an NDEF-formatted card, you can read and write using both Android and iPhone. But we didn’t need a "B2C"-style app, we were going to create a key cutter emulator. And for this, Android is a better choice:
Implementation
The "key cutting" logic is pretty simple: we’re just connecting to the server and waiting for the command. After the command is received, we fetch additional data (since the command itself contains only the room number, we need to fetch the reservation details) and validate them (it should point to the correct active reservation). If the data are valid, we start an NFC writing session: enter discovering tag mode, and write the data (room number in our case) after the tag is discovered (aka NFC-card bumped to the phone). After that, we return to the "waiting" state, and the process repeats.
This state diagram can be easily mapped to the BLoC code, so let’s just take a look at the NFC writing part:
As you see, we’re starting an NFC session, and passing it a callback as?onDiscovered?parameter – it will be triggered once an NFC trigger detects a tag nearby. As I mentioned earlier, in Android we can work with either NDEF or NDEF formattable tags, so if the tag of the correct type was bumped, we just write the prepared message there (which contains just the room number in our case) and close the session.
The code for the reading part of the app is pretty straightforward as well. I will show the complete source code for the?NfcReaderBloc, but the most interesting part is the?`_onTagDiscovered?method:
As you see, when the tag is discovered, we just read the first record there (assuming that we read the NDEF formatted tag) and emit it as a new state. The only trick here is to skip the first three bytes of the payload. This is needed because, according to the NDEF specification, the first byte in the payload is reserved to store the length of the language code (N), then goes N bytes to store the language code itself, and then the actual record content (our message). In our case, we only use EN language (two bytes for the code), so we can hard-code to skip the three reserved bytes.
Demo
The result was pretty good and we received a lot of positive feedback, so we decided to reuse this idea for WebExpo 2022, but that’s a different story.
---
Originally published at developers.mews.com