传感器与硬件访问:你想读硬件?硬件同意了吗?

🏆本文收录于「滚雪球学SpringBoot」专栏(全网一个名),手把手带你零基础入门Spring Boot,从入门到就业,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8
摘要
这一章我可太有“硬件情结”了😆——传感器、定位、蓝牙、Wi-Fi这四兄弟,写好了像开挂🚀;写不好嘛……就会出现那种“我明明开了权限,为啥它还装死😵💫?”的名场面。来,咱把它讲得又稳又好玩,还能直接抄进项目里用✅
🧭目录(先把路牌立好🪧)
- 🏃♂️ 20.1 Sensor API:加速度 & 陀螺仪(动起来!)
- 📍 20.2 位置服务:单次定位 & 持续监听(省电才是王道)
- 🔵 20.3 蓝牙(BLE):扫描、过滤、事件回调(别扫成雷达站)
- 📶 20.4 Wi-Fi:状态、已连接信息、事件监听(别乱扫,容易挨骂)
- 🧯 20.5 常见翻车点(我替你踩过😭)
🏃♂️20.1 Sensor API(加速度、陀螺仪)——“手机在动”,你得听得懂🫨
✅你能用 Sensor API 干啥?
- 加速度 ACCELEROMETER:看设备在三轴上的加速度(含重力),做运动/甩一甩/游戏重力感应都靠它
- 陀螺仪 GYROSCOPE:看角速度(rad/s),做转向、体感、姿态判断特别香
官方的订阅接口很清晰:sensor.on / sensor.once / sensor.off,订阅和取消订阅要成对出现,不然就会一直上报、一直耗电(你手机:我谢谢你😅)
🔐权限怎么搞?
加速度/陀螺仪对应权限在文档里写得明明白白:
ohos.permission.ACCELEROMETERohos.permission.GYROSCOPE
而且它们属于 system_grant(系统授权型),通常不需要你弹窗请求,但必须在 module.json5 里声明
📌module.json5 权限声明示例(别偷懒哈😤)
{
"module": {
"requestPermissions": [
{ "name": "ohos.permission.ACCELEROMETER" },
{ "name": "ohos.permission.GYROSCOPE" }
]
}
}
声明权限的规范(reason/usedScene 等)官方有明确要求,尤其是 user_grant 类权限更严格
🧪实战:加速度 + 陀螺仪实时面板(带“低通滤波”,不抖成鬼畜👻)
我这个示例特别适合你复制进项目里:
进入页面开始监听 → 离开页面立刻取消监听,不当“电量刺客”🪫
import sensor from '@ohos.sensor'
@Entry
@Component
struct MotionDashboard {
@State ax: number = 0
@State ay: number = 0
@State az: number = 0
@State gx: number = 0
@State gy: number = 0
@State gz: number = 0
// 低通滤波系数:越小越稳,越大越灵敏(也越抖😅)
private alpha: number = 0.2
private accCb = (data: sensor.Response) => {
// data.x / data.y / data.z
this.ax = this.ax + this.alpha * (data.x - this.ax)
this.ay = this.ay + this.alpha * (data.y - this.ay)
this.az = this.az + this.alpha * (data.z - this.az)
}
private gyrCb = (data: sensor.Response) => {
this.gx = this.gx + this.alpha * (data.x - this.gx)
this.gy = this.gy + this.alpha * (data.y - this.gy)
this.gz = this.gz + this.alpha * (data.z - this.gz)
}
aboutToAppear() {
// 持续监听:sensor.on / 取消:sensor.off :contentReference[oaicite:3]{index=3}
sensor.on(sensor.SensorId.ACCELEROMETER, this.accCb)
sensor.on(sensor.SensorId.GYROSCOPE, this.gyrCb)
}
aboutToDisappear() {
sensor.off(sensor.SensorId.ACCELEROMETER, this.accCb)
sensor.off(sensor.SensorId.GYROSCOPE, this.gyrCb)
}
build() {
Column({ space: 12 }) {
Text('🧲 运动传感器面板').fontSize(22).fontWeight(FontWeight.Bold)
Column({ space: 6 }) {
Text('🏃♂️ 加速度 (m/s²)').fontSize(16).fontWeight(FontWeight.Medium)
Text(`x=${this.ax.toFixed(2)} y=${this.ay.toFixed(2)} z=${this.az.toFixed(2)}`)
}.padding(12).borderRadius(12).backgroundColor('#F6F6F6')
Column({ space: 6 }) {
Text('🌀 陀螺仪 (rad/s)').fontSize(16).fontWeight(FontWeight.Medium)
Text(`x=${this.gx.toFixed(2)} y=${this.gy.toFixed(2)} z=${this.gz.toFixed(2)}`)
}.padding(12).borderRadius(12).backgroundColor('#F6F6F6')
Text('😄 小提示:离开页面记得 off,不然你手机会“悄悄发热”给你看。')
.fontColor('#666')
}
.padding(16)
}
}
📍20.2 位置服务——“我在哪儿”可以问,但别一直问🙃
位置能力由 geoLocationManager 提供,官方把常用接口都列得很清楚:
isLocationEnabled():位置开关是否开了getLastLocation():取最近一次缓存位置(更省电)getCurrentLocation():取当前位置(更实时,功耗更大)on('locationChange', …)/off('locationChange', …):持续监听位置变化
我最喜欢的省电套路就是:
先拿 getLastLocation(有缓存就直接用),觉得不够新鲜再 getCurrentLocation。官方也建议优先用缓存位置以降低功耗
🔐权限:定位是 user_grant,别想“偷偷来”😅
声明权限要按规范写进 module.json5,文档强调:不声明可能拿不到授权,甚至上架会被拦
📌module.json5(定位权限示例:模糊 + 精确)
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.APPROXIMATELY_LOCATION",
"reason": "$string:approx_location_reason",
"usedScene": { "abilities": ["EntryAbility"], "when": "inuse" }
},
{
"name": "ohos.permission.LOCATION",
"reason": "$string:precise_location_reason",
"usedScene": { "abilities": ["EntryAbility"], "when": "inuse" }
}
]
}
}
声明规范(reason/usedScene 必填的场景、写法等)见官方指南
🧪实战:一次定位(先缓存后实时)+ 权限弹窗申请✅
权限申请用 abilityAccessCtrl.requestPermissionsFromUser(AtManager)是标准做法
import { geoLocationManager } from '@kit.LocationKit'
import abilityAccessCtrl from '@ohos.abilityAccessCtrl'
import { promptAction } from '@kit.ArkUI'
async function ensureLocationPermission(context: any): Promise<boolean> {
const atManager = abilityAccessCtrl.createAtManager()
const res = await atManager.requestPermissionsFromUser(context, [
'ohos.permission.APPROXIMATELY_LOCATION',
'ohos.permission.LOCATION'
]) // requestPermissionsFromUser :contentReference[oaicite:9]{index=9}
// res.authResults: 每个权限的授权结果(具体字段以实际返回为准)
return res.authResults?.every(r => r === 0) ?? false
}
async function getNiceLocation(context: any) {
// 位置开关判断 :contentReference[oaicite:10]{index=10}
const enabled = geoLocationManager.isLocationEnabled()
if (!enabled) {
promptAction.showToast({ message: '📍 位置开关没开呀…先去设置里开一下🥲' })
return
}
const ok = await ensureLocationPermission(context)
if (!ok) {
promptAction.showToast({ message: '🙃 你不给权限,我也没办法假装知道你在哪儿…' })
return
}
try {
// 省电优先:最近缓存位置 :contentReference[oaicite:11]{index=11}
const last = geoLocationManager.getLastLocation()
if (last) return last
} catch (e) {
// 没缓存很正常,别慌😄
}
// 实时定位:更耗电,但更“新鲜” :contentReference[oaicite:12]{index=12}
const current = await geoLocationManager.getCurrentLocation()
return current
}
🔵20.3 蓝牙(BLE)——扫描可以,但别扫成“电量收割机”🪫😅
BLE 这块我先送你一句“老江湖忠告”😎:
扫描必须加过滤条件。不然你会把附近所有设备都扫出来(而且功耗蹭蹭涨)。
官方 BLE 模块列得很全:
ble.startBLEScan / ble.stopBLEScanble.on('BLEDeviceFind') / ble.off('BLEDeviceFind')
还特别提醒:filters 传 null 会扫到一堆非预期设备、并增加功耗(这不是吓你,是官方原话意思😅)
🔐蓝牙权限小坑:别用过期权限名
官方 FAQ 讲得很直白:USE_BLUETOOTH 属于旧时代(API 7/8/9)用的权限,后来推荐用 ACCESS_BLUETOOTH 等(别抱着“旧钥匙开新门”啊🤣)
社区实践里也明确提到扫描前需获得如 ohos.permission.ACCESS_BLUETOOTH 等权限
🧪实战:BLE 扫描 + 过滤 + 事件回调(只扫我想要的😏)
import { ble } from '@kit.ConnectivityKit'
type Found = { name?: string, deviceId: string, rssi?: number }
export class BleScanner {
private results: Map<string, Found> = new Map()
private onFind = (arr: Array<ble.ScanResult>) => {
arr.forEach(item => {
const deviceId = item.deviceId
this.results.set(deviceId, {
deviceId,
name: item.deviceName,
rssi: item.rssi
})
})
console.info(`🔵 found=${this.results.size}`)
}
start() {
// 订阅扫描事件:BLEDeviceFind :contentReference[oaicite:16]{index=16}
ble.on('BLEDeviceFind', this.onFind)
// filters 不建议为 null:会增加功耗且扫到非预期设备 :contentReference[oaicite:17]{index=17}
const filters: Array<ble.ScanFilter> = [
// 示例:按服务 UUID 或设备名过滤(按你业务填)
{ serviceUuid: '0000180F-0000-1000-8000-00805F9B34FB' } // 电量服务举例
]
const options: ble.ScanOptions = {
// 具体字段看版本能力,示例表示“别太激进”
}
ble.startBLEScan(filters, options) // startBLEScan :contentReference[oaicite:18]{index=18}
}
stop() {
ble.stopBLEScan() // stopBLEScan :contentReference[oaicite:19]{index=19}
ble.off('BLEDeviceFind', this.onFind)
}
list(): Found[] {
return Array.from(this.results.values()).sort((a, b) => (b.rssi ?? -999) - (a.rssi ?? -999))
}
}
📶20.4 Wi-Fi 调用——能读就读,别“手欠”一直扫🤣
Wi-Fi 这块有个很现实的版本差异:
- 老模块
@ohos.wifi从 API 9 起不再维护,官方建议用@ohos.wifiManager等接口 wifiManager的能力列表里包含:isWifiActive、getLinkedInfo、各种事件监听等
✅场景一:判断 Wi-Fi 开关 + 获取当前连接信息
wifiManager.isWifiActive() 用于判断开关状态,需要权限 ohos.permission.GET_WIFI_INFO(这权限名你可别写错😅)
import { wifiManager } from '@kit.ConnectivityKit'
import { promptAction } from '@kit.ArkUI'
async function showWifiStatus() {
const active = wifiManager.isWifiActive() // :contentReference[oaicite:23]{index=23}
if (!active) {
promptAction.showToast({ message: '📶 Wi-Fi 还没开呢,先开开再聊~' })
return
}
const info = await wifiManager.getLinkedInfo() // getLinkedInfo :contentReference[oaicite:24]{index=24}
console.info(`ssid=${info.ssid}, bssid=${info.bssid}, rssi=${info.rssi}`)
}
✅场景二:监听 Wi-Fi 状态变化(别一直轮询,太“烦人”😅)
wifiManager.on/off 支持监听 wifiStateChange、wifiConnectionChange 等事件
import { wifiManager } from '@kit.ConnectivityKit'
const onState = (data: any) => {
console.info(`📶 wifiStateChange: ${JSON.stringify(data)}`)
}
function startListenWifi() {
wifiManager.on('wifiStateChange', onState) // :contentReference[oaicite:26]{index=26}
}
function stopListenWifi() {
wifiManager.off('wifiStateChange', onState) // :contentReference[oaicite:27]{index=27}
}
🧯20.5 常见翻车点(全是血泪😭,你别笑)
-
😵 传感器忘了 off
你以为只是监听,实际是在持续耗电 + 持续回调,后台一跑就“温热小火炉”🪫
→ 订阅/取消必须成对:on ↔ off -
📍 定位不先判断开关
官方明确有isLocationEnabled(),先看开关再干活,用户体验会好很多 -
🧠 定位一上来就 getCurrentLocation
省电第一步:先拿getLastLocation()缓存,不够新鲜再实时 -
🔵 BLE 扫描 filters 传 null
官方提醒:不建议这么干,功耗和误扫都会更糟 -
📶 Wi-Fi 还用旧 @ohos.wifi 不看弃用说明
API 9 起不维护了,别等线上出问题才想起升级😭
🧧福利赠与你🧧
无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」专栏(全网一个名),bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。
最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。
同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。
✨️ Who am I?
我是bug菌(全网一个名),CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云多年度十佳博主/价值贡献奖,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;更多精彩福利点击这里;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。

-End-
- 点赞
- 收藏
- 关注作者
评论(0)