设备硬件能力调用:传感器、蓝牙与定位
本文将全面介绍如何在HarmonyOS 5.0+中调用设备硬件能力,包括传感器数据获取、蓝牙设备连接与通信、定位服务使用等核心技术。
1. 硬件能力调用概述
HarmonyOS提供了统一的硬件访问框架,允许开发者安全、高效地访问设备的各种硬件能力。这些能力通过标准化的API接口暴露给应用层,确保了跨设备的一致性体验。
1.1 硬件访问架构
HarmonyOS的硬件访问采用分层架构:
- 应用层:业务逻辑和用户界面
- 框架层:提供标准化硬件API
- 服务层:硬件能力管理和调度
- 驱动层:底层硬件驱动程序
1.2 权限管理要求
访问硬件能力需要声明相应权限:
// module.json5中的权限声明
{"module": {"requestPermissions": [{"name": "ohos.permission.ACCELEROMETER","reason": "$string:accel_permission_reason"},{"name": "ohos.permission.LOCATION","reason": "$string:location_permission_reason"},{"name": "ohos.permission.BLUETOOTH","reason": "$string:bluetooth_permission_reason"}]}
}
2. 传感器数据获取
传感器是获取设备物理状态信息的重要硬件,HarmonyOS提供了统一的传感器管理框架。
2.1 传感器类型支持
HarmonyOS支持多种传感器类型:
传感器类型 | 标识符 | 数据内容 | 典型应用场景 |
---|---|---|---|
加速度传感器 | SENSOR_TYPE_ACCELEROMETER | x,y,z轴加速度 | 运动检测、姿态识别 |
陀螺仪传感器 | SENSOR_TYPE_GYROSCOPE | 角速度数据 | 旋转检测、游戏控制 |
环境光传感器 | SENSOR_TYPE_LIGHT | 光照强度 | 屏幕亮度调节 |
距离传感器 | SENSOR_TYPE_PROXIMITY | 接近距离 | 通话时屏幕关闭 |
心率传感器 | SENSOR_TYPE_HEART_RATE | 心率数据 | 健康监测 |
2.2 传感器数据获取实现
import sensor from '@ohos.sensor';
import { BusinessError } from '@ohos.base';class SensorService {private sensorManager: sensor.SensorManager | null = null;private sensorEventListener: sensor.SensorEventListener | null = null;// 初始化传感器管理器async initializeSensorService(): Promise<void> {try {this.sensorManager = await sensor.getSensorManager();console.info('传感器服务初始化成功');} catch (error) {console.error(`传感器服务初始化失败: ${(error as BusinessError).message}`);}}// 开始监听加速度传感器async startAccelerometerMonitoring(): Promise<void> {if (!this.sensorManager) {console.error('传感器管理器未初始化');return;}try {const accelerometer = await this.sensorManager.getDefaultSensor(sensor.SensorType.SENSOR_TYPE_ACCELEROMETER);this.sensorEventListener = await this.sensorManager.registerListener(accelerometer,(sensorEvent: sensor.SensorEvent) => {this.handleAccelerometerData(sensorEvent);},{ interval: 100 } // 100ms采样间隔);console.info('加速度传感器监听已启动');} catch (error) {console.error(`启动加速度监控失败: ${(error as BusinessError).message}`);}}// 处理加速度数据private handleAccelerometerData(event: sensor.SensorEvent): void {const x = event.data[0]; // x轴加速度const y = event.data[1]; // y轴加速度const z = event.data[2]; // z轴加速度// 计算合加速度const magnitude = Math.sqrt(x * x + y * y + z * z);console.debug(`加速度数据 - X: ${x.toFixed(2)}, Y: ${y.toFixed(2)}, Z: ${z.toFixed(2)}, 合力: ${magnitude.toFixed(2)}`);// 运动检测逻辑if (magnitude > 15.0) {this.detectSignificantMovement();}}// 停止所有传感器监听async stopAllSensors(): Promise<void> {if (this.sensorEventListener && this.sensorManager) {try {await this.sensorManager.unregisterListener(this.sensorEventListener);console.info('传感器监听已停止');} catch (error) {console.error(`停止传感器监听失败: ${(error as BusinessError).message}`);}}}
}
2.3 环境传感器监测示例
// 环境传感器监测类
class EnvironmentalMonitor {private sensorManager: sensor.SensorManager | null = null;private lightEventListener: sensor.SensorEventListener | null = null;private temperatureEventListener: sensor.SensorEventListener | null = null;// 开始环境监测async startEnvironmentalMonitoring(): Promise<void> {try {this.sensorManager = await sensor.getSensorManager();// 光照强度监测const lightSensor = await this.sensorManager.getDefaultSensor(sensor.SensorType.SENSOR_TYPE_LIGHT);this.lightEventListener = await this.sensorManager.registerListener(lightSensor,(event: sensor.SensorEvent) => {const lux = event.data[0];this.adjustScreenBrightness(lux);},{ interval: 5000 } // 5秒采样一次);// 温度监测(如果设备支持)try {const tempSensor = await this.sensorManager.getDefaultSensor(sensor.SensorType.SENSOR_TYPE_AMBIENT_TEMPERATURE);this.temperatureEventListener = await this.sensorManager.registerListener(tempSensor,(event: sensor.SensorEvent) => {const temperature = event.data[0];console.info(`环境温度: ${temperature.toFixed(1)}°C`);},{ interval: 60000 } // 1分钟采样一次);} catch (error) {console.warn('设备不支持环境温度传感器');}} catch (error) {console.error(`环境监测启动失败: ${(error as BusinessError).message}`);}}// 根据光照调整屏幕亮度private adjustScreenBrightness(lux: number): void {let brightnessLevel: number;if (lux < 10) {brightnessLevel = 20; // 黑暗环境} else if (lux < 100) {brightnessLevel = 40; // 室内环境} else if (lux < 1000) {brightnessLevel = 70; // 明亮室内} else {brightnessLevel = 100; // 户外强光}console.info(`光照强度: ${lux}lux, 调整亮度至: ${brightnessLevel}%`);// 实际应用中会调用屏幕亮度调节API}
}
3. 蓝牙设备连接与通信
蓝牙技术是实现设备间短距离无线通信的重要方式,HarmonyOS提供了完整的蓝牙API支持。
3.1 蓝牙基础操作
import bluetooth from '@ohos.bluetooth';
import { BusinessError } from '@ohos.base';class BluetoothManager {private bluetoothAdapter: bluetooth.BluetoothAdapter | null = null;private discoveredDevices: bluetooth.BluetoothDevice[] = [];// 初始化蓝牙适配器async initializeBluetooth(): Promise<boolean> {try {this.bluetoothAdapter = bluetooth.getDefaultAdapter();// 检查蓝牙状态const isEnabled = await this.bluetoothAdapter.isEnabled();if (!isEnabled) {console.warn('蓝牙未开启,正在尝试开启...');await this.bluetoothAdapter.enable();await new Promise(resolve => setTimeout(resolve, 1000)); // 等待蓝牙启动}console.info('蓝牙适配器初始化成功');return true;} catch (error) {console.error(`蓝牙初始化失败: ${(error as BusinessError).message}`);return false;}}// 开始扫描设备async startDeviceDiscovery(): Promise<void> {if (!this.bluetoothAdapter) {console.error('蓝牙适配器未初始化');return;}try {// 注册设备发现回调this.bluetoothAdapter.on('deviceDiscover', (device: bluetooth.BluetoothDevice) => {this.handleDiscoveredDevice(device);});// 开始扫描await this.bluetoothAdapter.startDiscovery();console.info('蓝牙设备扫描已开始');// 10秒后停止扫描setTimeout(() => {this.stopDeviceDiscovery();}, 10000);} catch (error) {console.error(`设备扫描失败: ${(error as BusinessError).message}`);}}// 处理发现的设备private handleDiscoveredDevice(device: bluetooth.BluetoothDevice): void {// 过滤掉无效设备if (!device.deviceName || device.deviceName === '') {return;}// 检查是否已存在const existingIndex = this.discoveredDevices.findIndex(d => d.deviceId === device.deviceId);if (existingIndex === -1) {this.discoveredDevices.push(device);console.info(`发现设备: ${device.deviceName} (${device.deviceId})`);// 如果是目标设备,尝试连接if (device.deviceName.includes('MyDevice')) {this.connectToDevice(device);}}}// 停止扫描async stopDeviceDiscovery(): Promise<void> {if (!this.bluetoothAdapter) return;try {await this.bluetoothAdapter.stopDiscovery();console.info('蓝牙设备扫描已停止');} catch (error) {console.error(`停止扫描失败: ${(error as BusinessError).message}`);}}
}
3.2 蓝牙连接与数据传输
// 蓝牙连接管理器
class BluetoothConnectionManager {private connectedDevices: Map<string, bluetooth.BluetoothDevice> = new Map();private sockets: Map<string, bluetooth.BluetoothSocket> = new Map();// 连接到设备async connectToDevice(device: bluetooth.BluetoothDevice): Promise<boolean> {try {console.info(`正在连接设备: ${device.deviceName}`);// 创建Socket连接const socket = await device.createRfcommSocketToServiceRecord('00001101-0000-1000-8000-00805F9B34FB' // SPP通用UUID);await socket.connect();this.sockets.set(device.deviceId, socket);this.connectedDevices.set(device.deviceId, device);console.info(`设备连接成功: ${device.deviceName}`);// 开始监听数据this.startDataListening(socket, device.deviceId);return true;} catch (error) {console.error(`连接设备失败: ${(error as BusinessError).message}`);return false;}}// 监听数据接收private startDataListening(socket: bluetooth.BluetoothSocket, deviceId: string): void {socket.on('message', (data: Uint8Array) => {const message = new TextDecoder().decode(data);console.info(`从设备 ${deviceId} 收到数据: ${message}`);this.handleReceivedData(message, deviceId);});socket.on('close', () => {console.warn(`设备连接已关闭: ${deviceId}`);this.connectedDevices.delete(deviceId);this.sockets.delete(deviceId);});socket.on('error', (error: BusinessError) => {console.error(`Socket错误: ${error.message}`);this.connectedDevices.delete(deviceId);this.sockets.delete(deviceId);});}// 发送数据到设备async sendData(deviceId: string, message: string): Promise<boolean> {const socket = this.sockets.get(deviceId);if (!socket) {console.error('设备未连接');return false;}try {const encoder = new TextEncoder();const data = encoder.encode(message);await socket.send(data);console.info(`数据发送成功: ${message}`);return true;} catch (error) {console.error(`数据发送失败: ${(error as BusinessError).message}`);return false;}}// 断开连接async disconnectDevice(deviceId: string): Promise<void> {const socket = this.sockets.get(deviceId);if (socket) {try {await socket.close();this.connectedDevices.delete(deviceId);this.sockets.delete(deviceId);console.info('设备连接已断开');} catch (error) {console.error(`断开连接失败: ${(error as BusinessError).message}`);}}}
}
3.3 蓝牙低能耗(BLE)操作
import ble from '@ohos.bluetooth.ble';
import { BusinessError } from '@ohos.base';class BleManager {private gattServer: ble.GattServer | null = null;private connectedPeripherals: Set<string> = new Set();// 初始化BLEasync initializeBle(): Promise<void> {try {this.gattServer = await ble.getGattServer();console.info('BLE GattServer初始化成功');} catch (error) {console.error(`BLE初始化失败: ${(error as BusinessError).message}`);}}// 扫描BLE设备async scanBleDevices(): Promise<void> {try {const scanner = await ble.createScanner();scanner.on('deviceDiscover', (device: ble.BluetoothDevice) => {console.info(`发现BLE设备: ${device.name} - RSSI: ${device.rssi}`);// 连接感兴趣的设备if (device.name?.includes('HeartRate')) {this.connectBleDevice(device);}});await scanner.startScan();console.info('BLE设备扫描开始');// 扫描10秒setTimeout(async () => {await scanner.stopScan();console.info('BLE设备扫描停止');}, 10000);} catch (error) {console.error(`BLE扫描失败: ${(error as BusinessError).message}`);}}// 连接BLE设备async connectBleDevice(device: ble.BluetoothDevice): Promise<void> {try {const client = await ble.createGattClientDevice(device.deviceId);await client.connect();this.connectedPeripherals.add(device.deviceId);console.info(`BLE设备连接成功: ${device.name}`);// 发现服务const services = await client.discoverServices();for (const service of services) {console.info(`发现服务: ${service.uuid}`);this.subscribeToCharacteristics(client, service);}} catch (error) {console.error(`BLE连接失败: ${(error as BusinessError).message}`);}}// 订阅特征值通知private async subscribeToCharacteristics(client: ble.GattClientDevice, service: ble.GattService): Promise<void> {for (const characteristic of service.characteristics) {if (characteristic.properties.notify) {try {await client.subscribeToCharacteristic(characteristic);console.info(`已订阅特征值: ${characteristic.uuid}`);} catch (error) {console.error(`订阅特征值失败: ${(error as BusinessError).message}`);}}}}
}
4. 定位服务使用
定位服务是移动应用的核心功能之一,HarmonyOS提供了多种定位方式满足不同场景需求。
4.1 基础定位功能
import geolocation from '@ohos.geolocation';
import { BusinessError } from '@ohos.base';class LocationService {private locationManager: geolocation.LocationManager | null = null;private currentLocation: geolocation.Location | null = null;// 初始化定位服务async initializeLocationService(): Promise<void> {try {this.locationManager = geolocation.getLocationManager();// 检查定位权限const hasPermission = await this.checkLocationPermission();if (!hasPermission) {console.warn('缺少定位权限,请先申请权限');return;}console.info('定位服务初始化成功');} catch (error) {console.error(`定位服务初始化失败: ${(error as BusinessError).message}`);}}// 检查定位权限private async checkLocationPermission(): Promise<boolean> {try {const permissions: Array<string> = ['ohos.permission.LOCATION','ohos.permission.APPROXIMATELY_LOCATION'];const result = await accessControl.verifyAccessToken(permissions);return result === accessControl.GrantStatus.PERMISSION_GRANTED;} catch (error) {console.error(`权限检查失败: ${(error as BusinessError).message}`);return false;}}// 获取一次位置信息async getCurrentLocation(): Promise<geolocation.Location | null> {if (!this.locationManager) {console.error('定位管理器未初始化');return null;}try {const request: geolocation.CurrentLocationRequest = {priority: geolocation.LocationRequestPriority.FIRST_FIX,maxAccuracy: 50, // 50米精度timeout: 10000 // 10秒超时};this.currentLocation = await this.locationManager.getCurrentLocation(request);if (this.currentLocation) {console.info(`当前位置: 纬度=${this.currentLocation.latitude}, 经度=${this.currentLocation.longitude}`);console.info(`精度: ${this.currentLocation.accuracy}米`);return this.currentLocation;}return null;} catch (error) {console.error(`获取位置失败: ${(error as BusinessError).message}`);return null;}}
}
4.2 持续位置更新
// 持续位置监控类
class ContinuousLocationMonitor {private locationManager: geolocation.LocationManager | null = null;private locationCallback: geolocation.LocationCallback | null = null;private isMonitoring: boolean = false;// 开始持续位置更新async startContinuousLocationUpdates(): Promise<void> {if (!this.locationManager) {console.error('定位管理器未初始化');return;}try {const request: geolocation.LocationRequest = {priority: geolocation.LocationRequestPriority.FAST_FIRST_FIX,maxAccuracy: 100,timeInterval: 5000, // 5秒更新间隔distanceInterval: 10 // 10米距离间隔};this.locationCallback = (location: geolocation.Location) => {this.handleLocationUpdate(location);};await this.locationManager.requestLocationUpdates(request, this.locationCallback);this.isMonitoring = true;console.info('持续位置更新已启动');} catch (error) {console.error(`启动持续定位失败: ${(error as BusinessError).message}`);}}// 处理位置更新private handleLocationUpdate(location: geolocation.Location): void {console.info(`位置更新: 纬度=${location.latitude.toFixed(6)}, 经度=${location.longitude.toFixed(6)}`);console.info(`精度: ${location.accuracy}米, 速度: ${location.speed ?? 0}m/s`);// 根据业务需求处理位置数据this.checkGeofence(location);this.recordLocationHistory(location);}// 地理围栏检查private checkGeofence(location: geolocation.Location): void {// 预设的地理围栏坐标const targetLatitude = 39.9042;const targetLongitude = 116.4074;const fenceRadius = 1000; // 1公里半径const distance = this.calculateDistance(location.latitude,location.longitude,targetLatitude,targetLongitude);if (distance <= fenceRadius) {console.info('已进入目标地理围栏区域');this.onEnterGeofence();}}// 计算两点间距离(Haversine公式)private calculateDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {const R = 6371000; // 地球半径(米)const dLat = this.deg2rad(lat2 - lat1);const dLon = this.deg2rad(lon2 - lon1);const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +Math.cos(this.deg2rad(lat1)) * Math.cos(this.deg2rad(lat2)) *Math.sin(dLon / 2) * Math.sin(dLon / 2);const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));return R * c;}private deg2rad(deg: number): number {return deg * (Math.PI / 180);}// 停止位置更新async stopLocationUpdates(): Promise<void> {if (this.locationManager && this.locationCallback) {try {await this.locationManager.stopLocationUpdates(this.locationCallback);this.isMonitoring = false;console.info('持续位置更新已停止');} catch (error) {console.error(`停止定位失败: ${(error as BusinessError).message}`);}}}
}
4.3 定位策略与优化
为了平衡定位精度和功耗,需要根据具体场景选择合适的定位策略:
class LocationStrategyManager {private locationManager: geolocation.LocationManager | null = null;// 根据场景选择定位策略selectLocationStrategy(scenario: string): geolocation.LocationRequest {const baseRequest: geolocation.LocationRequest = {timeInterval: 5000,distanceInterval: 10};switch (scenario) {case 'navigation':// 导航场景:高精度、高频率return {...baseRequest,priority: geolocation.LocationRequestPriority.FAST_FIRST_FIX,maxAccuracy: 10,timeInterval: 1000,distanceInterval: 5};case 'fitness':// 运动健身:中等精度return {...baseRequest,priority: geolocation.LocationRequestPriority.BALANCED_POWER_ACCURACY,maxAccuracy: 50,timeInterval: 3000,distanceInterval: 10};case 'background':// 后台定位:低功耗return {...baseRequest,priority: geolocation.LocationRequestPriority.LOW_POWER,maxAccuracy: 100,timeInterval: 10000,distanceInterval: 50};default:return baseRequest;}}// 自适应定位调整async adaptiveLocationTracking(): Promise<void> {let batteryLevel = 100;let isCharging = false;// 监听电池状态(简化示例)setInterval(async () => {// 获取电池状态// const batteryInfo = await battery.getBatteryInfo();// batteryLevel = batteryInfo.batteryLevel;// isCharging = batteryInfo.isCharging;// 根据电池状态调整定位策略if (batteryLevel < 20 && !isCharging) {this.switchToPowerSavingMode();} else if (batteryLevel > 80 || isCharging) {this.switchToHighAccuracyMode();}}, 60000); // 每分钟检查一次}private switchToPowerSavingMode(): void {console.info('切换到省电定位模式');const request = this.selectLocationStrategy('background');this.applyLocationStrategy(request);}private switchToHighAccuracyMode(): void {console.info('切换到高精度定位模式');const request = this.selectLocationStrategy('navigation');this.applyLocationStrategy(request);}private applyLocationStrategy(request: geolocation.LocationRequest): void {// 实现定位策略应用逻辑}
}
5. 错误处理与性能优化
硬件调用过程中需要考虑错误处理和性能优化,确保应用的稳定性和用户体验。
5.1 统一的错误处理机制
class HardwareErrorHandler {// 处理硬件相关错误static handleHardwareError(error: BusinessError, context: string): void {console.error(`[${context}] 硬件错误: ${error.message}`);switch (error.code) {case 201: // 权限错误this.showUserMessage('请授予应用必要的硬件访问权限');break;case 202: // 硬件不可用this.showUserMessage('设备不支持此硬件功能');break;case 203: // 硬件繁忙this.showUserMessage('硬件资源正忙,请稍后重试');break;case 204: // 连接超时this.showUserMessage('连接超时,请检查设备状态');break;default:this.showUserMessage('硬件操作失败,请重试');}// 上报错误日志this.reportErrorToServer(context, error);}// 显示用户提示private static showUserMessage(message: string): void {// 实际应用中会调用UI提示组件console.warn(`用户提示: ${message}`);}// 错误上报private static reportErrorToServer(context: string, error: BusinessError): void {const errorReport = {timestamp: Date.now(),context: context,errorCode: error.code,errorMessage: error.message,deviceInfo: this.getDeviceInfo()};// 实际上报逻辑console.info('错误已上报服务器', errorReport);}private static getDeviceInfo(): any {return {// 获取设备信息model: deviceInfo.model,osVersion: deviceInfo.osVersion};}
}
5.2 性能监控与优化
class PerformanceMonitor {private static metrics: Map<string, number[]> = new Map();// 记录性能指标static recordMetric(metricName: string, value: number): void {if (!this.metrics.has(metricName)) {this.metrics.set(metricName, []);}this.metrics.get(metricName)!.push(value);// 定期分析性能数据if (this.metrics.get(metricName)!.length % 100 === 0) {this.analyzePerformance(metricName);}}// 分析性能数据private static analyzePerformance(metricName: string): void {const values = this.metrics.get(metricName) || [];const avg = values.reduce((a, b) => a + b, 0) / values.length;const max = Math.max(...values);const min = Math.min(...values);console.info(`性能指标 ${metricName}: 平均=${avg.toFixed(2)}ms, 最大=${max}ms, 最小=${min}ms`);// 性能告警if (avg > 100) {console.warn(`性能警告: ${metricName} 平均执行时间过长`);}}// 监控硬件操作性能static async monitorHardwareOperation<T>(operationName: string,operation: () => Promise<T>): Promise<T> {const startTime = Date.now();try {const result = await operation();const duration = Date.now() - startTime;this.recordMetric(operationName, duration);return result;} catch (error) {const duration = Date.now() - startTime;this.recordMetric(`${operationName}_error`, duration);throw error;}}
}// 使用示例
const location = await PerformanceMonitor.monitorHardwareOperation('get_current_location',() => locationService.getCurrentLocation()
);
6. 安全与隐私保护
硬件能力调用涉及用户隐私和数据安全,需要采取适当的安全措施。
6.1 隐私保护实践
class PrivacyProtectionManager {// 匿名化处理位置数据static anonymizeLocationData(location: geolocation.Location): any {return {// 降低精度保护隐私latitude: Math.round(location.latitude * 100) / 100,longitude: Math.round(location.longitude * 100) / 100,timestamp: location.time,// 移除精确标识信息accuracy: Math.round(location.accuracy / 100) * 100};}// 敏感数据加密存储static encryptSensitiveData(data: any, key: string): string {// 实际应用中会使用加密库const encrypted = btoa(JSON.stringify(data)); // 简单base64编码示例return encrypted;}// 检查隐私设置static checkPrivacySettings(): boolean {// 检查用户隐私设置,是否允许数据收集const privacySettings = {allowLocationCollection: true,allowSensorDataCollection: false,allowBluetoothScanning: true};return privacySettings.allowLocationCollection;}
}
6.2 权限动态申请
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import { BusinessError } from '@ohos.base';class PermissionManager {// 动态申请权限static async requestPermissions(permissions: string[]): Promise<boolean> {try {const atManager = abilityAccessCtrl.createAtManager();const grantStatus = await atManager.requestPermissionsFromUser(permissions,(result) => {console.info('权限申请结果:', result);});return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;} catch (error) {console.error(`权限申请失败: ${(error as BusinessError).message}`);return false;}}// 检查并申请硬件权限static async checkAndRequestHardwarePermissions(): Promise<boolean> {const requiredPermissions = ['ohos.permission.LOCATION','ohos.permission.BLUETOOTH','ohos.permission.APPROXIMATELY_LOCATION'];try {const hasPermissions = await this.requestPermissions(requiredPermissions);if (!hasPermissions) {console.warn('缺少必要的硬件访问权限');return false;}return true;} catch (error) {console.error(`权限检查失败: ${(error as BusinessError).message}`);return false;}}
}