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- 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. - 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, oreas build). - 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 withLinking.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:
reverseGeocoderesolvesnullthere. - 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-modulesIn a finalized tree setup is a stub, so you undo it by hand. Here is everything this module added:
- Delete the files that are still there:
src/lib/__tests__/location.test.ts. - Replace, don't delete
src/lib/location.ts: core code imports it, so swap in the no-op version frommodules/location/none/files/of a fresh clone of your tier repo - same exports, nothing behind them. - Uninstall the dependencies:
bun remove expo-location. - Drop the config plugin
expo-locationfrom.readynative.json→modules.app.expo.plugins(that is whereapp.config.tsreads it from), then rebuild the dev build. - Update the privacy declarations: remove this module's entries from
.readynative.json→modules.app.expo.ios.privacyManifests, then re-runbun run gen:privacyand revise your store privacy answers. - Check it:
bun run typecheckandbun run lintpoint at anything that still imports the removed files;bun run gen:graphrefreshesdocs/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-locationModule id: location/expo-location (the default for this category).
Dependencies
| Package | Version | Kind |
|---|---|---|
expo-location | ~57.0.20 | dependency (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):
| Type | Linked to user | Tracking | Purposes |
|---|---|---|---|
CoarseLocation | no | no | AppFunctionality |
After setup
- Rewrite the location purpose string for your app: app.config patch →
expo-locationplugin →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.tssrc/lib/location.ts