Updated January 18, 2017
React Native Basics: Geolocation
Originally publish on medium.com.
I’ve been using the Geolocation API in React Native a fair amount lately. It’s an API that I didn’t realize existed in React Native and definitely didn’t realize how easy it was to actually use.
React Native has some great polyfills that bring APIs that we’ve gotten used to on the web to mobile which makes using them insanely easy. The Geolocation API in React Native is simply an extension of the web spec. This post will basically be a rehash of the official documentation with some additional commentary and examples. I encourage you to read the official documentation in addition to this.
Installation
Installation is really straightforward. On iOS the necessary key in the Info.plist (NSLocationWhenInUseUsageDescription) is already set when you create a new app. If you want to use a user’s location when the app is in the background you’ll have to do some additional configuration.
On Android it’s similarly simple, just not enabled by default. In your AndroidManifest.xml you’ll need to add the following permission request
<uses-permission android:name="android.permission.ACCESS\_FINE\_LOCATION" />
The reason it comes enabled by default on iOS but not Android comes down to how & when each platform requests permission to use location data. On iOS permission is requested the first time you try to use it, on Android it’s requested upon app download. Because of this if the location permission came enabled by default on Android a user will see what it’s requesting (location data) and if your app doesn’t have a good reason to need their location information then they may not download your app.
API Overview
The geolocation api exists on the global navigator
object in React Native, just like on the web, so you would access it via navigator.geolocation
.
I’ll be covering three of the methods available on navigator.geolocation
— getCurrentPosition
, watchPosition
, and clearWatch
.
getCurrentPosition allows us to request a user’s location at any time. It accepts three parameters — a success callback, an error callback, and a configuration object (in that order). The success callback will be passed an object that looks like
response.json
{
"timestamp": 1484669056399.49,
"coords": {
"accuracy": 5,
"altitude": 0,
"altitudeAccuracy": -1,
"heading": -1,
"latitude": 37.785834,
"longitude": -122.406417,
"speed": -1
}
}
The error callback will be passed a standard error message. And finally the config object has
- enableHighAccuracy (boolean)— which allows you to get the most accurate location. Due to how it gets the location (via GPS) it may be slower to return a result but it will be more accurate when enabled.
- timeout (milliseconds)— how long does the API have to return the position before throwing an error?
- maximumAge (milliseconds) — if a location exists in the device cache, how old can it be before it’s no longer valuable to your app?
watchPosition is very similar to getCurrentPosition. The only difference is that the success or error callback will be called whenever the user’s location updates. There’s also an extra option in the config object and that’s distanceFilter
this will allow you to specify how many meters a user has to move before a callback is triggered again.
clearWatch should be used any time watchPosition
is used. This will tell the device that your app no longer needs location information. Just like you should always clear an interval, you should always clear a position watch when the app unmounts or you no longer need it.
getCurrentPosition Example
GeolocationExample.js
import React, { Component } from 'react';
import { View, Text } from 'react-native';
class GeolocationExample extends Component {
constructor(props) {
super(props);
this.state = {
latitude: null,
longitude: null,
error: null,
};
}
componentDidMount() {
navigator.geolocation.getCurrentPosition(
(position) => {
this.setState({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
error: null,
});
},
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }
);
}
render() {
return (
<View
style={{ flexGrow: 1, alignItems: 'center', justifyContent: 'center' }}
>
<Text>Latitude: {this.state.latitude}</Text>
<Text>Longitude: {this.state.longitude}</Text>
{this.state.error ? <Text>Error: {this.state.error}</Text> : null}
</View>
);
}
}
export default GeolocationExample;
You can see above just how simple it is to access the current location with this API.
watchPosition Example
GeolocationExample.js
import React, { Component } from 'react';
import { View, Text } from 'react-native';
class GeolocationExample extends Component {
constructor(props) {
super(props);
this.state = {
latitude: null,
longitude: null,
error: null,
};
}
componentDidMount() {
this.watchId = navigator.geolocation.watchPosition(
(position) => {
this.setState({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
error: null,
});
},
(error) => this.setState({ error: error.message }),
{
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 1000,
distanceFilter: 10,
}
);
}
componentWillUnmount() {
navigator.geolocation.clearWatch(this.watchId);
}
render() {
return (
<View
style={{ flexGrow: 1, alignItems: 'center', justifyContent: 'center' }}
>
<Text>Latitude: {this.state.latitude}</Text>
<Text>Longitude: {this.state.longitude}</Text>
{this.state.error ? <Text>Error: {this.state.error}</Text> : null}
</View>
);
}
}
export default GeolocationExample;
You can see there that using watch position is very similar to fetching the position, it just happens whenever the location changes. It’s important to note two things
- Make sure to clear the watch when the component is unmounted (see line 30)
- If you don’t need realtime updating location information use getCurrentPosition instead as it will be less battery intensive