Today as some of you could have expected after our short movie with “Hello world” written in React Native running on Amazon Fire TV Stick (referred to AF later), Jakub Stasiak and I are going to describe our journey with an AF.
Our adventure with an AF has started from a request from a one of our client to build an app which would be responsible for displaying important information on TV displays in shops. Fire TV Stick is a small device (in the size of a bigger memory stick) which is probably the cheapest option to make non-smart TVs “smarter”. The most important thing for us is that it’s powered by Android.
When our AF arrived, we had to decide which technology stack we would like to choose. A final app would consist of 3–4 screens with input areas, list and details view.
How can we write an app for AF?
After some research we came up with the following options:
- HTML5 app
- native Android app
- React Native app
The order of the list above is not a coincidence, the first option is probably the easiest and you can find relatively many docs about that solution. RN app is on the last position because we haven’t found anyone who had done this before. As it’s not too hard to spot the answer we wanted to try with RN on AF.
For the purpose of this article, we want to go through a process of creating an RSS reader in RN for AF.
How to enable adb?
The first step to become a React Native developer for Amazon Fire TV Stick is to enable adb on a device. On a Fire Stick, it’s even easier than on an Android phone. We just have to go to the device settings and find the adb switch. Next, we can verify whether the adb was enabled or not, we can do that from CLI (if our AF is connected to our computer) using command
Will empty app work?
Now we can generate and start an empty RN app, we have to run the following two commands:
react-native init FirestickDemo && cd FirestickDemo
As a result, we should see a standard RN app, be able to show developers the menu and navigate through options. 🎉
Can we navigate through buttons?
At this point, it seems like we can start developing what we planned. Let’s add some buttons to test if it works.
White rectangle should change background color.
What?! Why can’t we click on anything? 😦
We are clicking center button on remote control but nothing happens. It’s possible to navigate between touchable components and buttons but there is no possibility to call
onPress method. We tried few different approaches. We even wrote native apps in Java and Native Script with few buttons (those apps works great). Turned out that
Buttoncomponent doesn’t use native button underneath. That’s an unfortunate.
How AF’s remote works?
While writing our first app for AF we realized that remote control sends classic keyboard events. React Native doesn’t support those events by default but we found a library for that. Great, so there is still hope. It looks like we have everything we need — possibility to navigate between every
touchable and possibility to listen to keyboard events. We could manually call
onPress after user press center button on a remote control.
Yes, we could… but we can’t.
Another problem — there is no possibility to find out which
touchable is focused. Ah, React Native, dear friend why you have to make everything harder. Now we must write something big and ugly that will become better
touchable and keep in our state information about currently focused component.
How to live with that?
Our idea was to create two things:
SelectableContainer– a component which will store all information about selectable components in current view and react to keyboard events.
selectable– a Higher Order Component , something that can transform classic
View, etc. into a component that can be focused and selected using a keyboard or a remote control.
SelectableContainer should be a stateful component with a state in that shape:
So we can properly react on every up/down button click and change
activeSelectable to one above/below. There is a list of coordinates in a component state so we can easily find out which selectable should we select. On every change of
activeSelectable we will call
onPress method. The code which is responsible for all of that:
How SelectableContainer has access to buttons inside?
The answer could frighten you — through
context. Yes, we know… it’s an experimental API which will probably change but still, it’s the best solution for us. Of course, we don’t want to write context “magic“ every time we want to add simple button. It will be ugly and hard to maintain.
That’s why we created
selectable HOC. It will register our component in SelectableContainer and make sure that we can use
onPress prop on every component wrapped by it. It will also read position of our component so
SelectableContainer will know the proper visual order of selectable components.
Okay, we can now easily create selectable
View. Let’s do that by modifying our first attempt to AF buttons:
Now we can select buttons!
Will inputs work?
The first part of our work is done! We are ready to create a list of RSS feeds with buttons. Now we only have to add some possibility to create custom RSS feed. And there is no surprise, classic
TextInput doesn’t work well on AF. It’s impossible to navigate from another component to it. Fortunately, we created
selectable before so we can us it here. Just simply wrap
selectable and call
onPress function prop. Just like this:
Now we truly have all pieces we need to build AF app!
RSS feed app
Link to source code: https://github.com/souhe/react-native-firestick
Should you use React Native as a technology to build AF app?
If you are familiar with React Native definitely yes, it was a great adventure for us and we learned a lot of things. If not maybe stay with native stuff or write an app in HTML5 which is kind of a recommended solution for Fire TV Stick.