Wouldn’t it be cool to have a way to watch flights move across the world; essentially see the flight’s live location change in realtime? Of course, it would be, at least to a geek like me.

In the course of finding positive solutions, and easy implementation, but good enough to carry out this idea of mine — We will use FlightAPI — a global flight database with an API. This is a REST API and fulfill my real-time requirement. Using this API you can also compare prices from more than 70 airline vendors & airlines itself.

And with the advent of event-streaming technologies, many data providers prefer streaming data in real-time using push protocols over letting their consumers poll for data frequently using REST — which is inefficient for both parties.

During this search, I found Ably Hub . It is a marketplace for publicly hosted free, open and commercial data streams by various providers that are available to be consumed. Most of them are free to use. Luckily, I found just the thing that could scratch my itch with this project. A realtime data stream of flight data that uses data from Flight Radar called Heathrow Flights . Even though the flight information coming through in this data stream is limited to flights originating or arriving at London Heathrow airport, this was enough for my project.

If you’ve never heard of Ably, you can read about them from their site to learn more, and probably share what you learn with me too.

For this article, I’ll share how we can build a Realtime flight tracking app in React Native using the data from the Heathrow flight product on the Ably Hub.

Somethings that’ll be nice to have before we get started:

Knowledge of JavaScript

A free account with Ably

Knowledge of React, React Hooks and React Native

Features of the application:

Arrival and Departure Screens: each screen will have a list of airports labeled with location and the destination of aircrafts

A search box: to quickly find a flight with its IATAID (International Air Transport Association ID)

The map area: we’ll have a map that tracks the current location of a moving flight; a Polyline from origin to destination

Step 1 — Creating a free Ably account

If you don’t have a free account with Ably, you can create one here . If you already have an account, you can proceed to the Heathrow Flights product on Ably Hub . This is a self-subscribe product.

Locate the ‘Subscribe to Heathrow Flight’ button by the right corner of the product page as shown above. This will enable your Ably account to access the flight data stream from one or more of your apps. Let’s go ahead and set one up next.

Step 2 — Setting up an Ably App

We’ll assume we already have an Ably free account and we’ve subscribed to Ably’s Hub Stream Product: Heathrow Flight . Now, we want to create an Ably app.

If you’ve successfully arrived on your dashboard, you should see a blue button labelled ‘create app’. Create an Ably app using the button, then enter a project name for the project/app, as shown below.

Step 3 — Using Ably React Native Hub Stream Kit

I’ve created a starter kit to make building our project a lot faster and cleaner. The starter kit contains a quick setup of React Native with Expo Managed Workflow. Expo is highly recommended by the React Native team to build a small (or large project depending on complexity) with React.

Quickly clone the project from GitHub using the command below:

Next, change directory into the project folder cd flight-tracking-app-starter-kit .

You’ll want to confirm you have yarn , expo-cli , and nodejs installed on your machine.

Installations:

Node.js (https://nodejs.org)

Yarn ( npm install -g yarn )

) Expo-CLI ( npm install -g expo-client )

We’d use Expo Client to test our application while building. Expo Client is currently available on both iOS and Android stores. Please, create an Expo account here

Step 4 — Setting up locally

To get started with the project run yarn from the project directory your terminal.

$ cd flight-tracking-app-starter-kit

Next, run $ expo start and also launch the running application on a mobile device.

Step 5 — Obtaining Your Private API_KEY

Locate env.js in the root directory of your project and replace the code with the private API_KEY obtained from the Ably application you created in Step Two. Your API_KEY should look like this:

Step 6 — Update and Modify Codes

Your folder structure should like this:

Navigate to the hooks/ably.hooks.js and update the CHANNEL_SCOPE with this code:

const CHANNEL_NAME = '[product:ably-flightradar24/heathrow-flights]flights:airport:LHR'

The above channel subscribes to a data stream of airport information like the flights departing and arriving at Heathrow Airport, London.

Step 7 — Connecting to Ably (Pub/Sub)

Ably uses a scalable and resilient messaging mechanism Pub/Sub . Ably Realtime service organizes the message traffic within applications into named channels

Add the code in ./hooks/ably.hooks.js to connect and subscribe to a named channel.

export const useAblyChannel = (channel, dependencies) => { const [onMessage, setOnMessage] = useState('Please wait..') const [isLoading, setLoading] = useState(true) //fetch channel data const [channelData, setChannelData] = useState(null) useEffect(() => { //add ably connection here console.log('Ran Use Effects', channel) // know the current state of the application ably.connection.on(function(stateChange) { console.log('New connection state is ' + stateChange.current) setOnMessage(stateChange.current) setLoading(true) }) // use the channel scope in the application const useChannel = ably.channels.get(`${CHANNEL_NAME}:${channel}`) useChannel.subscribe(message => { if (message.data.length > 0) { setOnMessage('Loading Data...') setLoading(false) setChannelData(message.data) } }) }, dependencies) return [isLoading, onMessage, channelData] }

./context/ApplicationContext.js to have Also quickly updateto have listeners

export default ApplicationContext = ({ children }) => { ..... //add subscription listeners here const setChannel = iATA => { console.log(`This ${iATA} was clicked`) return ably.channels.get(`${HUB_STREAM}:${iATA}`) } const departureListener = message => { console.log('Still Listening Departure', message.data) message.data && subscribe(message.data) } const arrivalListener = message => { console.log('Still Listening', message.data) message.data && subscribe(message.data) } const subscribe = data => { setIsLoading(false) setArrivalsData(data) } // add unsubscribe listeners here const unsubscribe = (useChannel, type) => { console.log(`unmounting sub ${type}`) useChannel.off() useChannel.unsubscribe() type === 'arrival' ? setArrivalsData(null) : setDeparturesData(null) setIsLoading(true) } const setArrivals = (iATA, action) => { action === 'reset' ? unsubscribe(setChannel(iATA), 'arrival') : setChannel(iATA).subscribe(arrivalListener) } const setDepartures = (iATA, action) => { action === 'reset' ? unsubscribe(setChannel(iATA), 'departure') : setChannel(iATA).subscribe(departureListener) } ... }

Next, update the ./screens/ArrivalScreen.js with the code as follows:

import { ListCards } from '../components/ListCards' import { arrival as channelData } from '../constants/RawData' import { Container, Text, Content } from 'native-base'

The above imports dummy data structured in the form of a data stream; this gives you a glance of what the expected data looks like.

import React, { useEffect } from 'react' import { StyleSheet } from 'react-native' import { Container, Text, Content } from 'native-base' import { ListCards } from '../components/ListCards' import { arrival as channelData } from '../constants/RawData'

Next, still in ArrivalScreen.js file, display a ListCard to show the origin and destination of the aircraft we want to watch in realtime. Add the codes below to display a ListCard:

export default ArrivalScreen = ({navigation}) => { ... const Arrivals = channelData ? channelData.map((item, index) => { return ( <ListCards key={index} text={`${item.origin} - ${item.destination} (${item.iataId})`} icon="ios-airplane" action={() => navigation.navigate('PopModal', { iataId: item.iataId, action: 'arrival' }) } rotate /> ) }) : [] ... return ( <Container style={styles.container}> <Content>{Arrivals}</Content> </Container> ) ... }

Repeat the steps for ./screens/ArrivalScreen.js in ./screen/DepartureScreen.js , and also rename 'Arrivals' constant to 'Departures'. Rename

... import { departure as channelData } from '../constants/RawData' export default DepartureScreen = ({ navigation }) => { const Departures = channelData ? channelData.map((item, index) => { return ( <ListCards key={index} text={`${item.origin} - ${item.destination} (${item.iataId})`} icon="ios-airplane" action={() => navigation.navigate('PopModal', { iataId: item.iataId, action: 'arrival', }) } /> ) }) : [] .... return ( <Container style={styles.container}> <Content>{Departures}</Content> </Container> ) }

Ensure you save and see changes as shown below in your mobile application before proceeding to Step Seven.

Step 7 — Adding State Management

First, update the React’s Context API. Open ./context/ApplicationContext.js

Replace:

const HUB_STREAM = '<HUB_API_STREAM_CHANNEL>'

With:

const HUB_STREAM = '[product:ably-flightradar24/heathrow-flights]flights:plane'

The channel above subscribes to a data stream of aircraft information such as its current location, its route and the speed of the aircraft.

Next, return back to ./screens/ArrivalScreen.js and update code to use React Hooks for the state management of our application: useAblyChannel(channel, [])

export default ArrivalScreen = ({navigation}) => { ... const [ isLoading, displayMessage, channelData ] = useAblyChannel('arrivals', []) ... ... return ( <Container> {isLoading ? ( <LoadingScreen message={displayMessage} /> ) : ( <> <Content>{Arrivals}</Content> </> )} </Container> ) ... }

./screen/DepartureScreen.js

export default DepartureScreen = ({navigation}) => { ... const [ isLoading, displayMessage, channelData ] = useAblyChannel('departures', []) ... ... return ( <Container> {isLoading ? ( <LoadingScreen message={displayMessage} /> ) : ( <> <Content>{DeparturesScreen}</Content> </> )} </Container> ) ... }

Delete this import from both your DepartureScreen and ArrivalScreen since our data will be coming from live data stream using the hooks:

./screens/ArrivalScreens.js

import { arrival as channelData } from '../constants/RawData'

./screens/DepartureScreens.js

import { departures as channelData } from '../constants/RawData'

Next, open up ./components/ListCards.js and add a little bit of spice to make the cards clickable.

export const ListCards = ({ text, rotate, action }) => { ... return ( <Card noShadow> <CardItem button onPress={() => handleActions(action)}> ... </CardItem> </Card> ) ... }

Adding the button property to the CardItem makes the button clickable.

Save and play around with the project a little bit. Click on a ListCard and to launch the Flight Tracking. Your Application should look like the Gif we have played above.

Step 8: Cleaning up and Finalising

Let’s quickly add a search function to our application. Update both ./screen/ArrivalScreen.js and ./screen/DepartureScreen.js

... import FabButton from '../components/FabButton' export default DepartureScreen = ({navigation}) => { ... ... ... return ( <Container> {isLoading ? ( <LoadingScreen message={displayMessage} /> ) : ( <> <Content>{Arrivals}</Content> <FabButton navigation={navigation} channelData={channelData}/> </> )} </Container> ) ... }

Save and right now your application should look and feel like this:

Summary

You’ve successfully built a realtime flight tracking application that tracks the real-world flights’ location and shows it on a map. How cool!.