Fala Samurai, beleza?
Aqui vamos nós com mais um tutorial para React Native.
Dessa vez nós iremos destrinchar outro caso de uso bastante requisitado para desenvolvimento mobile que é o uso de mapas e geolocalização.
Índice
Considerações iniciais
Iremos partir de uma aplicação React Native do zero, gerada pelo:
react-native init SamuraiMap
Para esse tutorial, a ideia é trazer uma tela com um mapa com uma
View
para nos informar a latitude e longitude atual e um botão que ao clicar fará uso da geolocalização para pegar a localização atual e marcar no mapa.
Essa é uma prévia da aplicação:

Preparando o layout
Nesse caso vamos trabalhar somente no arquivo App.js.
Como iremos precisar de um ícone para nosso layout, já vamos instalar a lib
react-native-vector-icons
e faremos o link para utilizá-la:
yarn add react-native-vector-icons
react-native link react-native-vector-icons
Para exibir o mapa, vamos utilizar a lib
react-native-maps
, então rode o comando:
yarn add react-native-maps
No caso do IOS essa lib pode utilizar o mapa providenciado nativamente.
Mas para o Android temos que utilizar o Google Maps.
Então caso esteja no IOS e queira utilizar o mapa nativo, pode pular essa próxima etapa Gerando uma API-KEY, mas se quiser utilizar o Google Maps no IOS, pode acompanhar.
Gerando uma API-KEY
Acesse o site https://cloud.google.com/console/google/maps-apis/overview, caso não tenha uma conta no Google Cloud Platform, vai precisar criar.
Depois, é preciso criar um novo projeto, pode chamar como quiser, ai dentro do projeto, no menu que pode ser acessado na lateral esquerda, procure por APIS e serviços, deverá chegar em uma tela parecida com essa:

Na opção Credentials, crie uma nova chave de api para todos os serviços e não precisa de por com restrições, COPIE ESSA API-KEY GERADA e cole em algum lugar para usar daqui a pouco.
Depois volte para a opção Painel.
Agora podemos clicar em + ATIVAR APIS E SERVIÇOS e depois ativar o Maps SDK for Android se estiver no Android ou Maps SDK for IOS caso esteja no IOS.
Utilizando o MapView
Voltando no projeto React Native.
Caso esteja em Android, vá em andoroid/app/src/main/AndroidManifest.xml e adicione isso dentro da tag application:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="SUA_API_KEY"/>
Vamos adicionar em nosso App.js um
MapView
com um
Marker
, ambos da lib
react-native-maps
:
import React, {useState} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import MapView, {Marker} from 'react-native-maps';
const App = () => {
const [position, setPosition] = useState({
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
});
return (
<View style={styles.container}>
<MapView
style={styles.map}
region={position}
onPress={e =>
setPosition({
...position,
latitude: e.nativeEvent.coordinate.latitude,
longitude: e.nativeEvent.coordinate.longitude,
})
}>
<Marker
coordinate={position}
title={'Marcador'}
description={'Testando o marcador no mapa'}
/>
</MapView>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
map: {
height: '100%',
width: '100%',
},
});
export default App;
O
MapView
tem suas props e eventos que estão documentados aqui: https://github.com/react-native-community/react-native-maps/blob/master/docs/mapview.md
No nosso app, utilizando a props
region
e o evento
onPress
para manipular um valor de
state
que chamamos de
position
, onde vai armazenar as coordenadas atuais do mapa, sendo os valores atuais, a região de San Francisco, apenas para nossa demonstração.
OBS: Se estiver utilizando o Google Maps no IOS, adicionar mais uma props no
MapView
, chamada
provider
com o valor de google
Rode o comando
react-native run-android
ou
react-native run-ios
.
OBS: Se o build falhar, acusando erro nessa linha:
dev_samurai/SamuraiMap/node_modules/react-native-maps/lib/android/build.gradle' line: 20
Acesse esse arquivo descrito e exatamente na linha acusada (no caso a 20), adicione:
def supportLibVersion = safeExtGet('supportLibVersion', '28.0.0')
A aplicação deve apresentar o mapa e o marcador:

Adicionando o logo, painel e botão
Agora que já exibimos o mapa, vamos adicionar os outros detalhes do layout.
import React, {useState} from 'react';
import {View, Text, TouchableOpacity, StyleSheet} from 'react-native';
import MapView, {Marker} from 'react-native-maps';
import Icon from 'react-native-vector-icons/MaterialIcons';
const App = () => {
const [position, setPosition] = useState({
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
});
return (
<View style={styles.container}>
<MapView
style={styles.map}
region={position}
onPress={e =>
setPosition({
...position,
latitude: e.nativeEvent.coordinate.latitude,
longitude: e.nativeEvent.coordinate.longitude,
})
}>
<Marker
coordinate={position}
title={'Marcador'}
description={'Testando o marcador no mapa'}
/>
</MapView>
<View style={styles.positonBox}>
<Text style={styles.positonBoxTitle}>Sua Localização</Text>
<View style={styles.positonBoxLatLon}>
<Text style={{fontSize: 18}}>Lat.</Text>
<Text style={{fontSize: 18}}>{position.latitude}</Text>
</View>
<View style={styles.positonBoxLatLon}>
<Text style={{fontSize: 18}}>Lon.</Text>
<Text style={{fontSize: 18}}>{position.longitude}</Text>
</View>
</View>
<TouchableOpacity style={styles.locationButton} onPress={() => {}}>
<Icon name="my-location" color={'#fff'} size={30} />
</TouchableOpacity>
<View style={styles.logo}>
<Text style={styles.logoText}>Samurai</Text>
<Text style={[styles.logoText, {color: '#e74c3c'}]}>Map</Text>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
map: {
height: '100%',
width: '100%',
},
logo: {
backgroundColor: '#fff',
borderRadius: 15,
paddingHorizontal: 15,
elevation: 5,
marginTop: -730,
alignSelf: 'center',
marginRight: 10,
flexDirection: 'row',
},
logoText: {
fontWeight: 'bold',
fontSize: 22,
},
positonBox: {
backgroundColor: '#fff',
borderRadius: 20,
opacity: 0.75,
marginTop: -170,
marginHorizontal: 40,
padding: 25,
shadowColor: '#000',
elevation: 5,
},
positonBoxTitle: {
textAlign: 'center',
fontSize: 22,
fontWeight: 'bold',
color: '#e74c3c',
},
positonBoxLatLon: {flexDirection: 'row', justifyContent: 'space-between'},
locationButton: {
backgroundColor: '#e74c3c',
borderRadius: 150,
marginTop: -25,
width: 50,
height: 50,
alignSelf: 'center',
justifyContent: 'center',
alignItems: 'center',
shadowColor: '#000',
elevation: 8,
},
});
export default App;
Com isso sua aplicação já deve estar com o layout igual a da prévia.
Agora falta adicionar a Geolocalização e colocar a função no botão.
Adicionando a Geolocalização
O sentido da geolocalização no nosso exemplo é para ao clicar a
position
do mapa receber a localização atual em que estamos.
Para isso vamos utilizar uma lib chamada
react-native-geolocation-service
, ela proverá funções para pegar a localização do GPS do celular, por isso, é preciso dar permissão para acessar a nossa localização.
yarn add react-native-geolocation-service
Se estiver no emulador, terá que habilitar o GPS do emulador e definir uma coordenada especifica para simular sua posição atual, no meu caso, como estou utilizando o emulador de Android no Genymotion, a tela de configuração do GPS, é assim:

Caso esteja em Android, vá em andoroid/app/src/main/AndroidManifest.xml e adicione isso dentro da tag manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Agora vamos importar o
Geolocation
da lib
react-native-geolocation-service
e utilizaremos o método
getCurrentPosition
para acessar nossa localização atual.
O método
getCurrentPosition
é assíncrono e podemos usar nesse formato:
Geolocation.getCurrentPosition(
pos => {
setPosition({
...position,
latitude: pos.coords.latitude,
longitude: pos.coords.longitude,
});
},
error => {
console.log(error);
Alert.alert('Houve um erro ao pegar a latitude e longitude.');
},
);
Iremos utilizar esse método no clique no botão para pegar nossa localização, mas precisamos verificar se o usuário deu permissão para acessar o GPS do celular, por isso, vamos criar um método que fará essa verificação e depois pega a posição atual:
import React, {useState} from 'react';
import {
PermissionsAndroid,
Alert,
View,
Text,
TouchableOpacity,
StyleSheet,
} from 'react-native';
import MapView, {Marker} from 'react-native-maps';
import Geolocation from 'react-native-geolocation-service';
import Icon from 'react-native-vector-icons/MaterialIcons';
const App = () => {
const [position, setPosition] = useState({
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
});
const request_location_runtime_permission = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: 'Permissão de Localização',
message: 'A aplicação precisa da permissão de localização.',
},
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
Geolocation.getCurrentPosition(
pos => {
setPosition({
...position,
latitude: pos.coords.latitude,
longitude: pos.coords.longitude,
});
},
error => {
console.log(error);
Alert.alert('Houve um erro ao pegar a latitude e longitude.');
},
);
} else {
Alert.alert('Permissão de localização não concedida');
}
} catch (err) {
console.log(err);
}
};
return (
<View style={styles.container}>
<MapView
style={styles.map}
region={position}
onPress={e =>
setPosition({
...position,
latitude: e.nativeEvent.coordinate.latitude,
longitude: e.nativeEvent.coordinate.longitude,
})
}>
<Marker
coordinate={position}
title={'Marcador'}
description={'Testando o marcador no mapa'}
/>
</MapView>
<View style={styles.positonBox}>
<Text style={styles.positonBoxTitle}>Sua Localização</Text>
<View style={styles.positonBoxLatLon}>
<Text style={{fontSize: 18}}>Lat.</Text>
<Text style={{fontSize: 18}}>{position.latitude}</Text>
</View>
<View style={styles.positonBoxLatLon}>
<Text style={{fontSize: 18}}>Lon.</Text>
<Text style={{fontSize: 18}}>{position.longitude}</Text>
</View>
</View>
<TouchableOpacity
style={styles.locationButton}
onPress={() => {
request_location_runtime_permission();
}}>
<Icon name="my-location" color={'#fff'} size={30} />
</TouchableOpacity>
<View style={styles.logo}>
<Text style={styles.logoText}>Samurai</Text>
<Text style={[styles.logoText, {color: '#e74c3c'}]}>Map</Text>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
map: {
height: '100%',
width: '100%',
},
logo: {
backgroundColor: '#fff',
borderRadius: 15,
paddingHorizontal: 15,
elevation: 5,
marginTop: -730,
alignSelf: 'center',
marginRight: 10,
flexDirection: 'row',
},
logoText: {
fontWeight: 'bold',
fontSize: 22,
},
positonBox: {
backgroundColor: '#fff',
borderRadius: 20,
opacity: 0.75,
marginTop: -170,
marginHorizontal: 40,
padding: 25,
shadowColor: '#000',
elevation: 5,
},
positonBoxTitle: {
textAlign: 'center',
fontSize: 22,
fontWeight: 'bold',
color: '#e74c3c',
},
positonBoxLatLon: {flexDirection: 'row', justifyContent: 'space-between'},
locationButton: {
backgroundColor: '#e74c3c',
borderRadius: 150,
marginTop: -25,
width: 50,
height: 50,
alignSelf: 'center',
justifyContent: 'center',
alignItems: 'center',
shadowColor: '#000',
elevation: 8,
},
});
export default App;
Rode o comando
react-native run-android
ou
react-native run-ios
.
OBS: Pode ser que o build venha a falhar novamente, acusando erro nessa linha:
dev_samurai/SamuraiMap/node_modules/react-native-maps/lib/android/build.gradle' line: 20
Acesse esse arquivo descrito e exatamente na linha acusada (no caso a 20), adicione:
def supportLibVersion = safeExtGet('supportLibVersion', '28.0.0')
Depois só rodar o build novamente.
Agora ao clicar no botão para pegar a localização atual, a primeira vez deverá pedir o acesso e depois irá levar o marcador do mapa para a localização atual \O. Aplicação final, pegando minha localização atual:

Conclusão
Chegamos ao final de mais um tutorial de libs, ferramentas em React Native, nesse tutorial tivemos algumas configurações especiais e um problema de build que foi necessário lidar.
Essas nuances e problemas são perfeitamente normais na vida de um programador e principalmente quando lidamos com ferramentas open-source e que estão em constante atualização.
E como a intenção desses tutoriais e fazer o passo a passo definitivo, exatamente do jeito que nós aprendemos a utilizar as ferramentas aqui na Dev Samurai, também trazemos os problemas que tivemos.
A partir desses labs (como gosto de chamar esses testes de ferramentas) que aprendemos e é assim que depois saímos utilizando e criando aplicações mais complexas e robustas.
Espero que tenham gostado do tutorial e caso não tenham visto sobre utilização da câmera do celular com React Native, acessem aqui: React Native Tutorials: Usando a Câmera do Celular
E não deixe de participar da nossa comunidade no Discord, lá podemos discutir sobre diversos assuntos relacionados a programação e os cursos do Dev Samurai, você vai poder encontrar com o pessoal da equipe Dev Samurai e também toda comunidade que participa e esta engajada em aprender a fazer aplicativos e discutir sobre programação, então segue o link:
Comunidade Dev Samurai no Discord.
Segue o link do repositório para você baixar o código: https://mautic.devsamurai.com.br/asset/12:tutorial-samuraimap
Valeu e até a próxima!
Boa tarde DevSamurai blz? mto obrigado pelo conteudo, tenho uma duvida.. como faço abrir outro navegador de mapa dentro da minha aplicação, exemplo google maps, uber ...
a ideia seria igual ao uber traçar a rota mas abrir uma app a parte para navegar.