ReadyNative

Expo Location

Set up Expo Location for location in an Expo app with ReadyNative: foreground position + reverse geocoding, permission states handled · Expo Go OK

Expo Go: yes

Runs in Expo Go; no dev build needed for this module.

This gives you the device position through expo-location: src/lib/location.ts implements the shim, so location.getCurrentPosition() asks for foreground permission when it is still undetermined, returns a recent cached fix when there is one (up to 10 minutes old) and otherwise waits for a balanced-accuracy fix. location.reverseGeocode(coords) names the place ("Almaty") on iOS and Android. Every call resolves - null on denial, no fix or web geocoding - so screens never need a try. The weather demo's "My location" card uses it.

Setup

bun run setup --location expo-location
  1. Rewrite the purpose string. The module adds ["expo-location", { locationWhenInUsePermission: "…" }] to the app config; iOS shows that sentence in the permission dialog, and App Review rejects vague ones (guideline 5.1.1). Say what your app does with the position.
  2. Nothing else: there are no keys, and Expo Go already includes expo-location. A changed purpose string needs a new native build (npx expo run:ios, or eas build).
  3. Run bun run doctor - every row for this module should be green.

The module declares approximate location in the privacy manifest and the Play Data safety draft, because most apps send coordinates to a server (the weather demo sends them to Open-Meteo). If yours never leaves the device, you can drop that entry.

Usage

import { location } from "@/lib/location";

const coords = await location.getCurrentPosition(); // { latitude, longitude } | null
if (coords) {
  const city = await location.reverseGeocode(coords); // "Almaty" | null
}

Check or ask for permission yourself, for example to explain it on your own screen first:

const permission = await location.getPermission(); // "undetermined" | "denied" | "granted" | "unsupported"
if (permission === "undetermined") await location.requestPermission();

location.supported is true here and false with --location none: use it to hide a "use my location" button rather than showing one that does nothing.

Gotchas

  • iOS asks once. After a "Don't allow", requestPermission() resolves "denied" without a dialog - send people to Settings with Linking.openSettings().
  • Simulators have a location, but you choose it: iOS Simulator → Features → Location, Android emulator → Extended controls → Location.
  • Web gets coordinates from the browser (HTTPS only) but no place names: reverseGeocode resolves null there.
  • Background location is not wired. It needs isIosBackgroundLocationEnabled, the "Always" permission and a much harder App Review conversation - add it only when a feature needs it.

Remove it

While modules/ exists (a tree set up with --keep-modules), setup does all of it:

bun run setup --location none --yes --keep-modules

In a finalized tree setup is a stub, so you undo it by hand. Here is everything this module added:

  1. Delete the files that are still there: src/lib/__tests__/location.test.ts.
  2. Replace, don't delete src/lib/location.ts: core code imports it, so swap in the no-op version from modules/location/none/files/ of a fresh clone of your tier repo - same exports, nothing behind them.
  3. Uninstall the dependencies: bun remove expo-location.
  4. Drop the config plugin expo-location from .readynative.json → modules.app.expo.plugins (that is where app.config.ts reads it from), then rebuild the dev build.
  5. Update the privacy declarations: remove this module's entries from .readynative.json → modules.app.expo.ios.privacyManifests, then re-run bun run gen:privacy and revise your store privacy answers.
  6. Check it: bun run typecheck and bun run lint point at anything that still imports the removed files; bun run gen:graph refreshes docs/ARCHITECTURE.md.

Reference

Everything below is generated from modules/location/expo-location/module.json - the same file bun run setup reads, so it is what actually lands in your repo.

Install

bun run setup --location expo-location

Module id: location/expo-location (the default for this category).

Dependencies

PackageVersionKind
expo-location~57.0.20dependency (expo install)

Config plugins

Merged into app.config.ts through .readynative.json (modules.app):

  • expo-location (with options)

Privacy

Apple privacy manifest data types (composed into ios.privacyManifests by setup):

TypeLinked to userTrackingPurposes
CoarseLocationnonoAppFunctionality

After setup

  1. Rewrite the location purpose string for your app: app.config patch → expo-location plugin → locationWhenInUsePermission (modules/location/expo-location/module.json, or override it in app.config.ts). App Review rejects vague purpose strings (guideline 5.1.1). A new string needs a new native build.

Files

2 files copied to the project root
  • src/lib/__tests__/location.test.ts
  • src/lib/location.ts

On this page

Get ReadyNative