Reputation: 135
I am trying use expo-location and expo-task-manager to find the users position both when the app is in the foreground and in the background. I am compiling the code using expo without using Xcode. The problem is that the code I provide gives me two errors:
[Unhandled promise rejection: Error: One of the `NSLocation*UsageDescription` keys must be present in Info.plist to be able to use geolocation.]
at node_modules\@babel\runtime\helpers\construct.js:null in <global>
at node_modules\@babel\runtime\helpers\wrapNativeSuper.js:null in _wrapNativeSuper
- ... 3 more stack frames from framework internals
and:
[Unhandled promise rejection: Error: Background Location has not been configured. To enable it, add `location` to `UIBackgroundModes` in Info.plist file.]
at node_modules\@babel\runtime\helpers\construct.js:null in <global>
at node_modules\@babel\runtime\helpers\wrapNativeSuper.js:null in _wrapNativeSuper
- ... 3 more stack frames from framework internals
these errors refer to the infoPlist setup within my App.json:
"infoPlist": {
"UIBackgroundModes": ["location"],
"NSLocationWhenInUseUsageDescription": "To allow the user to start recording a run...",
"NSLocationAlwaysUsageDescription": "To allow the distance to be measured even when the phone is turned off"
"NSLocationAlwaysAndWhenInUseUsageDescription": "Allow $(PRODUCT_NAME) to use your location to track your runs"
}
These errors ocurr even though it is clear that the UIBackgroundModes is set up as well as the NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription.
Code that is being run:
App.js:
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import UserLocation from "./UserLocation"
export default function App() {
return (
<View style={styles.container}>
<UserLocation />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
UserLocation.js:
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import * as Location from 'expo-location';
import * as TaskManager from 'expo-task-manager';
const LOCATION_TRACKING = 'location-tracking';
var l1;
var l2;
export default function UserLocation() {
const [locationStarted, setLocationStarted] = React.useState(false);
const startLocationTracking = async () => {
await Location.startLocationUpdatesAsync(LOCATION_TRACKING, {
accuracy: Location.Accuracy.Highest,
timeInterval: 5000,
distanceInterval: 0,
});
const hasStarted = await Location.hasStartedLocationUpdatesAsync(
LOCATION_TRACKING
);
setLocationStarted(hasStarted);
console.log('tracking started?', hasStarted);
};
React.useEffect(() => {
const config = async () => {
let resf = await Location.requestForegroundPermissionsAsync();
let resb = await Location.requestBackgroundPermissionsAsync();
if (resf.status != 'granted' && resb.status !== 'granted') {
console.log('Permission to access location was denied');
} else {
console.log('Permission to access location granted');
}
};
config();
}, []);
const startLocation = () => {
startLocationTracking();
}
const stopLocation = () => {
setLocationStarted(false);
TaskManager.isTaskRegisteredAsync(LOCATION_TRACKING)
.then((tracking) => {
if (tracking) {
Location.stopLocationUpdatesAsync(LOCATION_TRACKING);
}
})
}
return (
<View>
{locationStarted ?
<TouchableOpacity onPress={stopLocation}>
<Text style={styles.btnText}>Stop Tracking</Text>
</TouchableOpacity>
:
<TouchableOpacity onPress={startLocation}>
<Text style={styles.btnText}>Start Tracking</Text>
</TouchableOpacity>
}
</View>
);
}
const styles = StyleSheet.create({
btnText: {
fontSize: 20,
backgroundColor: 'green',
color: 'white',
paddingHorizontal: 30,
paddingVertical: 10,
borderRadius: 5,
marginTop: 10,
},
});
TaskManager.defineTask(LOCATION_TRACKING, async ({ data, error }) => {
if (error) {
console.log('LOCATION_TRACKING task ERROR:', error);
return;
}
if (data) {
const { locations } = data;
let lat = locations[0].coords.latitude;
let long = locations[0].coords.longitude;
l1 = lat;
l2 = long;
console.log(
`${new Date(Date.now()).toLocaleString()}: ${lat},${long}`
);
}
});
full verion of app.js:
{
"expo": {
"name": "FinalHopefully",
"slug": "FinalHopefully",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true,
"infoPlist": {
"UIBackgroundModes": ["location"],
"NSLocationWhenInUseUsageDescription": "To allow the user to start recording a run...",
"NSLocationAlwaysUsageDescription": "To allow the distance to be measured even when the phone is turned off"
"NSLocationAlwaysAndWhenInUseUsageDescription": "Allow $(PRODUCT_NAME) to use your location to track your runs"
}
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
Upvotes: 1
Views: 1057
Reputation: 709
If you're using expo-dev-client and EAS you have to rebuild your app after making these changes, and if you're are building locally you need to run npx expo prebuild --clean -p ios
to regenerate your iOS files and update your Info.plist
Upvotes: 0