expo location permissions work on android, but not on iOS

I have a react-native app that uses expo. The location permissions work on android, but not on iOS. On a real iPhone (iOS version 14.4.2), it does nothing. On a simulator, I get this error message:

[Unhandled promise rejection: Error: LOCATION_FOREGROUND permission is required to do this operation.] at node_modules/react-native/Libraries/BatchedBridge/NativeModules.js:103:50 in promiseMethodWrapper…

The app only needs the location in the foreground. I added the “always” descriptions only because previously there was a bug that required them.

I haven’t checked the camera and camera roll permissions on iOS. They may not be working in my app either.

Here is what I’m using:

app.json:

{
“expo”: {
“name”: “Andiamo”,
“slug”: “andiamo_places”,
“version”: “1.0.0”,
“orientation”: “default”,
“icon”: “./assets/icon.png”,
“splash”: {
“image”: “./assets/splash.png”,
“resizeMode”: “contain”,
“backgroundColor”: “#ffffff
},
“updates”: {
“fallbackToCacheTimeout”: 0
},
“assetBundlePatterns”: [
“**/*”
],
“ios”: {
“bundleIdentifier”: “com.andiamoplaces.andiamotravelapp”,
“supportsTablet”: true,
“infoPlist”: {
“NSLocationUsageDescription”:
“The app needs permission to access your location, if you want to be located on the map.”,
“NSLocationWhenInUseUsageDescription”: “The app needs permission to access your location, if you want to be located on the map”,
“NSLocationAlwaysUsageDescription”: “The app needs permission to access your location, if you want to be located on the map”,
“NSLocationAlwaysAndWhenInUseUsageDescription”: “The app needs permission to access your location, if you want to be located on the map”,
“NSPhotoLibraryUsageDescription”: “The app needs permission to your camera roll, if you want to upload pictures.”,
“NSCameraUsageDescription”: “The app needs permission to your camera, if you want to take pictures from the app.”
}
},
“android”: {
“package”: “com.andiamoplaces.andiamotravelapp”,
“adaptiveIcon”: {
“foregroundImage”: “./assets/adaptive-icon.png”,
“backgroundColor”: “#FFFFFF
},
“permissions”: [
“CAMERA”,
“LOCATION”
]
},
“web”: {
“favicon”: “./assets/favicon.png”
},
“description”: “”
}
}

package.json:

{
“main”: “node_modules/expo/AppEntry.js”,
“scripts”: {
“start”: “expo start”,
“android”: “expo start --android”,
“ios”: “expo start --ios”,
“web”: “expo start --web”,
“eject”: “expo eject”,
“postinstall”: “jetifier -r”
},
“dependencies”: {
“cross-fetch”: “^3.1.4”,
“expo”: “^41.0.0”,
“expo-camera”: “~11.0.2”,
“expo-cli”: “^4.4.4”,
“expo-clipboard”: “~1.0.2”,
“expo-facebook”: “~11.0.5”,
“expo-font”: “~9.1.0”,
“expo-image-manipulator”: “~9.1.0”,
“expo-image-picker”: “~10.1.4”,
“expo-location”: “~12.0.4”,
“expo-media-library”: “~12.0.2”,
“expo-permissions”: “~12.0.1”,
“expo-status-bar”: “~1.0.4”,
“firebase”: “8.2.3”,
“geolib”: “^3.3.1”,
“global”: “^4.4.0”,
“luxon”: “^1.26.0”,
“native-base”: “^2.15.2”,
“react”: “16.13.1”,
“react-devtools”: “^4.13.2”,
“react-dom”: “16.13.1”,
“react-native”: “https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz”,
“react-native-color-picker”: “^0.6.0”,
“react-native-draggable-flatlist”: “^2.6.1”,
“react-native-gesture-handler”: “~1.10.2”,
“react-native-ionicons”: “^4.6.5”,
“react-native-maps”: “0.27.1”,
“react-native-material-menu”: “^1.2.0”,
“react-native-modal”: “^11.10.0”,
“react-native-pell-rich-editor”: “^1.7.0”,
“react-native-popup-menu”: “^0.15.10”,
“react-native-prompt-crossplatform”: “^1.6.1”,
“react-native-ratings”: “^8.0.4”,
“react-native-reanimated”: “~2.1.0”,
“react-native-safe-area-context”: “3.2.0”,
“react-native-safe-area-view”: “^1.1.1”,
“react-native-screens”: “~3.0.0”,
“react-native-simple-radio-button”: “^2.7.4”,
“react-native-switch”: “^2.0.0”,
“react-native-switch-selector”: “^2.1.4”,
“react-native-vector-icons”: “^8.1.0”,
“react-native-web”: “~0.13.12”,
“react-native-webview”: “11.2.3”,
“react-native-youtube-iframe”: “^2.0.1”,
“react-navigation”: “^4.4.4”,
“react-navigation-drawer”: “^2.7.1”,
“react-navigation-stack”: “^2.10.4”,
“react-navigation-tabs”: “^2.11.1”,
“react-redux”: “^7.2.4”,
“redux”: “^4.1.0”,
“redux-persist”: “^6.0.0”,
“redux-thunk”: “^2.3.0”
},
“devDependencies”: {
@babel/core”: “~7.9.0”,
“jetifier”: “^1.6.8”
},
“private”: true
}

Code:

startUserLocationUpdates = async () => {
const returns = await Location.watchPositionAsync(
{
accuracy: Location.Accuracy.BestForNavigation,
timeInterval: 1000,
// distanceInterval: 0,
},
(loc) => {
if (this.props.ShowLocation) this.centerMapTo(loc.coords.latitude, loc.coords.longitude);
this.props.onSetCurrentLocation({ latitude: loc.coords.latitude, longitude: loc.coords.longitude });
}
);
this._removeLocationUpdates = returns.remove;
};

Update: I tried it on another Android device and it did not work, so maybe it works on my main Android phone because the permissions were already granted when running a previous version? There is a bug report about permissions breaking between Expo version 40 and 41 [expo-location][sdk41] startLocationUpdatesAsync got broken in permissions refactoring · Issue #12581 · expo/expo · GitHub

I think that I figured it out. The reason that it was working on android is because I had previously used the correct permissions code and run it on my android device. I then commented out that code because it didn’t seem to matter, not realizing that the permission is only asked once. So I had to reinstall the expo client to verify that it also did not work on android. I used this code:

const { status } = await Permissions.askAsync(Permissions.LOCATION_FOREGROUND);
if (status === “granted”) {…}

which works, but gives warning messages that the code is now deprecated, so I changed it to:

let { status } = await Location.requestForegroundPermissionsAsync();

For camera and camera roll I had to do something similar.

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.