I am trying to get the user location in my React Native app and move my MapView to that location. When the app loads, it shows the location (by default, not because of my action), but when the action is executed I get this error:
Exception thrown while executing UI block:
Invalid Region <center:+37.33233141, -122.03121860 span: +0.00044916, -0.05737702>
The region object being passed to my MapView (from my location actions) is
{
latitude: 37.33233141,
longitude: -122.0312186,
accuracy: 0.05,
latitudeDelta: 0.0004491555874955085,
longitudeDelta: -0.05737702242408729
};
I actually copied the code from an old project that had had the same problem and then at some point stopped having the problem.
Anyway, here's my code:
MapScreen.js
import React, { Component } from "react";
import MapView, { Marker, Callout } from "react-native-maps";
import { connect } from "react-redux";
import { View, Button, Text, Platform, TextInput } from "react-native";
const CurrentRegionMarker = ({ currentRegion }) => {
return currentRegion && currentRegion.showMarker ? (
<Marker coordinate={currentRegion} pinColor={"green"} />
) : null;
};
class MapScreen extends Component {
state = { region: null };
render() {
return (
<View style={styles.container}>
<MapView
style={{ flex: 1 }}
showsUserLocation={true}
region={this.props.currentRegion}
>
<CurrentRegionMarker currentRegion={this.props.currentRegion} />
</MapView>
</View>
);
}
}
export default connect(({ location }) => ({
currentRegion: location.currentRegion
}))(MapScreen);
locationActions.js
// #flow
import * as Location from "expo-location";
import * as Permissions from "expo-permissions";
import type {
Location as LocationType,
LocationAction
} from "../reducers/locationReducer";
import type { Saga } from "redux-saga";
import { call, put, select, takeEvery, all } from "redux-saga/effects";
export function getLocationAsync(): LocationAction {
return { type: "USER_LOCATION_START" };
}
export function* getLocationSaga(): Saga<void> {
try {
const region = yield call(getUserLocation);
yield put({ type: "USER_LOCATION_SUCCESS", region });
} catch (error) {
yield put({ type: "USER_LOCATION_FAILURE", error: error.message });
}
}
async function getUserLocation(): LocationType {
let { status } = await Permissions.askAsync(Permissions.LOCATION);
if (status !== "granted") {
return console.warn("Permission to access location was denied");
}
let location = await Location.getCurrentPositionAsync({});
let { latitude, longitude } = location.coords;
let accuracy = 0.05;
let region = { latitude, longitude, accuracy };
console.log("direct", calculateRegion(region));
console.log("interpolated", { ...region, ...calculateRegion(region) });
return { ...calculateRegion(region), accuracy };
}
function calculateRegion({
latitude,
longitude,
accuracy = 0.05
}): LocationType {
const oneDegreeOfLongitudeInMeters = 111.32;
const circumference = 40075 / 360;
const latitudeDelta = accuracy / oneDegreeOfLongitudeInMeters;
const longitudeDelta = accuracy * (1 / Math.cos(latitude * circumference));
const region = { latitude, longitude, latitudeDelta, longitudeDelta };
return region;
}
export default function* locationSaga(): Saga<void> {
yield all([yield takeEvery("USER_LOCATION_START", getLocationSaga)]);
}
locationReducer.js
// #flow
const initialState: LocationState = {
currentRegion: {
latitude: 0,
longitude: 0,
latitudeDelta: 0.00922,
longitudeDelta: 0.00421,
showMarker: false
}
};
export default function dealsReducer(
state: LocationState = initialState,
action: LocationAction
): LocationState {
switch (action.type) {
case "USER_LOCATION_SUCCESS":
return { ...state, currentRegion: action.region };
case "USER_LOCATION_FAILURE":
return { ...state, error: action.error };
default:
return state;
}
}
export type Location = {
latitude: number,
longitude: number,
latitudeDelta: number,
longitudeDelta: number,
showMarker?: boolean
};
type LocationState = {
+currentRegion: Location,
+error: ?string
};
export type LocationAction =
| { type: "USER_LOCATION_START" }
| {
type: "USER_LOCATION_SUCCESS",
region: Location
}
| {
type: "USER_LOCATION_FAILURE",
error: string
};
Update: It appears that the longitudeDelta and latitudeDelta values were the problem. Right now I'm using hard-coded values for these, but I'm still not sure why this code is working as is in one app and not another.
Related
can someone help me why is my marker not showing my location
when I remove lat and lon and replace it with actual latitude and longitude it works. when i console log lat and lon it comes up with the right coords but still has an error
import React from 'react'
import MapView, { Marker, PROVIDER_GOOGLE } from 'react-native-maps'
import { Entypo } from "#expo/vector-icons";
import { Feather } from "#expo/vector-icons";
import { Ionicons } from "#expo/vector-icons";
import { useNavigation } from '#react-navigation/native'
import * as Location from 'expo-location'
import { useState, useEffect } from 'react'
import { API, Auth, graphqlOperation } from 'aws-amplify';
const MapScreen = () => {
const [location, setLocation] = useState(null)
const [errMsg, setErrMsg] = useState(null)
const [lat, setLat] = useState(null)
const [lon, setLon] = useState(null)
useEffect(() => {
(async () => {
let {status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
setErrMsg('Location denied!');
return;
}
let location = await Location.getCurrentPositionAsync()
setLocation(location)
setLat(location.coords.latitude)
setLon(location.coords.longitude)
console.log(location)
})();
}, []);
let text = 'Waiting..'
if (errMsg) {
text = errMsg;
} else if (location) {
text = JSON.stringify(location)
console.log(text)
}
const signOut = () => {
Auth.signOut();
};
const navigation = useNavigation()
return (
<View style={{marginTop:33}}>
<MapView
zoomEnabled={true}
provider={PROVIDER_GOOGLE}
style={{width:"100%", height:"100%"}}
initialRegion={{
latitude: -36.8491788,
longitude: 174.7574553,
latitudeDelta: 0.07,
longitudeDelta: 0
}}
>
<Marker
coordinate={{
latitude: lat,
longitude: lon,
}}
onPress={() => navigation.navigate('Home')}
>
</Marker>
</MapView>
i am getting the issue Warning: Failed %s type: %s%s, prop, The prop coordinate.longitude is marked as required in MapMarker, but its value is null.,
I am working with react native maps and react native geocoding, I want to pass the current user location to the redux store using mapDispatchToProps, and to be able to use that location on a different map component. I am roughly a newbie in the redux world and I am a bit confused. kindly make corrections to my code below. I have tried using the example implemented on the documentation, however, I do not fully understand
Location 1
import React, { Component, Fragment } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
} from 'react-native';
import { connect } from 'react-redux';
import MapView from 'react-native-maps';
import Geocoder from 'react-native-geocoding';
Geocoder.init('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
const LONGITUDEDELTA = 0.0173;
const LATITUDEDELTA = 0.0174;
class Location1 extends Component {
static navigationOptions = {
header: null,
}
constructor(props) {
super(props);
this.state = {
region: null,
};
this.handleBack = this.handleBack.bind(this);
}
async componentDidMount() {
this.watchId = navigator.geolocation.watchPosition(
async ({ coords: { latitude, longitude } }) => {
const response = await Geocoder.from({ latitude, longitude });
const address = response.results[0].formatted_address;
const location = address.substring(0, address.indexOf(','));
this.setState({
location,
region: {
latitude,
longitude,
title: location,
latitudeDelta: LATITUDEDELTA,
longitudeDelta: LONGITUDEDELTA,
},
});
}, //sucesso
() => {}, //erro
{
timeout: 2000,
enableHighAccuracy: true,
maximumAge: 1000
}
);
}
componentWillUnmount() {
navigator.geolocation.clearWatch(this.watchId);
}
render() {
const { region } = this.state;
const { container, map, } = styles;
return (
<View style={container}>
<MapView
style={map}
region={region}
loadingEnabled
showsCompass
showsTraffic
showsBuildings
showsIndoors
>
</MapView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
map: {
...StyleSheet.absoluteFill,
},
});
function mapDispatchToProps(dispatch) {
return {
region: () => {
dispatch(this.state.region);
},
location: () => {
dispatch(this.state.location); // address name
}
}
}
export default connect(mapDispatchToProps) (Location1);
Location2
import React, { Component, Fragment } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
} from 'react-native';
import { connect } from 'react-redux';
import MapView from 'react-native-maps';
import Geocoder from 'react-native-geocoding';
const LONGITUDEDELTA = 0.0173;
const LATITUDEDELTA = 0.0174;
class Location2 extends Component {
static navigationOptions = {
header: null,
}
constructor(props) {
super(props);
this.state = {
region: null,
};
}
render() {
const { container, map, } = styles;
return (
<View style={container}>
<MapView
style={map}
region={this.props.region}
loadingEnabled
showsCompass
showsTraffic
showsBuildings
showsIndoors
>
</MapView>
<View><Text>{this.props.location}</Text></View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
map: {
...StyleSheet.absoluteFill,
},
});
function mapStateToProps(state) {
return {
region: state.region,
location: state.location
}
}
export default connect(mapStateToProps) (Location2);
Reducer
import { CURRENT_LOCATION, LOCATION_NAME } from '../actions/types';
const initialState = {
region: null,
location: ''
};
const Reducer = (state = initialState, action) => {
switch (action.type) {
case CURRENT_LOCATION:
return {
...state,
region: action.region
};
case LOCATION_NAME:
return {
...state,
location: action.location
};
default:
return state;
}
};
export default Reducer;
Firstly in the first code here
function mapDispatchToProps(dispatch) {
return {
region: () => {
dispatch(this.state.region);
},
location: () => {
dispatch(this.state.location); // address name
}
}
}
export default connect(mapDispatchToProps) (Location1);
you need to pass the first argument to connect wich is the mapStateToProps but if you don't wanna use it pass null instead
export default connect(mapStateToProps, mapDispatchToProps)(Location1);
and also you dispatch actions in redux by passing and actionType(required) and a actionPayload(optional)
function mapDispatchToProps(dispatch) {
return {
region: (regionVal) => {
dispatch({type: 'LOCATION_NAME',payload: regionVal});
},
location: (locationVal) => {
dispatch({type: 'CURRENT_LOCATION',payload: locationVal}); // address name
}
}}
and call it inside the componentDidMount like
async componentDidMount() {
.
.
.
this.props.region(regionVal);
this.props.locatio(locationVal);
}
and in the reducer you should fix this
case CURRENT_LOCATION:
return {
...state,
region: action.region
};
to something like this
case CURRENT_LOCATION:
return {
...state,
region: action.payload // you should call the payload from the action
};
Hey Guys Iam getting an error on my Android Devices.
On Iphone it works very well I'am getting my Markers in maps but on Android iam getting this Error
Click for the Image
Since i upgraded the Code with geolib where iam filtering markers out which are not near to me it won't work on Android...
Anybody an idea?
this is my Code:
import React from 'react';
import MapView from 'react-native-maps';
import Marker from 'react-native-maps';
import Geolib from 'geolib';
import {
View,
Text,
StyleSheet,
Button,
} from "react-native";
const geolib = require('geolib');
class Grillplaetze extends React.Component {
constructor() {
super();
this.state = {
markers: [],
loaded: false
}
}
componentDidMount() {
this.getPosition();
}
getPosition(){
navigator.geolocation.getCurrentPosition(
(position) => {
console.log(position);
this.setState({
region: {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
latitudeDelta: 0.020,
longitudeDelta: 0.020,
}
}, () => this.getLocations());
},
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: false, timeout: 200000, maximumAge: 1000 },
);
}
getLocations() {
return fetch('http://media-panda.de/bp/whs.geojson')
.then(response => response.json())
.then(responseData => {
let { region } = this.state;
let { latitude, longitude } = region;
let markers = responseData.features.map(feature => {
let coords = feature.geometry.coordinates
return {
coordinate: {
latitude: coords[1],
longitude: coords[0],
}
}
}).filter(marker => {
let distance = this.calculateDistance(latitude, longitude, marker.coordinate.latitude, marker.coordinate.longitude);
return distance <= 500;
});
this.setState({
markers: markers,
loaded: true,
});
}).done();
}
calculateDistance(origLat, origLon, markerLat, markerLon) {
return geolib.getDistance(
{latitude: origLat, longitude: origLon},
{latitude: markerLat, longitude: markerLon}
);
}
render() {
return (
<View style={styles.container}>
<MapView.Animated
style={styles.map}
region={this.state.region}
showsUserLocation={true}
>
{this.state.markers.map(marker => (
<MapView.Marker
coordinate={marker.coordinate}
/>
))}
<MapView.Circle
key = { (this.state.latitude + this.state.longitude).toString() }
center = { this.state.region }
radius = { 500 }
strokeWidth = { 1 }
strokeColor = { '#1a66ff' }
fillColor = { 'rgba(230,238,255,0.5)' }
/>
</MapView.Animated>
</View>
);
}
}
export default Grillplaetze;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ecf0f1',
},
map: {
width: "100%",
height: "100%",
},
})
Your errors aren't related to your implementation of the geolib but instead they are due to your implementation of the MapView.Circle.
If we look at the documentation the MapView.Circle we see the following:
| Prop | Type | Default | Note |
|----------|----------|------------|------------------------------------------------|
| `center` | `LatLng` | (Required) | The coordinate of the center of the circle .
| `radius` | `Number` | (Required) | The radius of the circle to be drawn (in meters)
Both the center and the radius are required fields.
If we look at your code:
<MapView.Circle
key = { (this.state.latitude + this.state.longitude).toString() }
center = { this.state.region }
radius = { 500 }
strokeWidth = { 1 }
strokeColor = { '#1a66ff' }
fillColor = { 'rgba(230,238,255,0.5)' }
/>
It would appear that you have set them, however you have not actually set the region. You can confirm this by checking your initial state.
constructor () {
super();
this.state = {
markers: [],
loaded: false
}
}
Notice that you have not set an initial region for the map. This is what is causing your error. The app is trying to handle the undefined value for the region.
To overcome this the easiest way is to set an initial region for the map in state.
Something like this:
constructor () {
super();
this.state = {
markers: [],
loaded: false,
region: {
latitude: 0,
longitude: 0,
latitudeDelta: 0.020,
longitudeDelta: 0.020
},
latitude: 1,
longitude: 1
};
}
If you app is for a specific region then it may make sense to pick an initial region that is close to where you app is going to be used.
Also note in your MapView.Circle code you are also using undefined values of latitude and longitude for the key. I don't think that you need to define a key property for the MapView.Circle. I cannot find any mention of this being a requirement in the documentation.
Making the above changes allows the code to work.
Some other points.
You are importing geolib twice. You only need to do it once. You should either have import GeoLib from 'geolib'; or const geolib = require('geolib'); you don't need both. Seeing as you are using geolib with a lower case, I would just remove import GeoLib from 'geolib';
You are importing Markers from react-native-maps in the wrong way. It should be imported as import { Markers } from 'react-native-maps, however you are using the Markers as MapView.Markers which is absolutely fin. I think you can remove the unused and incorrect import Markers from 'react-native-maps
MapView.Animated I am not 100% that this is correct or required. I haven't seen it used in this way before. However if it is not causing you issues then I suppose it isn't really a problem.
You should also add a key prop on your Markers so that you suppress the warning that it is missing. This should be something unique.
I'm using Expo together with react-native-maps for a rather simple map component. It works fine on iOS, however on Android I get the following error:
abi30_0_0.com.facebook.react.bridge.ReadableNativeMap cannot be cast to java.lang.String
getString
ReadableNativeMap.java:168
showAlert
DialogModule.java:247
invoke
Method.java
invoke
JavaMethodWrapper.java:372
invoke
JavaModuleWrapper.java:160
run
NativeRunnable.java
handleCallback
Handler.java:790
dispatchMessage
Handler.java:99
dispatchMessage
MessageQueueThreadHandler.java:29
loop
Looper.java:164
run
MessageQueueThreadImpl.java:192
run
Thread.java:764
Here is my map component (sorry it's a bit longer):
import React from 'react';
import {
StyleSheet,
View,
Dimensions,
Alert,
TouchableOpacity,
Text,
Platform,
} from 'react-native';
import {
MapView,
Location,
Permissions,
Constants,
} from 'expo';
import { Ionicons } from '#expo/vector-icons';
import axios from 'axios';
import geolib from 'geolib';
import Polyline from '#mapbox/polyline';
import api from '../helpers/api';
import appConfig from '../app.json';
const { width, height } = Dimensions.get('window');
class MapScreen extends React.Component {
static navigationOptions = {
title: 'Map',
};
constructor(props) {
super(props);
this.state = {
coordinates: [],
focusedLocation: {
latitude: 0,
longitude: 0,
latitudeDelta: 0.0122,
longitudeDelta: width / height * 0.0122,
},
destinationReached: false,
isMapReady: false,
};
this.apikey = appConfig.expo.android.config.googleMaps.apiKey;
// bind this in constructor so state can be set in these methods
this.getLocation = this.getLocation.bind(this);
this.getDirections = this.getDirections.bind(this);
this.checkUserLocation = this.checkUserLocation.bind(this);
this.animateToCoordinates = this.animateToCoordinates.bind(this);
}
async componentDidMount() {
// ask the user for location permission
if (Platform.OS === 'android' && !Constants.isDevice) {
Alert.alert('Warning', 'This will not work on sketch in an android emulator. Try it on your device!');
return;
}
if (await !this.isPermissionGranted(Permissions.LOCATION)) {
Alert.alert('Permission', 'You need to enable location services');
return;
}
// get the current location of the user
// retrieve the destination location where the users shift will start
const [currentLocation, destinationLocation] = await Promise.all([
this.getLocation(),
this.getInterceptionCoords(),
]);
// retrieve a direction between these two points
this.getDirections(currentLocation, destinationLocation);
// monitor the current position of the user
this.watchid = await Location.watchPositionAsync({
enableHighAccuracy: true,
distanceInterval: 1,
}, this.checkUserLocation);
}
componentWillUnmount() {
if (this.watchid) {
this.watchid.remove();
}
}
/**
* retrieve current coordinates and move to them on the map
* assumes that location permission has already been granted
* #returns {Promise<{latitude: (number|*|string), longitude: (number|*|string)}>}
*/
async getLocation() {
// get current position if permission has been granted
const { coords } = await Location.getCurrentPositionAsync({
enableHighAccuracy: true,
});
// initalize map at current position
this.animateToCoordinates(coords);
this.setState(prevState => {
return {
focusedLocation: {
...prevState.focusedLocation,
latitude: coords.latitude,
longitude: coords.longitude,
},
};
});
return {
latitude: coords.latitude,
longitude: coords.longitude,
};
}
/**
* retrieves the coordinates of a route
* route: safety drivers position to the interception point
* #param startLoc
* #param destinationLoc
* #returns {Promise<*>}
*/
async getDirections(startLoc, destinationLoc) {
try {
const response = await axios({
method: 'GET',
url: 'https://maps.googleapis.com/maps/api/directions/json',
params: {
origin: Object.values(startLoc).join(','),
destination: Object.values(destinationLoc).join(','),
key: this.apikey,
},
responseType: 'json',
headers: {},
});
if (response.status !== 200) {
// this will execute the catch block
throw new Error('Fetching the coordinates of the interception point failed');
}
const { data } = response;
if (data.status !== 'OK') {
throw new Error('Determining a route between the two points failed');
}
const points = Polyline.decode(data.routes[0].overview_polyline.points);
const coordinates = points.map(point => {
return {
latitude: point[0],
longitude: point[1],
};
});
this.setState({ coordinates: coordinates });
return coordinates;
} catch (error) {
console.log(error);
Alert.alert('Network error', error);
return error;
}
}
/**
* get the coordinates of the interception point
* #returns {Promise<*>}
*/
async getInterceptionCoords() {
try {
const response = await api.get('/shifts/next');
if (response.status !== 200) {
// this will execute the catch block
throw new Error('Fetching the coordinates of the interception point failed');
}
const { data } = response;
return {
latitude: data.latStart,
longitude: data.longStart,
};
} catch (error) {
console.log(error);
Alert.alert('Network error', error);
return error;
}
}
checkUserLocation(location) {
const { coordinates } = this.state;
const { coords } = location;
if (Platform.OS === 'android') {
// follow the user location
// mapview component handles this for ios devices
this.animateToCoordinates(coords);
}
const destinationCoords = coordinates[coordinates.length - 1];
const distance = geolib.getDistance(coords, destinationCoords);
if (distance <= 20) {
// distance to destination is shorter than 20 metres
// show button so user can confirm arrival
this.setState({ destinationReached: true });
} else {
// remove arrival button in case the user moves away from the destination
this.setState({ destinationReached: false });
}
}
/**
* animate to specified coordinates on the map
* #param coords
*/
animateToCoordinates(coords) {
const { focusedLocation } = this.state;
const { latitude, longitude } = coords;
if (focusedLocation && latitude && longitude) {
this.map.animateToRegion({
...focusedLocation,
latitude: latitude,
longitude: longitude,
});
}
}
renderConfirmalButton() {
const { destinationReached } = this.state;
if (!destinationReached) {
return null;
}
return (
<View style={styles.confirmContainer}>
<TouchableOpacity
style={styles.confirmButton}
onPress={this.onArrivalConfirmed}
>
<View style={styles.drawerItem}>
<Ionicons
name="ios-checkmark-circle-outline"
size={30}
color="#ffffff"
style={styles.drawerItemIcon}
/>
<Text style={styles.buttonText}>Confirm Arrival</Text>
</View>
</TouchableOpacity>
</View>
);
}
isPermissionGranted = async permission => {
const { status } = await Permissions.askAsync(permission);
return (status === 'granted');
};
onArrivalConfirmed = () => {
Alert.alert('Confirmation', 'Arrival confirmed');
};
onMapReady = () => {
this.setState({ isMapReady: true });
};
render() {
const { coordinates, focusedLocation, isMapReady } = this.state;
return (
<View style={styles.container}>
<MapView
style={styles.map}
initialRegion={focusedLocation}
showsUserLocation
followsUserLocation={Platform.OS === 'ios'}
loadingEnabled
ref={map => { this.map = map; }}
onMapReady={() => this.onMapReady()}
>
<MapView.Polyline
coordinates={coordinates}
strokeWidth={3}
strokeColor="blue"
/>
{isMapReady && coordinates.length > 0 && (
<MapView.Marker
coordinate={coordinates[coordinates.length - 1]}
/>
)}
</MapView>
{this.renderConfirmalButton()}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
map: {
width: width,
height: height,
},
confirmContainer: {
position: 'absolute',
left: 0,
bottom: 0,
height: 150,
width: '100%',
justifyContent: 'center',
},
confirmButton: {
paddingHorizontal: 30,
},
drawerItem: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
padding: 10,
backgroundColor: 'lightblue',
borderRadius: 15,
},
drawerItemIcon: {
marginRight: 10,
},
buttonText: {
color: '#ffffff',
fontSize: 22,
},
});
export default MapScreen;
Any help is greatly appreciated!
I'm following this tutorial on React Native Maps: https://www.youtube.com/watch?v=MqLC0kOqrwk&t=1s
My code is near identical to the tutors (I didn't use MapView.Markers) but I get this error: Attempt to invoke interface method 'boolean
abi19_0_0.com.facebook.react.bridge.ReadableMap.hasKey(java.lang.String)' on a null object reference
Here is my code:
import React from 'react';
import { View, Text, StyleSheet, Dimensions } from 'react-native';
import MapView from 'react-native-maps';
const { width, height } = Dimensions.get ('window')
const SCREEN_HEIGHT = height
const SCREEN_WIDTH = width
const ASPECT_RATIO = width / height
const LATITUDE_DELTA = 0.0922
const LONGTITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO
export default class MapScreen extends React.Component {
constructor (props) {
super (props)
this.state = {
initialPosition: {
latitude: 0,
longitude: 0,
latitudeDelta: 0,
longitudeDelta: 0,
}
}
}
watchID: ?number = null
componentDidMount () {
navigator.geolocation.getCurrentPosition ((position) => {
var lat = parseFloat (position.coords.latitude)
var long = parseFloat (position.coords.longitude)
var initialRegion = {
latitude: lat,
longitude: long,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGTITUDE_DELTA
}
this.setState ({ initialPosition: initialRegion })
},
(error) => alert (JSON.stringify (error)),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 })
this.watchID = navigator.geolocation.watchPosition ((position) => {
var lat = parseFloat (position.coords.latitude)
var long = parseFloat (position.coords.longitude)
var lastRegion = {
latitude: lat,
longitude: long,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGTITUDE_DELTA
}
this.setState ({ initialPosition: lastRegion })
})
}
componentWillUnmount () {
navigator.geolocation.clearWatch (this.watchID)
}
render () {
return (
<MapView
style = { styles.mapContainer }
region = {this.state.initialPosition}
/>
);
}
}
Managed to get this working in a new react-native init project (RN 0.47.1, RNMaps 0.16.0) with the following added to ./android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="WHATEVERYOURAPIKEYIS" />