Los sensores de dispositivo de Capacitor están disponibles a través de plugins pequeños y enfocados: @capgo/capacitor-accelerometer para movimiento, @capgo/capacitor-barometer para presión atmosférica, @capgo/capacitor-compass para rumbo, @capgo/capacitor-pedometer para pasos, más plugins de luz, proximidad y sacudida. Cada uno sigue el mismo patrón: verificar disponibilidad, solicitar permiso si es necesario, iniciar actualizaciones, escuchar y detenerse cuando termines. Esta guía cubre cada sensor con Capacitor 8 code, las diferencias de plataforma que importan y las reglas de batería que mantienen a las apps fuera de problemas.
Resumen de sensores
| Sensor | Plugin | iOS | Android | Permiso |
|---|---|---|---|---|
| Acelerómetro | @capgo/capacitor-accelerometer |
Sí | Sí | iOS NSMotionUsageDescription |
| Barómetro | @capgo/capacitor-barometer |
Sí, con altitud relativa | Sí, solo presión, en dispositivos con sensor | Cadena de uso de movimiento en iOS |
| Brújula | @capgo/capacitor-compass |
Sí | Sí, con eventos de precisión | Ubicación de iOS en uso |
| Podómetro | @capgo/capacitor-pedometer |
Pasos, distancia, pisos, ritmo, cadencia | Pasos | Movimiento de iOS, Android ACTIVITY_RECOGNITION |
| Luz ambiental | @capgo/capacitor-light-sensor |
Sin API público | Sí | Ninguno |
| Proximidad | @capgo/capacitor-proximity |
Sí | Sí | Ninguno |
| Gesto de sacudida | @capgo/capacitor-shake |
Sí | Sí | Ninguno |
| Giroscopio / orientación | Web DeviceMotionEvent / DeviceOrientationEvent |
Sí | Sí | iOS requestPermission() en el WebView |
Instala solo lo que uses. Cada plugin es pequeño, y menos cadenas de permisos significan menos preguntas en App Review.
bun add @capgo/capacitor-accelerometer @capgo/capacitor-compass @capgo/capacitor-pedometer
bunx cap sync
Configurar iOS
Añade las cadenas de uso que necesitan tus sensores a ios/App/App/Info.plist:
<!-- Accelerometer, pedometer, barometer altitude -->
<key>NSMotionUsageDescription</key>
<string>Counts your steps and detects movement during workouts.</string>
<!-- Compass heading -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>Shows which direction you are facing on the map.</string>
Explica el beneficio para el usuario con palabras sencillas. Textos genéricos como «Esta app necesita acceso al movimiento» son un motivo frecuente de rechazo en App Review.
Configuración de Android
La mayoría de sensores no requieren permisos. El plugin de podómetro añade ACTIVITY_RECOGNITION al manifiesto fusionado, y lo solicitas en tiempo de ejecución en Android 10+.
Si un sensor es esencial, declara la característica de hardware para que Google Play oculte tu app en los dispositivos que no la tengan. Si es opcional, declárala con required="false" and check availability at runtime:
<uses-feature android:name="android.hardware.sensor.barometer" android:required="false" />
<uses-feature android:name="android.hardware.sensor.stepcounter" android:required="false" />
<uses-feature android:name="android.hardware.sensor.compass" android:required="false" />
Acelerómetro: movimiento e inclinación
El acelerómetro informa de la aceleración en los ejes x, y y z en G. Un teléfono en horizontal marca aproximadamente z = -1 o 1 según la convención de la plataforma, porque incluye la gravedad.
import { CapacitorAccelerometer } from '@capgo/capacitor-accelerometer';
const { isAvailable } = await CapacitorAccelerometer.isAvailable();
if (isAvailable) {
await CapacitorAccelerometer.requestPermissions();
const listener = await CapacitorAccelerometer.addListener('measurement', ({ x, y, z }) => {
const tiltX = Math.atan2(x, Math.sqrt(y * y + z * z)) * (180 / Math.PI);
ball.style.transform = `translateX(${tiltX * 3}px)`;
});
await CapacitorAccelerometer.startMeasurementUpdates();
// later
await CapacitorAccelerometer.stopMeasurementUpdates();
await listener.remove();
}
Casos de uso: controles de inclinación en juegos, interfaz de «levantar para despertar», detección de caídas o impactos, intensidad de actividad. Los datos crudos son ruidosos, así que suavízalos con un filtro paso bajo antes de usarlos:
const alpha = 0.2;
let smoothed = { x: 0, y: 0, z: 0 };
function lowPass(m: { x: number; y: number; z: number }) {
smoothed = {
x: smoothed.x + alpha * (m.x - smoothed.x),
y: smoothed.y + alpha * (m.y - smoothed.y),
z: smoothed.z + alpha * (m.z - smoothed.z),
};
return smoothed;
}
No actualices el DOM en cada muestra. Almacena el último valor y renderízalo en un requestAnimationFrame bucle.
Gestos de sacudida
Para «sacudir para reportar un error» o «sacudir para deshacer», no necesitas ajustar los umbrales tú mismo:
import { CapacitorShake } from '@capgo/capacitor-shake';
const handle = await CapacitorShake.addListener('shake', () => openFeedbackForm());
Giroscopio y orientación del dispositivo
No se necesita un plugin separado para la rotación. El WebView ya lo expone:
async function enableMotion() {
// iOS 13+ requires a user gesture and explicit permission
const DME = DeviceMotionEvent as unknown as { requestPermission?: () => Promise<'granted' | 'denied'> };
if (typeof DME.requestPermission === 'function') {
const result = await DME.requestPermission();
if (result !== 'granted') return;
}
window.addEventListener('devicemotion', (e) => {
const r = e.rotationRate; // alpha, beta, gamma in degrees per second
if (r) updateRotation(r.alpha ?? 0, r.beta ?? 0, r.gamma ?? 0);
});
window.addEventListener('deviceorientation', (e) => {
// alpha: 0-360 around z, beta: -180..180 front/back, gamma: -90..90 left/right
updateOrientation(e.alpha, e.beta, e.gamma);
});
}
document.querySelector('#enable-motion')!.addEventListener('click', enableMotion);
Llama a requestPermission desde una pulsación de botón, nunca al cargar la página, o iOS rechazará la solicitud.
Brújula: rumbo
import { CapgoCompass, CompassAccuracy } from '@capgo/capacitor-compass';
const status = await CapgoCompass.requestPermissions(); // iOS: location permission
if (status.compass === 'granted') {
await CapgoCompass.addListener('headingChange', ({ value }) => {
needle.style.transform = `rotate(${-value}deg)`;
});
await CapgoCompass.startListening({
minInterval: 100, // ms between events
minHeadingChange: 2, // degrees
});
// Android only: ask the user to calibrate when accuracy drops
await CapgoCompass.addListener('accuracyChange', ({ accuracy }) => {
calibrationHint.hidden = accuracy >= CompassAccuracy.MEDIUM;
});
await CapgoCompass.watchAccuracy();
}
// One-off reading
const { value } = await CapgoCompass.getCurrentHeading();
value es el ángulo respecto al norte magnético, de 0 a 360. Cosas a saber:
- El magnetómetro se ve afectado por los imanes de las fundas, los portátiles y los soportes de coche. Muestra un aviso de calibración (mueve el teléfono en forma de ocho) cuando Android indique baja precisión.
- Limita la frecuencia con
minIntervalyminHeadingChangeen lugar de hacerlo en JavaScript. Ahorra tráfico del bridge. - Para un mapa que gira con el usuario, combina el heading con la geolocalización. Si necesitas la ubicación con la app en segundo plano, consulta el plugin de geolocalización en segundo plano.
Podómetro: pasos, distancia y pisos
El contador de pasos es un chip de bajo consumo que cuenta continuamente, incluso cuando tu app no está en ejecución.
import { CapacitorPedometer } from '@capgo/capacitor-pedometer';
const features = await CapacitorPedometer.isAvailable();
// { stepCounting, distance, pace, cadence, floorCounting }
const perm = await CapacitorPedometer.requestPermissions();
if (perm.activityRecognition !== 'granted') {
// explain why and link to settings
}
// Steps today (start and end are required on iOS)
const startOfDay = new Date();
startOfDay.setHours(0, 0, 0, 0);
const today = await CapacitorPedometer.getMeasurement({
start: startOfDay.getTime(),
end: Date.now(),
});
console.log(today.numberOfSteps, today.distance, today.floorsAscended);
// Live updates during a walk
await CapacitorPedometer.addListener('measurement', (m) => {
stepsEl.textContent = String(m.numberOfSteps ?? 0);
});
await CapacitorPedometer.startMeasurementUpdates();
Diferencias entre plataformas:
- iOS (Core Motion) responde a consultas históricas de aproximadamente los últimos siete días y también proporciona distancia, pisos, ritmo y cadencia en dispositivos compatibles.
- Android solo reporta pasos. El contador de hardware se reinicia al reiniciar, así que no lo trates como un total de por vida. Almacena tu propia línea base.
Para el historial a largo plazo, totales diarios entre dispositivos o datos de un reloj, lee desde la tienda de salud con @capgo/capacitor-health en su lugar. Agrega pasos de todas las fuentes en Apple Health y Health Connect. Nuestro guía de migración a Health Connect explica la configuración.
Barómetro: presión y altitud
import { CapacitorBarometer } from '@capgo/capacitor-barometer';
const { isAvailable } = await CapacitorBarometer.isAvailable();
if (isAvailable) {
await CapacitorBarometer.requestPermissions();
await CapacitorBarometer.addListener('measurement', ({ pressure, relativeAltitude }) => {
pressureEl.textContent = `${pressure.toFixed(1)} hPa`;
altitudeEl.textContent = `${relativeAltitude.toFixed(1)} m`;
});
await CapacitorBarometer.startMeasurementUpdates();
}
pressure está en hectopascales en ambas plataformas. relativeAltitude es el cambio en metros desde que comenzaron las actualizaciones, proporcionado solo por iOS. En Android siempre es 0, así que calcúlalo tú mismo con la fórmula barométrica:
const P0 = 1013.25; // standard sea-level pressure in hPa
const altitudeMeters = (p: number) => 44330 * (1 - Math.pow(p / P0, 1 / 5.255));
let baseline: number | null = null;
function relativeAltitude(pressure: number) {
baseline ??= altitudeMeters(pressure);
return altitudeMeters(pressure) - baseline;
}
La altitud absoluta desde la presión tiene un error de decenas de metros porque el clima cambia la presión a nivel del mar. Los cambios relativos en minutos son precisos a unos metros, suficiente para contar pisos o ascensos. Muchos teléfonos Android económicos no tienen barómetro, así que verifica siempre isAvailable.
Sensor de luz ambiental (Android)
import { LightSensor } from '@capgo/capacitor-light-sensor';
const { available } = await LightSensor.isAvailable(); // always false on iOS
if (available) {
await LightSensor.addListener('lightSensorChange', ({ illuminance }) => {
document.body.classList.toggle('high-contrast', illuminance > 10_000); // bright sunlight
});
await LightSensor.start({ updateInterval: 500 });
}
Valores típicos: menos de 10 lux es una habitación oscura, unos cientos de lux es una oficina, decenas de miles es luz solar directa. Úsalo para un modo de lectura que se adapte a la habitación, o para aumentar el contraste al aire libre. Para cambiar el brillo de la pantalla en sí, combínalo con @capgo/capacitor-brightness.
Sensor de proximidad
El sensor de proximidad indica cuándo algo cubre la parte superior de la pantalla, normalmente la oreja del usuario durante una llamada.
import { CapacitorProximity } from '@capgo/capacitor-proximity';
const status = await CapacitorProximity.getStatus();
if (status.available) {
await CapacitorProximity.enable(); // screen turns off when covered
}
// when the call or voice message ends
await CapacitorProximity.disable();
En iOS, esto activa UIDevice.isProximityMonitoringEnabled, que apaga la pantalla mientras está cubierta. En Android, el plugin escucha el sensor de proximidad y atenúa la ventana de la app. Actívalo solo mientras esté activa una llamada de voz, un mensaje de voz o el modo walkie-talkie, para que la mejilla del usuario no pulse botones.
Reglas prácticas para apps de sensores
- Comprueba la disponibilidad primero. Las tablets a menudo no tienen podómetro ni barómetro, y los emuladores simulan la mayoría de los sensores. Oculta las funciones que no puedas ofrecer.
- Detén las actualizaciones cuando no esté visible. Usa
@capacitor/appdeappStateChangepara detener los listeners cuando la app pase a segundo plano y reiniciarlos al reanudar. Los sensores que siguen activos agotan la batería y provocan reseñas de una estrella. - Limita la frecuencia en code nativo cuando el plugin lo permita (brújula
minInterval, sensor de luzupdateInterval), no en JavaScript. - Solicita permiso en contexto. Solicita el acceso al movimiento cuando el usuario inicie un entrenamiento, no en el primer lanzamiento.
- Prueba en hardware real. Los simuladores devuelven valores constantes o sintéticos. Prueba al menos con un Android de gama baja, donde los sensores pueden faltar o ser ruidosos.
- Respeta las normas de privacidad. Los datos de movimiento y ubicación se consideran sensibles en las etiquetas de privacidad de la App Store y en el formulario de seguridad de datos de Play. Declara lo que recopilas.
Solución de problemas
Sin eventos en iOS: falta la cadena de uso en Info.plist, o se denegó el permiso. Revisa Ajustes, Privacidad y seguridad, Movimiento y forma física.
El podómetro devuelve 0 en Android: ACTIVITY_RECOGNITION se denegó, o el dispositivo no tiene contador de pasos. Revisa isAvailable().stepCounting.
El compás salta de un lado a otro: interferencia magnética o falta de calibración. Vigila la precisión en Android y muestra una sugerencia de calibración.
relativeAltitude siempre es 0: esperado en Android. Calcúlalo a partir de la presión como se muestra arriba.
DeviceMotionEvent.requestPermission lanza: no se llamó desde un gesto del usuario.
Los informes de consumo de batería: los listeners siguen ejecutándose en segundo plano. Deténlos en appStateChange.
Lanza funciones de sensores rápidamente
Los umbrales, los factores de suavizado y la interfaz de usuario para las funciones de sensores suelen requerir varias rondas de ajuste con usuarios reales. Esa lógica está en JavaScript, por lo que puedes ajustarla con actualizaciones Live Update de Capgo sin una revisión de la tienda, mientras que los nuevos plugins y las cadenas de permisos pasan por una compilación regular. Si estás conectando sensores externos como bandas torácicas, continúa con nuestra guía de crear un monitor de frecuencia cardíaca con Capacitor.