鸿蒙技术干货9:deviceInfo 设备信息获取与位置提醒 APP 整合

前两篇咱们分别搞定了通知服务(发送提醒)和地理位置服务(获取位置),这篇咱们先学习设备信息(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. 项目核心流程

  1. 应用启动:获取设备信息,适配 UI 布局和定位策略;
  2. 权限申请:批量申请通知权限和定位权限;
  3. 设置目标:用户输入或选择目标位置(经纬度);
  4. 定位监听:启动持续定位,实时计算与目标位置的距离;
  5. 提醒触发:到达目标区域,发送通知并停止定位;
  6. 点击跳转:用户点击通知,进入应用查看详情。

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. 用户体验优化

  • 实时显示当前位置和设备信息,状态透明;
  • 支持自定义目标位置和提醒半径,灵活适配不同场景;
  • 通知点击跳转应用,形成功能闭环。

加入班级,学习鸿蒙开发

相关推荐
BlackWolfSky2 小时前
鸿蒙暂未归类知识记录
华为·harmonyos
L、2184 小时前
Flutter 与开源鸿蒙(OpenHarmony):跨平台开发的新未来
flutter·华为·开源·harmonyos
L、2185 小时前
Flutter 与 OpenHarmony 深度融合实践:打造跨生态高性能应用(进阶篇)
javascript·flutter·华为·智能手机·harmonyos
威哥爱编程5 小时前
【鸿蒙开发案例篇】火力全开:鸿蒙6.0游戏开发战术手册
harmonyos·arkts·arkui
遇到困难睡大觉哈哈6 小时前
HarmonyOS —— Remote Communication Kit 定制数据传输(TransferConfiguration)实战笔记
笔记·华为·harmonyos
盐焗西兰花6 小时前
鸿蒙学习实战之路-HarmonyOS包转换全攻略
harmonyos
FrameNotWork6 小时前
【HarmonyOS 状态管理超全解析】从 V1 到 V2,一次讲清 @State/@Observed/@Local…等所有装饰器!附超易懂示例!
华为·harmonyos
威哥爱编程7 小时前
【鸿蒙开发案例篇】基于MindSpore Lite的端侧人物图像分割案例
harmonyos·arkts·arkui
我是Feri7 小时前
HarmonyOS 6.0 ArkWeb开发实战:从基础到进阶的ArkUI+ArkTS实践
华为·harmonyos·harmonyos6.0