Geolocation
Quick backstory
You are mobile experts, I at least expected the Geolocation to work
An unsatisfied client
Yann LEFLOUR
Deputy CTO chez
How to implement a perfect geolocation service...
... and 5 things to learn from it
Back to basics
- The user presses a button
- We display his position
export function getCurrentPosition(timeout, enableHighAccuracy, maximumAge) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject, {
timeout,
enableHighAccuracy,
maximumAge,
});
});
}
Step 1 - Promisify
export default class App extends Component<Props> {
state = {
location: '',
isLoading: false,
};
localize = () => {};
render() {
if (this.state.isLoading)
return (
<View style={styles.container}>
<ActivityIndicator size="large" />
</View>
);
return (
<View style={styles.container}>
<Button title="Localize" onPress={this.localize} />
<Text>{this.state.location}</Text>
</View>
);
}
}
Step 2 - Setup component
localize = () => {
this.setState({ isLoading: true, error: false });
getCurrentPosition(5000)
.then(location => {
this.setState({
isLoading: false,
location: JSON.stringify(location, null, 2),
});
});
};
};
Step 3 - Handle query
The result?
Come on! Why won't you work!
A typical phone user with geolocation service disabled
1st rule
- Inform your user of errors happening
Context:
- The location service is disabled
export function getCurrentPosition(timeout, enableHighAccuracy, maximumAge) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject, {...})
.catch(error => {
switch (error.code) {
case 1:
return Promise.reject(
new Error(ERROR_MESSAGES.GEOLOCATION_PERMISSION_DENIED)
);
case 2:
return Promise.reject(new Error(ERROR_MESSAGES.GEOLOCATION_INACTIVE));
case 3:
return Promise.reject(new Error(ERROR_MESSAGES.GEOLOCATION_TIMEOUT));
default:
return Promise.reject(error);
}
});
});
}
Step 1 - Normalize Errors
localize = () => {
/* ... */
getCurrentPosition()
.then(...)
.catch(error => {
let errorMessage = '';
switch (error.message) {
case ERROR_MESSAGES.GEOLOCATION_INACTIVE:
errorMessage = 'Geolocation service disabled';
}
this.setState({
isLoading: false,
errorMessage: errorMessage,
});
});
};
Step 2 - Translate Error
render() {
if (this.state.isLoading) return (...);
if (this.state.errorMessage)
return (
<View style={styles.container}>
<Button title="Display Position" onPress={this.localize} />
<Text>{`Error: ${this.state.errorMessage}`}</Text>
</View>
);
return (...);
}
Step 3 - Display it
The result?
Dafuk is the location service ?!
A typical phone user with geolocation service disabled
2nd rule
- Help your user handle the error
Context:
- The location service is disabled
- The user is not a developer
How to activate the location service on iOS
The pragmatic solution
The result?
Guess it's faster to uninstall the app
A typical phone user who has to activate the location service manually
3rd rule
- Help resolving the error as much as you can
Context:
- The location service is disabled
- The user is not a developer
- The user is lazy
export function openIosLocationSettings() {
return new Promise((resolve, reject) => {
return Linking.openURL('App-Prefs:root=LOCATION_SERVICES')
.then(() => {
const resolveOnChange = state => {
if (state === 'active') {
AppState.removeEventListener('change', resolveOnChange);
return resolve();
}
};
AppState.addEventListener('change', resolveOnChange);
})
.catch(() => {
reject(new Error(ERROR_MESSAGES.GEOLOCATION_OPEN_SETTINGS_FAILED));
});
});
}
Step 1 - Create service to open location settings
// App.js
displayLocationServiceDisabledAlert = () => {
return new Promise((resolve, reject) => {
Alert.alert(
'Location service disabled',
'Please activate it in order to display your position',
[
{
text: 'Later',
onPress: () => {
reject(new Error(ERROR_MESSAGES.GEOLOCATION_INACTIVE));
},
},
{
text: 'Activate',
onPress: () => {
resolve(openLocationSettings());
},
},
]
);
});
};
Step 2 - Add alert on error
// App.js
localize = () => {
this.setState({ isLoading: true, error: false });
getCurrentPosition()
.catch(error => {
switch (error.message) {
case ERROR_MESSAGES.GEOLOCATION_INACTIVE:
return this.displayLocationServiceDisabledAlert()
.then(this.localize);
}
})
.then(...) // Preserve success message display
.catch(...); // Preserve error message display
};
Step 3 - Display alert on error
The result?
I'm getting really tired with this...
A typical phone user who denied location access to your app
New 1st rule
- Plan out your error flow beforehand
The geolocation error flow
The result?
The result?
The 4 takeaways
- Plan your error flow beforehand
- Inform your user of errors happening
- Tell them how to handle them
- Facilitate any error handling action you can
- Don't waste time
React Native Geolocation Suite
yarn add @bam.tech/react-native-geolocation-suite
# OR
npm install @bam.tech/react-native-geolocation-suite
Questions?
Geolocation
By Yann Leflour
Geolocation
- 987