Capacitor 设备传感器可通过轻量、专注的插件使用: @capgo/capacitor-accelerometer 用于运动, @capgo/capacitor-barometer 用于气压, @capgo/capacitor-compass 用于航向, @capgo/capacitor-pedometer 用于计步,以及光照、距离和摇晃插件。每个插件都遵循相同的模式:检查是否可用、需要时请求权限、开始更新、监听,并在完成后停止。本指南介绍 Capacitor 8 code 中的每种传感器、重要的平台差异,以及避免应用出问题的电池规则。
传感器概览
| 传感器 | 插件 | iOS | Android | 权限 |
|---|---|---|---|---|
| 加速度计 | @capgo/capacitor-accelerometer |
是 | 是 | iOS NSMotionUsageDescription |
| 气压计 | @capgo/capacitor-barometer |
支持,包含相对高度 | 支持,仅限带传感器的设备提供气压数据 | iOS 运动传感器权限描述字符串 |
| 指南针 | @capgo/capacitor-compass |
是 | 支持,包含精度事件 | iOS 使用期间的位置权限 |
| 计步器 | @capgo/capacitor-pedometer |
步数、距离、楼层、步频、节奏 | 步骤 | iOS 运动传感器,Android ACTIVITY_RECOGNITION |
| 环境光传感器 | @capgo/capacitor-light-sensor |
暂无公开的 API | 是 | 无 |
| 距离感应 | @capgo/capacitor-proximity |
是 | 是 | 无 |
| 摇晃手势 | @capgo/capacitor-shake |
是 | 是 | 无 |
| 陀螺仪 / 方向 | Web 端 DeviceMotionEvent / DeviceOrientationEvent |
是 | 是 | iOS requestPermission() 在 WebView 中 |
只安装你用到的。每个插件都很小,权限说明越少,App Review 审核时的问题也越少。
bun add @capgo/capacitor-accelerometer @capgo/capacitor-compass @capgo/capacitor-pedometer
bunx cap sync
iOS 配置
将传感器所需的用途说明添加到 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>
用通俗的话说明对用户有什么好处。像“此应用需要运动权限”这种笼统描述,是 App Review 常见的拒审原因。
Android 配置
大多数传感器无需权限。Pedometer 插件会将其添加 ACTIVITY_RECOGNITION 到合并后的 manifest 中,并在 Android 10+ 上运行时请求它。
如果传感器是必需的,请声明该硬件特性,以便 Google Play 对不支持该特性的设备隐藏您的应用。如果是可选的,请使用 required="false" 进行声明,并在运行时检查可用性:
<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" />
加速度计:运动与倾斜
加速度计以 G 为单位报告 x、y、z 轴上的加速度。平放的手机读数约为 z = -1 或 1 具体取决于平台约定,因为读数包含重力。
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();
}
使用场景:游戏中的倾斜控制、“拿起唤醒” UI、跌倒或撞击检测、活动强度。原始数据噪声较大,因此使用前请通过低通滤波器进行平滑处理:
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;
}
不要在每次采样时都更新 DOM。请存储最新值,并在 requestAnimationFrame 循环中渲染它。
摇晃手势
对于“摇一摇报告 Bug”或“摇一摇撤销”功能,你无需手动调整阈值:
import { CapacitorShake } from '@capgo/capacitor-shake';
const handle = await CapacitorShake.addListener('shake', () => openFeedbackForm());
陀螺仪与设备方向
旋转功能不需要单独的 plugin。WebView 已经暴露了该接口:
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);
调用 requestPermission 必须由按钮点击触发,绝不能在页面加载时触发,否则 iOS 会拒绝该请求。
指南针:航向
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 即相对磁北的角度,范围为 0 到 360 度。注意事项:
- 手机壳、笔记本电脑和车载支架中的磁铁会干扰磁力计。当 Android 报告精度低时,显示校准提示(将手机按 8 字形移动)。
- Throttle with
minInterval以及minHeadingChange而不是在 JavaScript 里处理。这样能减少 bridge 流量。 - 若要实现随用户旋转的地图,请将航向与地理位置结合使用。如果需要在应用后台获取位置,请参阅 后台地理定位插件.
计步器:步数、距离和楼层数
步数计数器是一颗低功耗芯片,即使应用未运行也会持续计数。
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();
平台差异:
- iOS (Core Motion) 可查询过去约七天的历史数据,并在支持的设备上提供距离、楼层数、配速和步频。
- Android 仅报告步数。硬件计数器会在重启时重置,因此不要把它当作累计总数。请自行保存基准值。
如需长期历史记录、跨设备每日总计或手表数据,请改用健康存储读取: @capgo/capacitor-health 它会汇总 Apple Health 和 Health Connect 中所有来源的步数。我们的 Health Connect 迁移指南 介绍了设置方法。
气压计:气压与海拔
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 在两个平台上均以百帕为单位。 relativeAltitude 是自更新开始以来的变化量,单位为米,仅由 iOS 提供。在 Android 上始终为 0,因此请使用气压公式自行计算:
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;
}
由气压得出的绝对海拔会有几十米误差,因为天气会改变海平面气压。几分钟内的相对变化精度约为 1 米,足以统计楼层或爬升。许多入门级 Android 手机没有气压计,因此请务必检查 isAvailable.
环境光传感器(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 });
}
典型值:低于 10 lux 是昏暗房间,几百 lux 是办公室,数万 lux 是直射阳光。可用于让阅读模式适应房间环境,或在户外提高对比度。若要调整屏幕亮度本身,请配合 @capgo/capacitor-brightness.
距离传感器
距离传感器可检测屏幕顶部是否被遮挡,通常是通话时用户的耳朵。
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();
在 iOS 上,这会切换 UIDevice.isProximityMonitoringEnabled,它会在被遮挡时关闭显示屏。在 Android 上,该插件会监听距离传感器并调暗应用窗口。请仅在语音通话、语音消息或对讲机模式激活时启用,以免用户脸颊误触按钮。
传感器应用的实用规则
- 先检查可用性。 平板电脑通常缺少计步器或气压计,而模拟器会伪造大多数传感器。请隐藏无法支持的功能。
- 不可见时停止更新。 使用
@capacitor/app的appStateChange在应用进入后台时停止监听,并在恢复时重新启动。持续运行的传感器会耗电,还会导致一星差评。 - 如果插件允许,请在原生 code 中进行节流 (指南针
minInterval, 光线传感器updateInterval), 而不是在 JavaScript 中。 - 在合适的时机请求权限。 在用户开始锻炼时请求运动权限,而不是在首次启动时请求。
- 在真机上进行测试。 模拟器返回的是恒定值或合成值。至少在一台低端 Android 手机上测试,这类设备的传感器可能缺失或噪声较大。
- 遵守隐私规则。 在 App Store 隐私标签和 Play 数据安全表单中,运动和位置数据都算敏感数据。请声明你收集了哪些数据。
故障排除
iOS 上无事件:缺少使用说明字符串,位于 Info.plist,或权限被拒绝。请检查“设置”>“隐私与安全性”>“运动与健身”。
Android 上计步器返回 0: ACTIVITY_RECOGNITION 已被拒绝,或设备没有计步器。请检查 isAvailable().stepCounting.
指南针读数跳动:磁干扰或未校准。在 Android 上注意精度,并显示校准提示。
relativeAltitude 始终为 0:Android 上的预期值。请按上述方式通过压力值进行计算。
DeviceMotionEvent.requestPermission 抛出:未通过用户手势调用。
耗电量报告:监听器会在后台持续运行。请在...时停止它们 appStateChange.
快速上线传感器功能
Thresholds, smoothing factors and UI for sensor features usually need several rounds of tuning with real users. That logic lives in JavaScript, so you can adjust it with Capgo 实时更新 无需经过应用商店审核,而新的插件和权限字符串则通过常规 build 进行。如果你正在连接胸带等外部传感器,请继续阅读我们的指南以实现 使用 Capacitor 构建心率监测仪.