How to Build an Android NFC Tag Scanner App With React Native

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the The newline Guide to NFCs with React Native course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to The newline Guide to NFCs with React Native, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course The newline Guide to NFCs with React Native

Hello, in this lesson, we will focus on Android side. We will see the difference between Android and iOS, and discuss how to provide a similar experience for our NFC game app, the difference between iOS and Android. Let's first run our previous work on a real Android device. As you can see, I have pressed the start button several times, but it looks like there's nothing happen. What's wrong here? Actually, it's nothing wrong. It's because Android provides no built-in NFC scanning UI, so even our app is ready to scan NFC tags. There's no visual cue for our users. So our first step in this lesson is to build a component to mimic the behavior for iOS NFC scanning UI. Let's call it Android Prompt. This component will use real native built-in model component to present content about the enclosing view. Then we set both transparent and visible props to be true for the model component, and also provide some basic styling for our inner view. After the basic setup, let's add our Android Prompt component into our app.js. Okay, now our Android Prompt shows up on the screen. Let's move on to style our content inside the model. The built-in blocks are a full view component with flex1 as its container, and a backdrop inside the container. The actual prompt UI is rendered above the backdrop. And there are two components inside it. One hint tags and one cancel button, just like the iOS. Then the next step is to apply our styles to our components. Oops, it looks like there is something wrong with the backdrop. That's because we haven't applied the position absolute part into it. To write this kind of cover all style, here is a little trick. We can use the style sheet the absolute feel. It's very convenient in such a case. The next step is to design the interface between our Android Prompt and its parent. Normally in React, we use props passing as the primary interface between components. That's because of React's declarative nature, however, in our case, provide an imperative API set will be much easier. The API we want to expose is something like React Native's built-in alert module. For alert, we simply call alert.alert and it will appear. From the caller's perspective, we don't need to preserve a state like "is alert visible" and pass it as props into alert. We'd like to do something similar for our Android Prompt component here. In order to accomplish this, we will use ref. First, wrap the original Android Prompt component with React.forward ref. Once a function component is wrapped with 4 ref, it will receive a second argument, which is the ref object passing from its parent. Then we create our internal state, visible and hint text. Since those states are within the current component, we need to provide a method to let parent component to access them. We can use an use_effect_hook to accomplish this inside the hook. If we have a ref object passed in, we can set the current property of the ref object and put our state mutation function inside the current object. So the set visible and set hint text can be used by our parent component. And of course, we should pass our internal visible state into the modal component and display our internal hint text state. We also need to tackle the visible state back to false and clear the hint text when the cancel button is pressed. Now it's time to test them. Head back to our app.js. We first call use ref_hook to obtain a ref object and pass it into the Andrew prompt component. Then quickly create a test button. From the test buttons on press handler, we can simply call current.setvisible true. As you can see, we can now tackle our Andrew prompt component from parent and tackle it off by pressing its own cancel button without tracking the visible state from the parent component. Now it's the fun part. We'd like to add some animation into our Andrew prompt component. Import the animated module from ReNative. We also need an animated dot value initially set to 0. Then we create an underlined visible state. I will explain this in just a second. For now, just consider that we will use this underlined visible state instead of the previous visible state. Before we dive deeper, here's the thought process of creating animation. The first, what state triggered the animation? For us, that's the underlined visible state. The second, how to update the animated dot value object according to pyro state change. Third, how to update the style using the changing animated dot value object. To handle the first and second question, we create a new use effect hook. Depends on the underlined visible state and the anim value object. This hook function will be triggered when underlined visible value changed. And if this value is true, which means we are about to show our component, we first set the visible state to true and use animated dot timing to gradually change the anim value from 0 to 1. On the other hand, if the underlined visible is false, which means we are about to hide our component, we need to call animated dot timing first and then tackle the visible state to false in the completion handler, which is the callback passed into the start function. If we use the run order, the model will disappear instantly and no animation at all. That's why we need a second underlined visible state to signal the beginning of a transition. And the visible state is the one actually passed into our model component. After that, we change all the existing set visible into underlined set visible. Since its actual usage is to trigger the use effect hook, so we should only call set visible our effect hook. The next step is to update the style using the anim value. First, update the backdrop with the opacity. Test it and it looks pretty great. Then we can handle the animation for the prompt. The effect we want is a slide out effect. So we do a translate y transform and let the anim value to interpolate from 0 to 1. By the way, always remember only the animated view can have animation style in it, otherwise you will have some trouble. Test it again and it's awesome. The next step is to use our Android prompt component in our game. First, import it and set up the ref object. Then, when the NFC manager that registered tag event is called, we should set our Android prompt to be visible. By calling Android prompt ref.current.set visible true. And, when the user is playing, we can update the hint tags according to platforms. If it is Android, we will call our custom set hint tags function from ref. If it is iOS, we simply call set learn message iOS. Once the game is finished, we should set our Android prompt to be visible. Okay, it seems that we are ready to test it. Before testing, you will need to check the position of NFC antenna for your Android device, because they might be in different places according to different Android manufacturers. It looks pretty good. Though the app seems working correctly, but there is actually a potential bug. That is, once the user presses the cancel button in our Android prompt, we won 't actually stop the NFC from scanning, because our game component is not aware of it. To fix this issue, we first add the uncancel pressed into our Android prompt component, and call it when the cancel button is pressed. And then, go back to our game component, pass the uncancel pressed prompt into Android prompt component, and call unregistered tag event inside it. Besides the system scanning UI, another difference between Android and iOS. That is, NFC can be disabled in Android. So for Android app, before the game starts, we will need to confirm that the NFC is enabled. Let's do it now. First, create an enabled state, and in our check NFC function, we call NFC manager that is enabled. This API will resolve to a boolean value to indicate whether the NFC is enabled or not. And use this state in our render logic. If the NFC is supported but not enabled, we show a hint to our users, and provide a button for the user to jump to NFC system setting. By calling NFC manager that go to NFC setting, and please be aware, this API only works on Android. You might wonder, what about iOS? Actually, our NFC that is enabled will always return true since there is no NFC switch for iOS. So, we can confirm that the runtime execution flow will never reach here. Finally, we also provide a button to let the user recheck the NFC enabled state . It's about time to test our modifications. We first disable NFC, and then launch our app. As you can see, our UI hint at users about their NFC state. Then hit "Go to settings" to enable NFC. Then back to our app again, recheck the state, and now the user can enter the game. Cool. Now we have a simple but fully functional NFC tech counter game app for both Android and iOS. [BLANK_AUDIO]