Setting up an Android app with React Native in Kiosk Mode
I’ve been using React for quite a while. I like it a lot. I think it is an excellent tool that should be used for the right problem (not all of them, though). So, when I was given the task of developing an Android app I immediately thought about React Native.
I started working on it and it was very satisfying. I had little to no experience working on native Android applications, so using React Native made it all pretty simple, and… well, kinda fun 😁.
All of the sudden the project changed dramatically. My app was now not intended to run on a user’s personal phone, but we were to provide the users (in this case, cashiers) with a barcode scanner device (running Android, of course) directly imported from China.
With us providing the hardware, I started to get nervous. Hardware makes me nervous.
Our first constraint was that the app that I was developing was now intended to be running on Kiosk Mode, which means that the user was not to leave the app by any reason (apart from shutting down the device, which we thought was necessary). And do you know what that meant? Yeah. I had to go into the “Java side” of the app (which, to be honest, it fucking terrified me).
Welcome to Android development, rookie
I don’t consider myself a programmer nor a software engineer. I’m mostly a very persistent, glorified google searcher that reads a lot of stuff online (I also google myself every once in awhile). So I approach the Kiosk Mode problem as I do with most of my problems:
Fucking google it.
So I did. And I found lots of resources that pointed me in the right direction.
In the following paragraphs I will try to explain what I did so it might help someone else:
1. Disabling some keys on the devices physical keyboard
As I shown on fig. 1, the device has lot’s of keys that a standard Android phone doesn’t . For starters, those CALL and END CALL buttons. So 2000’s, amarite?
Well, those keys loaded the Phone app on the device from wherever you are. I tried to redirect those keys in the MainActivity.java file with no success. I was left to no other option. I had to root the device and change the physical keyboard layout. No biggie 😅.
I rooted it using one of those apps that magically does it for you. Then I tried to edit a file using adb shell with no success. I downloaded an app to navigate the root files and there it was:
I changed what it was the physical keyboard layout config file. And commented the lines that specified the keys that I wanted to delete. I rebooted it. It worked.
2. Overriding HOME and BACK keys
Ok. As the CALL and END CALL keys were now out of commission, I needed to have control of other keys that might redirect the user out of the application, but I didn’t want to lose their functionality completely. These keys are HOME and BACK.
Taking out these keys won’t make the app unusable as I had already added a back functionality inside the navigation toolbar (kinda like most iOS apps), with the main difference that it doesn’t let you switch the app and go to Home.
This was way easier. I googled how to look at the key code every key emits when you press it so I can bypass them.
Yup. That did it.
3. Auto boot app when starting the device
I have to be honest, it was Andreas Schrade’s article on how to build a Kiosk Mode App that helped me the most with the following parts. Big thanks to him.
I created a new .java file named BootReceiver.java in the same directory as my MainActivity with the following code.
Then I edited the AndroidManifest.xml to add a new permission (as a root xml node child) and a new action (as an application xml node child):
I rebooted the device and it worked. So much joy :)
4. Hiding the Status Bar
I had to make the status bar unavailable from within the app, because, ehm, users can use it to easily leave the app and go to Settings (which is like, a big no-no in the Kiosk Mode business, apparently).
I read this article and got the excellent idea of changing the theme so there’s no status bar when using the application. Brilliant. Just what I needed.
So I edited the React Native generated styles.xml file under /main/res/values/styles.xml and added this:
Also, I had to edit the application tag in the AndroidManifest.xml file:
5. Remove all system UI when starting the device
I started trying to get out of the app when booting the application and I found out that there’s a very small window of time between the OS loading up and the app starting when I can actually access the Settings menu. So I found out that you can actually disable the System UI so there’s absolutely nothing to click or touch on the phone in that window of time that I mentioned.
If you got this far it probably means that you already know how to run adb shell commands from your terminal, which is precisely what I did:
$ adb shell
$ pm disable com.android.systemui
Restart the device and that’s it. Bear in mind that you can easily enable the System UI by replacing disable to enable in the last command.
6. Safety Net
In one of the views of my project I had to load a WebView component, which, for some reason, caused a lot of problems with the barcode scanner (if you want to know more about it, please contact me, as this doesn’t have much to do with React Native itself, but with the device’s physical keyboard).
Anyway. We need to be able to automatically restart the application in case it crashes. You should only do this as your last measure, as it will most definitely fuck up your UX so bad your users will, well, not want to use your app.
And, oh man, this was hard. Mostly because I (still) don’t know much Java. And I’ll be honest, most of the work are thanks to the excellent article written by Chintan Rathod.
So this is what I did:
- I created a Java application class with the same name as my app in the MainActivity.java directory (In this article the name is YourAppName.java) [EDIT: Apparently newer versions of React Native, there’s some boilerplate code for a MainApplication.java class. You might want to add the methods there instead.]
- I added the following code (thanks again Chintan!) to YourAppName.java, which I think if follows the Singleton pattern and it’s mostly used to have some sort of control over the application state
3. Add the name of your application class in the AndroidManifest.xml. In our case we add:
(you can also check the fig 2 to see the full application xml node.
4. Modify MainActivity.java by adding a restartApp() method, and overriding the onCreate() method that restarts the app in case of an uncaught Exception (don’t forget to add any packages/libraries we use in our code)
And that’s pretty much it! You can test it by throwing a RunTimeException on some specific action (I linked it to the BACK button).
throw new RunTimeException(“I'll see you in hell, Alejandro!”);
I’m pretty sure one could develop lots of nice looking native applications with only learning React Native, but eventually you might want to invest in learning Java and familiarize yourself with Android development in general.
I’m also quite sure that when I was assigned to this project it made total sense to use React Native (we even considered to make an iOS version of the app too!). But projects change, requirements change, and as developers we have to always adapt to the times.
react-native-kiosk-mode — Sample React Native app on Kiosk Modegithub.com
Thanks for reading!