前两篇咱们分别搞定了通知服务(发送提醒)和地理位置服务(获取位置),这篇咱们先学习设备信息(deviceInfo)的核心用法,适配不同设备的硬件和系统特性,再将三大服务整合,完成 "位置提醒 APP" 的完整开发。让咱们从设备适配到功能闭环,一步步实现可直接复用的实战项目!
一、设备信息服务核心认知
1. 设备信息的应用价值
- 设备适配:根据屏幕尺寸调整 UI 布局、根据系统版本适配 API;
- 功能优化:根据设备型号调整定位策略(如高端机支持高精度 GNSS);
- 问题排查:记录设备信息用于日志分析,快速定位兼容性问题;
- 个性化服务:根据设备特性提供定制化功能(如平板端显示更多操作入口)。
2. 核心 API 与可获取信息
-
核心模块:
@ohos.deviceInfo(设备信息)、@ohos.screen(屏幕信息) -
关键信息:
- 设备基础信息:型号、厂商、设备 ID;
- 系统信息:系统版本、API 版本、设备类型;
- 屏幕信息:屏幕尺寸、分辨率、像素密度。
二、设备信息获取实战
1. 获取设备基础信息
typescript
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 布局)
ini
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. 设备适配实战(根据设备类型调整功能)
ini
/**
* 根据设备类型调整定位配置
* 手机:高精度模式,平板:平衡模式,手表:低功耗模式
*/
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)
javascript
// 整合前两篇的通知、定位工具方法,加上设备信息方法
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)
typescript
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)
json
{
"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. 用户体验优化
- 实时显示当前位置和设备信息,状态透明;
- 支持自定义目标位置和提醒半径,灵活适配不同场景;
- 通知点击跳转应用,形成功能闭环。