expo-location
Ubicación de primer plano/fondo, geofencing y cadenas de divulgación de App Store - el libro de recetas expo-location para aplicaciones de campo y entrega de Expo SDK 57.
Busca en todas las páginas de la documentación
Ubicación de primer plano/fondo, geofencing y cadenas de divulgación de App Store - el libro de recetas expo-location para aplicaciones de campo y entrega de Expo SDK 57.
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
npx expo install expo-location// app.config.ts - cadenas de divulgación (requeridas para revisión de tienda)
export default {
plugins: [
[
"expo-location",
{
locationWhenInUsePermission:
"FieldTrack muestra sitios de trabajo cercanos mientras usas la aplicación.",
locationAlwaysAndWhenInUsePermission:
"FieldTrack registra coordenadas de visita en el fondo para que los supervisores vean los tiempos de llegada.",
isIosBackgroundLocationEnabled: true,
isAndroidBackgroundLocationEnabled: true,
},
],
],
};import * as Location from "expo-location";
export async function requestForegroundLocation(): Promise<boolean> {
const { status } = await Location.requestForegroundPermissionsAsync();
return status === "granted";
}
export async function watchPosition(onUpdate: (loc: Location.LocationObject) => void) {
const granted = await requestForegroundLocation();
if (!granted) return null;
return await Location.watchPositionAsync(
{
accuracy: Location.Accuracy.Balanced,
distanceInterval: 25, // metros - reduce cambios vs timeInterval solo
timeInterval: 10_000,
},
onUpdate
);
}Cuándo recurrir a esto:
Cuándo evitar:
Pin de mapa de primer plano, puerta de permiso y flujo de actualización de fondo con copia de divulgación honesta.
npx expo install expo-location// src/location/LocationPermissionGate.tsx
import { useState } from "react";
import { Linking, Pressable, Text, View } from "react-native";
import * as Location from "expo-location";
type Props = {
onGranted: () => void;
needsBackground?: boolean;
};
export function LocationPermissionGate({ onGranted, needsBackground }: Props) {
const [denied, setDenied] = useState(false);
async function request() {
const fg = await Location.requestForegroundPermissionsAsync();
if (fg.status !== "granted") {
setDenied(true);
return;
}
if (needsBackground) {
const bg = await Location.requestBackgroundPermissionsAsync();
if (bg.status !== "granted") {
setDenied(true);
return;
}
}
onGranted();
}
return (
<View style={{ padding: 24, gap: 12 }}>
<Text style={{ fontWeight: "600" }}>Acceso de ubicación</Text>
<Text>
Adjuntamos GPS a fotos de inspección para que las disputas se resuelvan con prueba de presencia en el sitio.
{needsBackground
? " El acceso de fondo mantiene los registros de visita precisos cuando cambias de aplicación."
: ""}
</Text>
<Pressable onPress={request}>
<Text style={{ color: "#2563eb" }}>Continuar</Text>
</Pressable>
{denied && (
<Pressable onPress={() => Linking.openSettings()}>
<Text>Abrir configuración</Text>
</Pressable>
)}
</View>
);
}// src/location/useCurrentPosition.ts
import { useEffect, useState } from "react";
import * as Location from "expo-location";
export function useCurrentPosition(enabled: boolean) {
const [coords, setCoords] = useState<Location.LocationObjectCoords | null>(
null
);
useEffect(() => {
if (!enabled) return;
let subscription: Location.LocationSubscription | null = null;
(async () => {
subscription = await Location.watchPositionAsync(
{ accuracy: Location.Accuracy.Balanced, distanceInterval: 20 },
(loc) => setCoords(loc.coords)
);
})();
return () => subscription?.remove();
}, [enabled]);
return coords;
}// src/location/getOneShotPosition.ts
import * as Location from "expo-location";
export async function getOneShotPosition() {
const { status } = await Location.getForegroundPermissionsAsync();
if (status !== "granted") return null;
return Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.Balanced,
});
}Lo que esto demuestra:
app.config.needsBackground es verdadero.| Nivel | iOS | Android | Caso de uso |
|---|---|---|---|
| Primer plano | When In Use | Ubicación precisa | Mapas, etiquetado único |
| Fondo | Always | Fondo + primer plano | Registros de visita mientras la aplicación está en fondo |
| Precisión reducida | Aproximada (iOS 14+) | Grueso opcional | Solo características a nivel de ciudad |
Accuracy.Highest - Bloqueo de GPS, batería más pesada
Accuracy.Balanced - Valor predeterminado para aplicaciones de campo
Accuracy.Low - A nivel de ciudad, más baratodistanceInterval sobre timeInterval agresivo - menos activaciones de JS.stopLocationUpdatesAsync o elimina la suscripción de vigilancia cuando la pantalla se desmonta.// src/location/geofenceTask.ts - importación de alcance global al inicio
import * as Location from "expo-location";
import * as TaskManager from "expo-task-manager";
export const GEOFENCE_TASK = "site-geofence";
TaskManager.defineTask(GEOFENCE_TASK, ({ data, error }) => {
if (error) {
console.error(error);
return;
}
const { eventType, region } = data as Location.GeofencingEvent;
if (eventType === Location.GeofencingEventType.Enter) {
console.log("Entered", region.identifier);
}
});await Location.startGeofencingAsync(GEOFENCE_TASK, [
{
identifier: "warehouse-a",
latitude: 37.7749,
longitude: -122.4194,
radius: 200,
notifyOnEnter: true,
notifyOnExit: false,
},
]);| Clave | Plataforma | Ejemplo |
|---|---|---|
locationWhenInUsePermission | complemento de iOS | Por qué el acceso de primer plano ayuda |
locationAlwaysAndWhenInUsePermission | complemento de iOS | Por qué el acceso de fondo es necesario |
ACCESS_BACKGROUND_LOCATION | Android | Misma narrativa para revisores |
| API | Propósito |
|---|---|
requestForegroundPermissionsAsync | Permiso de cuándo se usa |
requestBackgroundPermissionsAsync | Siempre / fondo |
getCurrentPositionAsync | Coordenada única |
watchPositionAsync | Actualizaciones en streaming |
startGeofencingAsync | Entrada/salida de región |
reverseGeocodeAsync | Coordenadas - dirección (red) |
subscription.remove() en limpieza de useEffect.TaskManager.defineTask en alcance de módulo.| Alternativa | Cuándo usar | No uses cuando |
|---|---|---|
| Solo primer plano | Mapa y etiquetado único | Prueba de presencia en el sitio mientras la aplicación está en fondo |
| Entrada manual de dirección | Usuarios sensibles a la privacidad | Seguimiento de flota en tiempo real |
| Geofencing | Alertas de entrada/salida del sitio | Precisión de sub-metro en interiores |
| SDK de mapas de terceros | Navegación paso a paso | Pin simple "¿dónde estoy?" |
npx expo install expo-locationAñade el complemento de configuración expo-location con cadenas de divulgación, luego npx expo prebuild o compilación de EAS.
isIosBackgroundLocationEnabled en el complemento y la ubicación de UIBackgroundModes.Accuracy.Balanced - actualiza a Highest solo para requisitos de sub-10m.import { Linking } from "react-native";
await Linking.openSettings();reverseGeocodeAsync usa servicios de red. Almacena en caché la última etiqueta conocida localmente para mostrar sin conexión.Versiones de stack: Esta página fue escrita para React 19.2.3, React Native 0.86.0 y Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última actualización: 16 jul 2026