Saltar al contenido principal
Guías Capacitor Móvil

Guía de sensores del dispositivo en Capacitor: movimiento, brújula, pasos

Guía de sensores de dispositivo de Capacitor: lee el acelerómetro, barómetro, brújula, podómetro, sensores de luz y proximidad en iOS y Android, con permisos.

Sensores de smartphone como acelerómetro, brújula y barómetro usados en una app de Capacitor

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 minInterval y minHeadingChange en 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

  1. 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.
  2. Detén las actualizaciones cuando no esté visible. Usa @capacitor/appde appStateChange para 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.
  3. Limita la frecuencia en code nativo cuando el plugin lo permita (brújula minInterval, sensor de luz updateInterval), no en JavaScript.
  4. Solicita permiso en contexto. Solicita el acceso al movimiento cuando el usuario inicie un entrenamiento, no en el primer lanzamiento.
  5. 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.
  6. 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.

Live updates para apps Capacitor

Cuando un bug de la capa web está en producción, publica el fix a través de Capgo en lugar de esperar días a la aprobación de la app store. Los usuarios reciben la actualización en segundo plano mientras los cambios nativos siguen el flujo de revisión habitual.

Lo último de nuestro blog

Capgo te da la información clave que necesitas para crear una app móvil realmente profesional.