Sensor APIs - 向 Web 平台公开一致性的设备传感器接口

Sensor API(传感器 API)是根据通用设计构建的一组接口,以一致的方式向 Web 平台公开设备传感器。

传感器 API 的概念和用法

尽管通用的传感器 API 规范定义了一个 Sensor 接口,但作为 Web 开发人员,您不会使用到它。相反,您将使用它的一个子类来检索特定类型的传感器数据。例如,Gyroscope 接口返回设备在读取时沿所有三个轴的加速度。

传感器可能与物理设备传感器完全对应,也可能不完全对应。例如,Gyroscope 接口与物理设备接口完全对应。AbsoluteOrientationSensor 接口则提供从两个或多个设备传感器通过算法聚合的信息。这些传感器类型分别称为低级高级。后一种类型的传感器也称为融合传感器(或者,虚拟或合成传感器)。

特征检测

传感器接口只是底层设备传感器的代理。因此,传感器的特征检测比其他 API 更复杂。传感器 API 的存在并不能告诉您该 API 是否连接到真正的硬件传感器、该传感器是否工作、它是否仍然连接,甚至用户是否已授予对它的访问权限。使所有这些信息一致可用会对性能和电池寿命造成很大影响。

因此,传感器 API 的功能检测必须包括对 API 本身的检测和防御性编程策略 (见下文)

下面的实例显示了三种检测传感器 API 的方法。此外,您还可以将对象实例化放在一个 try...catch 块中。请注意,不应该通过 Navigator 接口进行检测。

if (typeof Gyroscope === "function") {
    // ...
}

if ("ProximitySensor" in window) {
    // ...
}

if (window.AmbientLightSensor) {
    // ...
}

防御性编程

如特征检测中所述,检查特定传感器 API 不足以进行特征检测。 还必须确认实际传感器的存在。 这就是需要防御性编程的地方。 防御性编程需要三种策略。

  • 检查实例化传感器对象时引发的错误。
  • 侦听在使用过程中抛出的错误。
  • 优雅地处理错误,从而增强而不是降低用户体验。

下面的代码实例说明了这些原则。try...catch 块捕获传感器实例化期间引发的错误。它侦听 error 事件以捕获在使用过程中引发的错误。只有在需要请求权限以及设备不支持传感器类型时,才会向用户显示内容。

Note: 如果功能策略阻止使用该功能,则原因是您的代码与服务器上设置的策略不一致。该情况不会向用户显示出来。有关实现说明,请参阅 Feature-Policy

let accelerometer = null;
try {
    accelerometer = new Accelerometer({ referenceFrame: 'device' });
    accelerometer.addEventListener('error', event => {
        // 处理运行时错误。
        if (event.error.name === 'NotAllowedError') {
            // 处理用于请求权限的代码。
        } else if (event.error.name === 'NotReadableError' ) {
            console.log('无法连接到传感器。');
        }
    });
    accelerometer.addEventListener('reading', () => reloadOnShake(accelerometer));
    accelerometer.start();
} catch (error) {
    // 处理构造错误。
    if (error.name === 'SecurityError') {
        // 请参阅上面有关功能策略的说明。
        console.log('初始化传感器被功能策略阻止。');
    } else if (error.name === 'ReferenceError') {
        console.log('用户代理不支持传感器。');
    } else {
        throw error;
    }
}

权限和功能策略

除非用户向特定类型的传感器授予许可,否则不能获取传感器数据。请使用 Permissions API 进行操作。下面显示了一个简短的实例,该实例在尝试使用传感器之前请求许可。

navigator.permissions.query({ name: 'accelerometer' })
.then(result => {
  if (result.state === 'denied') {
    console.log('使用加速度传感器的许可被拒绝。');
    return;
  }
  // 使用传感器。
});

另一种方法是尝试使用传感器并侦听 SecurityError

const sensor = new AbsoluteOrientationSensor();
sensor.start();
sensor.addEventListener('error', error => {
  if (event.error.name === 'SecurityError')
    console.log("没有使用 AbsoluteOrientationSensor 的权限。);
});

下表描述了每种传感器类型、权限 API 所需的名称、<iframe> 元素的 allow 属性和 Feature-Policy 指令。

传感器 权限 / 功能策略名称
AbsoluteOrientationSensor 'accelerometer''gyroscope''magnetometer'
Accelerometer 'accelerometer'
AmbientLightSensor 'ambient-light-sensor'
GravitySensor 'accelerometer'
Gyroscope 'gyroscope'
LinearAccelerationSensor 'accelerometer'
Magnetometer 'magnetometer'
RelativeOrientationSensor 'accelerometer''gyroscope'

读数

传感器读数是通过所有传感器类型继承的 READING 事件回调来接收的。读取频率由您决定,通过将一个选项传递给传感器的构造函数来实现。该选项是一个指定每秒读数的数字。可以使用整数或小数,后者用于频率小于一秒的频率。实际读取频率取决于设备硬件,因此可能小于请求的读取频率。

下面的实例使用 Magneteter 传感器说明了这一点。

let magSensor = new Magnetometer({frequency: 60});

magSensor.addEventListener('reading', e => {
  console.log("沿 X 轴方向的磁场:" + magSensor.x);
  console.log("沿 Y 轴方向的磁场:" + magSensor.y);
  console.log("沿 Z 轴方向的磁场:" + magSensor.z);
})
magSensor.addEventListener('error', event => {
  console.log(event.error.name, event.error.message);
})
magSensor.start();

接口

AbsoluteOrientationSensor 安全上下文

描述设备相对于地球参考坐标系的物理方向。

Accelerometer 安全上下文

提供沿所有三个轴应用于设备的加速度。

AmbientLightSensor 安全上下文

返回宿主设备周围环境光的当前灯光级别或照度。

GravitySensor 安全上下文

提供沿所有三个轴应用于设备的重力。

Gyroscope 安全上下文

提供设备沿所有三个轴的角速度。

LinearAccelerationSensor 安全上下文

提供沿所有三个轴应用于设备的加速度,不包含重力的影响。

Magnetometer 安全上下文

提供有关由设备的主磁力计传感器检测到的磁场的信息。

OrientationSensor 安全上下文

AbsolteOrientationSensor 的基类。此接口不能直接使用,它提供了属性和方法用于继承。

RelativeOrientationSensor 安全上下文

描述设备的物理方向,不包含地球的参考坐标系。

Sensor 安全上下文

所有其他传感器接口的基类。此接口不能直接使用。相反,它提供用于继承它的接口访问的属性、事件处理程序和方法。

SensorErrorEvent 安全上下文

提供有关由 Sensor 或相关接口引发的错误的信息。

规范

规范
Generic Sensor API
Accelerometer
Ambient Light Sensor
Gyroscope
Magnetometer
Orientation Sensor

桌面浏览器兼容性

特性ChromeEdgeFirefoxInternet ExplorerOperaSafari
基础支持6779 不支持 不支持54 不支持
activated6779 不支持 不支持54 不支持
hasReading6779 不支持 不支持54 不支持
onactivate6779 不支持 不支持54 不支持
onerror6779 不支持 不支持54 不支持
onreading6779 不支持 不支持54 不支持
start6779 不支持 不支持54 不支持
stop6779 不支持 不支持54 不支持
timestamp6779 不支持 不支持54 不支持

移动浏览器兼容性

特性AndroidChrome for AndroidEdge mobileFirefox for AndroidIE mobileOpera AndroidiOS Safari
基础支持6767 未知 不支持 未知48 不支持
activated6767 未知 不支持 未知48 不支持
hasReading6767 未知 不支持 未知48 不支持
onactivate6767 未知 不支持 未知48 不支持
onerror6767 未知 不支持 未知48 不支持
onreading6767 未知 不支持 未知48 不支持
start6767 未知 不支持 未知48 不支持
stop6767 未知 不支持 未知48 不支持
timestamp6767 未知 不支持 未知48 不支持