Sensors
Six motion and environment sensors, bound to expo-sensors: Accelerometer, Gyroscope,
Magnetometer, DeviceMotion, Barometer and LightSensor.
import { Sensor } from '@ng-native/expo';
Every one of them is the same object underneath - addListener, setUpdateInterval,
isAvailableAsync - so this is one Sensor class parameterized by the reading, not one per
sensor. That is also why these are injection tokens rather than six @Service() classes: a
@Service() class cannot be generic in the thing it reports, so each sensor is a distinct
InjectionToken<Sensor<T>> that shares the one implementation.
Install
npx expo install expo-sensorsimport {
Accelerometer,
Gyroscope,
Magnetometer,
DeviceMotion,
Barometer,
LightSensor,
} from '@ng-native/expo/sensors';The smallest useful example
import { Component, DestroyRef, inject } from '@angular/core';
import { Accelerometer } from '@ng-native/expo/sensors';
@Component({
selector: 'app-shake-detector',
template: `<text>z: {{ motion.reading().z.toFixed(2) }}</text>`,
})
export class ShakeDetector {
protected readonly motion = inject(Accelerometer);
constructor() {
inject(DestroyRef).onDestroy(this.motion.start(50));
}
}Nothing is subscribed until start is called, and the interval is explicit rather than defaulted
away: the sensible interval is a property of what the app is doing with the reading - a compass
wants a tenth of a second, a shake detector less - and every event is a change-detection pass, so a
sensor left at its default is a phone that never idles.
What each one reports
Accelerometer-{ x, y, z }in g. Includes gravity, so a phone lying flat reads about1onz.Gyroscope-{ x, y, z }, rotation in radians per second.Magnetometer-{ x, y, z }, the magnetic field in microteslas. What a compass is built on.DeviceMotion- everything at once:acceleration,accelerationIncludingGravity,rotation,rotationRate,orientation,interval.Barometer-{ pressure, relativeAltitude }, pressure in hectopascals. Present on fewer devices than the rest; checkavailablebefore relying on it.LightSensor-{ illuminance }in lux. Android only.
Each is read the same way regardless of the shape:
reading- a signal, the most recent value, or the stated zero until the sensor has said anything.available-boolean | null. Null until the platform has answered, which is always one turn away even though the underlying question is really a constant -isAvailableAsyncis asynchronous regardless. A signal rather than the promise the module itself offers, because the question is normally asked in a template (@if (barometer.available())), and a promise there is truthy on the first frame and every frame after: exactly the failure this project keeps guarding against.start(intervalMs = 100)- starts the listener at that interval and returns the function that stops it. Calling it again restarts at the new interval.stop()- what the returned function calls. Callstop()or the returned cleanup function when you no longer need readings.
Without the module
On iOS and Android, a missing expo-sensors - never installed, or installed without the app
being rebuilt since - throws a MissingModuleError when a sensor first reaches for it. Its
message names the module and the commands that fix it; see
Using a module.
On the web, and in a test that provides no fake, available resolves to false. reading stays at the stated zero (all axes 0, or the
equivalent rest state for DeviceMotion). start() returns a function that does nothing.
Reference
Sensorclass@ng-native/expoimport { Sensor } from '@ng-native/expo';Methods
start(intervalMs = 100): () => void Start reading, at intervalMs between readings. Returns the function that stops.
stop(): voidStop reading for everyone who started it.