HarmonyOS7 传感器开发:加速度计做个摇一摇,原来这么简单

📅 2026/7/23 22:53:56 👁️ 阅读次数 📝 编程学习
HarmonyOS7 传感器开发:加速度计做个摇一摇,原来这么简单

文章目录

    • 前言
    • 传感器能做什么
    • 权限声明
    • 加速度计接入
    • 摇一摇实现
      • 完整代码
      • 算法讲解
    • 采样率与功耗
    • 其他传感器速览
    • 写在最后

前言

摇一摇,这个功能最早是微信搞出来的,结果成了移动端的经典交互。在 HarmonyOS7 上实现摇一摇,比我想象的简单多了——加速度计数据就三个值,判断逻辑十几行代码,回调里加个震动就完事。但传感器开发有不少细节:权限怎么申、采样率怎么选、功耗怎么控。这篇从加速度计接入到摇一摇完整实现,顺便把其他传感器也扫一遍。

传感器能做什么

HarmonyOS7 支持的传感器不少,常见的这些:

传感器数据能干啥
加速度计x/y/z 三轴加速度摇一摇、计步、屏幕旋转
陀螺仪x/y/z 三轴角速度姿态检测、VR 头控
磁力计x/y/z 三轴磁场指南针、金属检测
接近光距离值通话时熄屏
环境光光照强度自动亮度
气压计大气压值海拔估算、天气
计步器步数运动统计
心率BPM健康监测

每个传感器的接入方式都一样:on订阅 → 回调拿数据 →off取消订阅。套路统一,学会一个就会所有

权限声明

加速度计需要权限,module.json5里加上:

{"requestPermissions":[{"name":"ohos.permission.ACCELEROMETER"}]}

这个权限不需要动态申请,声明了就行。但心率传感器那类敏感数据需要ohos.permission.HEALTH_DATA,那个要动态授权。

加速度计接入

核心就三步:导入模块、订阅数据、取消订阅。

import{sensor}from'@kit.SensorServiceKit'import{BusinessError}from'@kit.BasicServicesKit'@StateaccelX:number=0@StateaccelY:number=0@StateaccelZ:number=0privatesubscribed:boolean=falsesubscribeAccelerometer(){try{sensor.on(sensor.SensorId.ACCELEROMETER,(data:sensor.AccelerometerResponse)=>{this.accelX=data.xthis.accelY=data.ythis.accelZ=data.z},{interval:200000000})// 采样间隔,单位纳秒this.subscribed=true}catch(error){lete=errorasBusinessErrorconsole.error(`订阅失败:${e.code},${e.message}`)}}unsubscribeAccelerometer(){try{sensor.off(sensor.SensorId.ACCELEROMETER)this.subscribed=false}catch(error){lete=errorasBusinessErrorconsole.error(`取消订阅失败:${e.code}`)}}

关键讲解:

  • sensor.SensorId.ACCELEROMETER:传感器类型标识,加速度计固定用这个
  • data.x / data.y / data.z:三轴加速度值,单位 m/s²。手机静止平放时,z 轴约等于 9.8(重力),x/y 接近 0
  • { interval: 200000000 }:采样间隔,单位是纳秒。200000000ns = 200ms,也就是每秒采样 5 次。这个值后面详细讲
  • onoff必须成对出现,页面销毁时一定记得 off,不然后台一直吃电

摇一摇实现

加速度计接好了,摇一摇的判断逻辑很直接——三轴加速度的绝对值之和超过阈值,就是"摇了"

完整代码

import{sensor}from'@kit.SensorServiceKit'import{vibration}from'@kit.VibrationEffectKit'import{BusinessError}from'@kit.BasicServicesKit'@Entry@Componentstruct ShakePage{@StateshakeCount:number=0@StateisShaking:boolean=falseprivatelastShakeTime:number=0privateSHAKE_THRESHOLD:number=18// 加速度阈值privateSHAKE_INTERVAL:number=500// 两次摇动最小间隔(ms)privateACCEL_INTERVAL:number=50000000// 50ms采样间隔aboutToAppear(){this.startShakeDetection()}aboutToDisappear(){this.stopShakeDetection()}startShakeDetection(){try{sensor.on(sensor.SensorId.ACCELEROMETER,(data:sensor.AccelerometerResponse)=>{constacceleration=Math.abs(data.x)+Math.abs(data.y)+Math.abs(data.z)constnow=Date.now()if(acceleration>this.SHAKE_THRESHOLD&&!this.isShaking){if(now-this.lastShakeTime>this.SHAKE_INTERVAL){this.isShaking=truethis.lastShakeTime=nowthis.onShakeDetected()// 300ms后重置状态,避免一次摇动多次触发setTimeout(()=>{this.isShaking=false},300)}}},{interval:this.ACCEL_INTERVAL})}catch(error){lete=errorasBusinessErrorconsole.error(`启动检测失败:${e.code}`)}}stopShakeDetection(){try{sensor.off(sensor.SensorId.ACCELEROMETER)}catch(error){// ignore}}onShakeDetected(){this.shakeCount++// 震动反馈try{vibration.vibrate(vibration.VibrateType.VIBRATOR_LIGHT)}catch(e){// 没有震动模块就算了}}build(){Column({space:20}){Text('摇一摇计数器').fontSize(28).fontWeight(FontWeight.Bold)Text(`${this.shakeCount}`).fontSize(72).fontColor('#FF6D00').fontWeight(FontWeight.Bold)Button('重置').onClick(()=>{this.shakeCount=0})Text('用力摇晃手机试试').fontSize(14).fontColor('#999999')}.width('100%').height('100%').justifyContent(FlexAlign.Center)}}

算法讲解

核心判断就这一行:

constacceleration=Math.abs(data.x)+Math.abs(data.y)+Math.abs(data.z)

三轴加速度取绝对值求和。静止时这个值约 9.8(纯重力),使劲摇的时候能到 25+。阈值设 18是个经验值——正常走路大概 12-15,不会误触;稍微用点力摇就能到 18。

两个防抖机制缺一不可:

  1. SHAKE_INTERVAL = 500ms:两次触发至少间隔 500ms,防止快速连续触发
  2. isShaking状态锁 +setTimeout(300ms):一次摇动只算一次,300ms 内不再响应

没有防抖的话,一次摇动会触发 5-10 次回调(因为采样间隔 50ms),计数器直接飞。

采样率与功耗

采样间隔怎么选?这事儿得权衡:

间隔采样率精度功耗适用场景
10000000ns (10ms)100Hz游戏、VR
50000000ns (50ms)20Hz摇一摇、手势识别
200000000ns (200ms)5Hz屏幕旋转、基础检测
1000000000ns (1s)1Hz很低很低后台监控

摇一摇用 50ms(20Hz)刚刚好——采样够密不会漏摇,功耗也不会炸。如果你做的是计步器那种长时间运行的,建议 200ms 甚至更低,不然电池扛不住。

真心建议:不用的时候一定 off。我见过一个 App 后台跑着传感器没关,4 小时掉电 20%。用户骂的你听不见。

其他传感器速览

加速度计学会了,其他传感器套路一模一样,换下SensorId就行:

  • 陀螺仪sensor.SensorId.GYROSCOPE,回调里data.x/y/z是角速度
  • 磁力计sensor.SensorId.MAGNETIC_FIELD,做指南针配合GeomagneticField算偏角
  • 接近光sensor.SensorId.PROXIMITY,通话时检测脸靠近就熄屏,data.distance
  • 环境光sensor.SensorId.AMBIENT_LIGHTdata.intensity是勒克斯值
  • 计步器sensor.SensorId.PEDOMETERdata.steps直接给你步数,不用自己算
  • 心率sensor.SensorId.HEART_RATE,需要额外权限,穿戴设备才支持

每种传感器的on/off用法完全一致,唯一区别是回调数据的字段名不同。官方文档里有每个传感器的 Response 类型定义,查一下就行。

写在最后

传感器开发真没那么难——on订阅、回调拿数据、off释放,三步走天下。摇一摇的实现核心就是加速度阈值判断 + 防抖,十几行代码搞定。但功耗控制和资源释放这些细节才是区分"能用"和"好用"的关键——不用就关、采样率别贪高、页面销毁一定 off

下次如果你做计步器、指南针或者体感游戏,回来翻这篇就行,套路都一样。Camera 那篇如果还没看,建议搭配着看,传感器 + 相机组合能做不少有趣的东西。