Volodymyr
Volodymyr

Reputation: 63

Error: One of the `NSLocation*UsageDescription` keys must be present in Info.plist to be able to use geolocation

When I want to test my app with Expo Go on iOS I get this error:

[Unhandled promise rejection: Error: One of the `NSLocation*UsageDescription` keys must be present in Info.plist to be able to use geolocation.]

Stack trace:
  node_modules\react-native\Libraries\BatchedBridge\NativeModules.js:104:50 in promiseMethodWrapper
  node_modules\expo-modules-core\build\NativeModulesProxy.native.js:15:23 in moduleName.methodInfo.name

I added that configuration to info.plist, rebuilt the project, but I get the same error, I also reinstalled node packages, but it didn't change anything.

package.json

    "dependencies": {
        "@expo/vector-icons": "^12.0.0",
        "expo": "~43.0.2",
        "expo-location": "~13.0.4",
        "expo-status-bar": "~1.1.0",
        "expo-task-manager": "~10.0.3",
        "react": "17.0.1",
        "react-dom": "17.0.1",
        "react-native": "0.64.3",
        "react-native-paper": "4.9.2",
        "react-native-web": "0.17.1",
        "expo-splash-screen": "~0.13.5",
        "expo-updates": "~0.10.13",
        "react-native-gesture-handler": "~1.10.2",
        "react-native-reanimated": "~2.2.0",
        "react-native-safe-area-context": "3.3.2",
        "react-native-screens": "~3.8.0"
      },
      "devDependencies": {
        "@babel/core": "^7.12.9"
      }

My js code

  const { status } = await Location.requestForegroundPermissionsAsync();
    if (status === "granted") {
      const background = await Location.requestBackgroundPermissionsAsync();
      if (background.status === "granted") {
        await Location.startLocationUpdatesAsync(TASK_FETCH_LOCATION, {
          activityType: Location.LocationActivityType.BestForNavigation,
          showsBackgroundLocationIndicator: true,
          accuracy: Location.Accuracy.BestForNavigation,
          deferredUpdatesInterval: 3000,
          deferredUpdatesDistance: 50,
          showsBackgroundLocationIndicator: true,
        }).then(() => {
          Alert.alert("Turn on", null, [
            { text: "OK", onPress: () => console.log("listening gps") },
          ]);
        });
      }
    }

app.json

   "ios": {
      "supportsTablet": true,
      "infoPlist": {
        "UIBackgroundModes": [
          "location",
          "fetch"
        ],
        "NSLocationAlwaysAndWhenInUseUsageDescription": "Allows App to use location services in the foreground and background.",
        "NSFaceIDUsageDescription": "Allows App to use Face ID for a simpler sign in."
      }
    }

Upvotes: 5

Views: 6799

Answers (4)

kroe
kroe

Reputation: 1126

For me what solved was:

  1. edit app.js
  2. delete ios folder
  3. npx expo run:ios --device

Upvotes: 0

Allex Radu
Allex Radu

Reputation: 1540

You need to first add this to your app.json:

{
  "expo": {
    "ios": {
      "infoPlist": {
        "UIBackgroundModes": [
          "location",
          "fetch",
          "remote-notification"
        ],
        "NSLocationWhenInUseUsageDescription": "This app requires access to your location when open.",
        "NSLocationAlwaysAndWhenInUseUsageDescription": "This app requires access to your location even when closed.",
        "NSLocationAlwaysUsageDescription":  "This app requires access to your location when open.",
        "deploymentTarget": "14"
      }
    },
    "plugins": [
      "expo-localization",
      "expo-background-fetch",
      [
        "expo-build-properties",
        {
          "android": {
            "compileSdkVersion": 33,
            "targetSdkVersion": 33,
            "buildToolsVersion": "33.0.0"
          },
          "ios": {
            "deploymentTarget": "14.0"
          }
        }
      ],
      [
        "expo-task-manager",
        {
          "ios": {
            "minimumOSVersion": "14"
          }
        }
      ],
      [
        "expo-background-fetch",
        {
          "ios": {
            "minimumOSVersion": "14"
          }
        }
      ],
      [
        "expo-location",
        {
          "locationAlwaysAndWhenInUsePermission": "Allow $(PRODUCT_NAME) to use your location.",
          "locationAlwaysPermission": "Allow $(PRODUCT_NAME) to use your location.",
          "locationWhenInUsePermission": "Allow $(PRODUCT_NAME) to use your location.",
          "isIosBackgroundLocationEnabled": true,
          "isAndroidBackgroundLocationEnabled": true
        }
      ]
    ]
  }
}

Then you need to run this:

npx expo prebuild --clean
npx expo run:ios

After you do a build, you need the open the app with Xcode, using this command:

open -a Xcode ios

Where "ios" is the folder where the app was built.

Then you need to sign in with your apple development account and add a certificate to the app.

After you add the certificate make sure to disable push notifications if you have a personal apple developer account by click on the trash icon on the right in the Xcode settings where you've added the certificate.

Then run the turn on development mode on your physical iphone, connect your iphone over USB and run this command:

npx expo run:ios --device

(select your iPhone that you connect over USB)

This is the only way to make background location work with expo on a physical iPhone.

Upvotes: 3

shivangg
shivangg

Reputation: 601

After expo-location, the docs said to do a rebuild. Just running npx expo run:ios wasn't enough, the native code had to be regenerated.

So,

  1. Had a clean working directory by committing the work
  2. Ran npx expo prebuild --clean
  3. Finally, npx expo run:ios

And then, the location code finally started working for this new build. Hope it helps.

Upvotes: 1

Tarik
Tarik

Reputation: 597

You need to explicitly set these key-string pair inside of the Info.plist of your project.

    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    <string>Your geolocation string</string>

Upvotes: -1

Related Questions