前两篇咱们分别搞定了通知服务(发送提醒)和地理位置服务(获取位置),这篇咱们先学习设备信息(deviceInfo)的核心用法,适配不同设备的硬件和系统特性,再将三大服务整合,完成 “位置提醒 APP” 的完整开发。让咱们从设备适配到功能闭环,一步步实现可直接复用的实战项目!
一、设备信息服务核心认知
1. 设备信息的应用价值
- 设备适配:根据屏幕尺寸调整 UI 布局、根据系统版本适配 API;
- 功能优化:根据设备型号调整定位策略(如高端机支持高精度 GNSS);
- 问题排查:记录设备信息用于日志分析,快速定位兼容性问题;
- 个性化服务:根据设备特性提供定制化功能(如平板端显示更多操作入口)。
2. 核心 API 与可获取信息
- 核心模块:
@ohos.deviceInfo(设备信息)、@ohos.screen(屏幕信息) - 关键信息:
- 设备基础信息:型号、厂商、设备 ID;
- 系统信息:系统版本、API 版本、设备类型;
- 屏幕信息:屏幕尺寸、分辨率、像素密度。
二、设备信息获取实战
1. 获取设备基础信息
import deviceInfo from '@ohos.deviceInfo'; /** * 获取设备基础信息 */ export function getDeviceBaseInfo(): { deviceModel: string; // 设备型号 manufacturer: string; // 设备厂商 osVersion: string; // 系统版本 apiVersion: number; // API版本 deviceType: string; // 设备类型(phone/tablet/watch等) } { return { deviceModel: deviceInfo.deviceModel, // 如:Mate 60 Pro manufacturer: deviceInfo.manufacturer, // 如:Huawei osVersion: deviceInfo.osVersion, // 如:4.0.0.188 apiVersion: deviceInfo.apiVersion, // 如:10 deviceType: deviceInfo.deviceType // 如:phone }; }2. 获取屏幕信息(适配 UI 布局)
import screen from '@ohos.screen'; /** * 获取屏幕信息 */ export function getScreenInfo(): { screenWidth: number; // 屏幕宽度(像素) screenHeight: number; // 屏幕高度(像素) density: number; // 像素密度 dpi: number; // 屏幕DPI } { const mainScreen = screen.getDefaultScreen(); const screenRect = mainScreen.getRect(); const density = mainScreen.getDensity(); const dpi = mainScreen.getDpi(); return { screenWidth: screenRect.width, screenHeight: screenRect.height, density: density, dpi: dpi }; }3. 设备适配实战(根据设备类型调整功能)
/** * 根据设备类型调整定位配置 * 手机:高精度模式,平板:平衡模式,手表:低功耗模式 */ export function getLocationConfigByDeviceType(): geoLocationManager.LocationRequest { const deviceInfo = getDeviceBaseInfo(); let priority: geoLocationManager.LocationRequestPriority; switch (deviceInfo.deviceType) { case 'phone': priority = geoLocationManager.LocationRequestPriority.HIGH_ACCURACY; break; case 'tablet': priority = geoLocationManager.LocationRequestPriority.BALANCED; break; case 'watch': priority = geoLocationManager.LocationRequestPriority.LOW_POWER; break; default: priority = geoLocationManager.LocationRequestPriority.BALANCED; } return { priority: priority, interval: deviceInfo.deviceType === 'watch' ? 10000 : 5000, // 手表定位间隔 longer distance: 10, scenario: geoLocationManager.LocationScenario.NAVIGATION }; }三、整合三大服务:位置提醒 APP 完整实现
1. 项目核心流程
- 应用启动:获取设备信息,适配 UI 布局和定位策略;
- 权限申请:批量申请通知权限和定位权限;
- 设置目标:用户输入或选择目标位置(经纬度);
- 定位监听:启动持续定位,实时计算与目标位置的距离;
- 提醒触发:到达目标区域,发送通知并停止定位;
- 点击跳转:用户点击通知,进入应用查看详情。
2. 完整代码实现
(1)全局工具类整合(utils/SystemServiceUtil.ets)
// 整合前两篇的通知、定位工具方法,加上设备信息方法 import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; import notification from '@ohos.notification'; import wantAgent from '@ohos.wantAgent'; import geoLocationManager from '@ohos.geolocation'; import deviceInfo from '@ohos.deviceInfo'; import screen from '@ohos.screen'; import common from '@ohos.app.ability.common'; // 权限申请:批量申请通知和定位权限 export async function requestAllPermissions(context: common.UIAbilityContext): Promise<boolean> { const permissions = [ 'ohos.permission.NOTIFICATION_CONTROLLER', 'ohos.permission.APPROXIMATELY_LOCATION', 'ohos.permission.LOCATION' ]; const atManager = abilityAccessCtrl.createAtManager(); try { const authResults = await atManager.checkAccessToken( abilityAccessCtrl.createTokenID(), permissions ); const needReqPerms = permissions.filter( (perm, index) => authResults[index] !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ); if (needReqPerms.length === 0) return true; const reqResult = await atManager.requestPermissionsFromUser(context, needReqPerms); return reqResult.authResults.every(status => status === 0); } catch (err) { console.error(`批量权限申请失败:${JSON.stringify(err)}`); return false; } } // 设备信息方法(同上篇) export function getDeviceBaseInfo() { /* 省略,复用前文代码 */ } export function getScreenInfo() { /* 省略,复用前文代码 */ } export function getLocationConfigByDeviceType() { /* 省略,复用前文代码 */ } // 通知方法(同上篇) export async function createLocationReminderNotification() { /* 省略,复用前文代码 */ } export async function sendNotification() { /* 省略,复用前文代码 */ } // 定位方法(同上篇) export function startContinuousLocation() { /* 省略,复用前文代码 */ } export function stopContinuousLocation() { /* 省略,复用前文代码 */ } export function isReachTargetArea() { /* 省略,复用前文代码 */ }(2)主页面实现(pages/LocationReminderPage.ets)
import common from '@ohos.app.ability.common'; import { requestAllPermissions, getDeviceBaseInfo, getScreenInfo, getLocationConfigByDeviceType, createLocationReminderNotification, sendNotification, startContinuousLocation, stopContinuousLocation, isReachTargetArea } from '../utils/SystemServiceUtil'; @Entry @Component struct LocationReminderPage { private context = getContext(this) as common.UIAbilityContext; @State deviceInfoStr: string = ''; @State currentLocation: string = '未获取位置'; @State targetLat: string = '39.9042'; // 目标纬度默认值 @State targetLng: string = '116.4074'; // 目标经度默认值 @State reminderRadius: number = 100; // 提醒半径(米) @State isTracking: boolean = false; // 页面加载时获取设备信息 aboutToAppear() { this.loadDeviceInfo(); } // 加载设备信息 loadDeviceInfo() { const deviceInfo = getDeviceBaseInfo(); const screenInfo = getScreenInfo(); this.deviceInfoStr = `设备:${deviceInfo.manufacturer} ${deviceInfo.deviceModel} | 系统:${deviceInfo.osVersion} | 屏幕:${screenInfo.screenWidth}x${screenInfo.screenHeight}`; } // 启动位置提醒 async startReminder() { // 1. 检查权限 const allGranted = await requestAllPermissions(this.context); if (!allGranted) { Toast.show({ message: '部分权限未授予,无法启动提醒' }); return; } // 2. 验证目标位置 const targetLoc = { latitude: parseFloat(this.targetLat), longitude: parseFloat(this.targetLng) }; if (isNaN(targetLoc.latitude) || isNaN(targetLoc.longitude)) { Toast.show({ message: '目标位置格式错误' }); return; } // 3. 启动持续定位(根据设备类型适配配置) this.isTracking = true; Toast.show({ message: '位置提醒已启动,正在跟踪您的位置' }); startContinuousLocation((currentLoc) => { this.currentLocation = `当前:纬度${currentLoc.latitude.toFixed(6)},经度${currentLoc.longitude.toFixed(6)}`; // 4. 判断是否到达目标区域 if (isReachTargetArea(currentLoc, targetLoc, this.reminderRadius)) { this.sendReminderNotification(); this.stopReminder(); } }, getLocationConfigByDeviceType()); } // 发送提醒通知 async sendReminderNotification() { const notification = await createLocationReminderNotification( this.context, '位置提醒', `您已到达目标区域(半径${this.reminderRadius}米),点击查看详情` ); await sendNotification(notification); } // 停止位置提醒 stopReminder() { stopContinuousLocation(); this.isTracking = false; Toast.show({ message: '位置提醒已停止' }); } build() { Column({ space: 25 }) .width('100%') .height('100%') .padding(30) .backgroundColor('#f5f5f5') { // 标题区域 Text('位置提醒APP') .fontSize(36) .fontWeight(FontWeight.Bold) .textAlign(TextAlign.Center) .width('100%') // 设备信息区域 Text(this.deviceInfoStr) .fontSize(16) .color('#666') .textAlign(TextAlign.Center) .width('100%') .lineHeight(24) // 目标位置输入区域 Column({ space: 15 }) .width('100%') .padding(20) .backgroundColor('#ffffff') .borderRadius(12) { Text('目标位置设置') .fontSize(20) .fontWeight(FontWeight.Medium) Row({ space: 10 }) .width('100%') { Text('纬度:') .fontSize(18) .width('20%') TextInput({ text: this.targetLat }) .width('80%') .height(45) .padding(10) .border({ width: 1, color: '#eee' }) .borderRadius(8) .fontSize(18) .onChange((value) => this.targetLat = value) } Row({ space: 10 }) .width('100%') { Text('经度:') .fontSize(18) .width('20%') TextInput({ text: this.targetLng }) .width('80%') .height(45) .padding(10) .border({ width: 1, color: '#eee' }) .borderRadius(8) .fontSize(18) .onChange((value) => this.targetLng = value) } Row({ space: 10 }) .width('100%') { Text('提醒半径:') .fontSize(18) .width('30%') TextInput({ text: this.reminderRadius.toString() }) .width('70%') .height(45) .padding(10) .border({ width: 1, color: '#eee' }) .borderRadius(8) .fontSize(18) .onChange((value) => this.reminderRadius = parseInt(value) || 100) Text('米') .fontSize(18) .marginLeft(10) } } // 当前位置显示 Text(this.currentLocation) .fontSize(18) .width('100%') .textAlign(TextAlign.Center) .padding(15) .backgroundColor('#ffffff') .borderRadius(12) // 操作按钮区域 Row({ space: 30 }) .width('100%') .justifyContent(FlexAlign.Center) { Button(this.isTracking ? '停止提醒' : '启动提醒') .type(ButtonType.Capsule) .width(200) .height(60) .fontSize(20) .backgroundColor(this.isTracking ? '#ff4d4f' : '#2f54eb') .onClick(() => { if (this.isTracking) { this.stopReminder(); } else { this.startReminder(); } }) } } } }(3)配置文件完善(module.json5)
{ "module": { "package": "com.example.locationreminder", "name": "LocationReminder", "mainAbility": "MainAbility", "requestPermissions": [ { "name": "ohos.permission.NOTIFICATION_CONTROLLER", "reason": "用于发送位置到达提醒通知", "usedScene": { "abilities": ["MainAbility"], "when": "always" } }, { "name": "ohos.permission.APPROXIMATELY_LOCATION", "reason": "用于获取大致位置,提供位置提醒服务", "usedScene": { "abilities": ["MainAbility"], "when": "inuse" } }, { "name": "ohos.permission.LOCATION", "reason": "用于获取精准位置,提升提醒准确性", "usedScene": { "abilities": ["MainAbility"], "when": "inuse" } } ], "abilities": [ { "name": ".MainAbility", "type": "page", "visible": true, "skills": [ { "entities": ["entity.system.home"], "actions": ["action.system.home"] } ] } ] } }四、APP 核心功能说明
1. 设备适配能力
- 自动识别设备类型(手机 / 平板 / 手表),调整定位策略;
- 根据屏幕尺寸自适应 UI 布局,在不同设备上显示正常;
- 适配不同 API 版本,避免因系统版本差异导致功能异常。
2. 合规性保障
- 批量申请权限,明确告知用户权限用途;
- 定位和通知功能可手动启停,用户可控;
- 到达目标后自动停止定位,降低功耗,符合系统规范。
3. 用户体验优化
- 实时显示当前位置和设备信息,状态透明;
- 支持自定义目标位置和提醒半径,灵活适配不同场景;
- 通知点击跳转应用,形成功能闭环。
加入班级,学习鸿蒙开发