鸿蒙技术干货6:鸿蒙权限管理与后台任务开发指南(下)

上一篇文章介绍了危险权限申请的内容,鸿蒙后台任务分为 "短时任务"(≤3 分钟,如临时数据同步)和 "长时任务"(持续运行,如定位、音频),本文聚焦定位上传场景的长时任务 ,核心依赖backgroundTaskManager模块。

一、后台任务调度:backgroundTaskManager 实战

1. 长时后台任务核心特性

  • 必备权限:ohos.permission.KEEP_BACKGROUND_RUNNING(必须声明)
  • 支持类型:location(定位)、audio(音频)、download(下载)等(需在backgroundModes配置)
  • 合规要求:运行时系统自动显示通知,告知用户 "应用正在后台运行",不可隐藏
  • 核心 API:startBackgroundRunning(启动)、stopBackgroundRunning(停止)

2. 长时任务启动与停止代码

javascript 复制代码
import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager';
import wantAgent from '@ohos.wantAgent';
import common from '@ohos.app.ability.common';

/**
 * 启动定位类型长时后台任务
 */
export async function startLocBackgroundTask(context: common.UIAbilityContext) {
  try {
    // 1. 创建通知代理(点击通知跳转应用)
    const wantAgentInfo = {
      wants: [{
        bundleName: context.applicationInfo.bundleName,
        abilityName: 'LocationAbility'
      }],
      operationType: wantAgent.OperationType.START_ABILITY,
      requestCode: 1001
    };
    const notifyAgent = await wantAgent.getWantAgent(wantAgentInfo);

    // 2. 启动长时后台任务(指定定位类型)
    await backgroundTaskManager.startBackgroundRunning(
      context,
      ['location'], // 任务类型:定位(需与backgroundModes一致)
      notifyAgent
    );
    console.log('长时后台任务启动成功');
  } catch (err) {
    console.error(`后台任务启动失败:${JSON.stringify(err)}`);
    Toast.show({ message: '后台服务启动失败,请重试' });
  }
}

/**
 * 停止长时后台任务(资源释放)
 */
export async function stopLocBackgroundTask(context: common.UIAbilityContext) {
  try {
    await backgroundTaskManager.stopBackgroundRunning(context);
    console.log('长时后台任务停止成功');
  } catch (err) {
    console.error(`后台任务停止失败:${JSON.stringify(err)}`);
  }
}

二、实战整合:位置权限 + 后台定位数据上传

结合前面的权限申请和后台任务,实现 "前台授权→后台持续定位→数据上传" 的完整流程,代码可直接嵌入项目使用:

1. 核心依赖导入

javascript 复制代码
import geoLocationManager from '@ohos.geolocation';
import http from '@ohos.net.http';
import common from '@ohos.app.ability.common';
import { requestForegroundLocPerm, startLocBackgroundTask, stopLocBackgroundTask } from './PermAndTaskUtil';

2. 全局变量与初始化

typescript 复制代码
// 全局状态管理
let locSubscriptionId: number | null = null; // 定位订阅ID
let httpClient: http.HttpClient | null = null; // HTTP上传客户端

/**
 * 初始化定位与后台上传服务
 */
export async function initLocAndBackgroundTask(context: common.UIAbilityContext) {
  // 1. 启动长时后台任务
  await startLocBackgroundTask(context);

  // 2. 初始化HTTP客户端(HTTPS加密传输,合规必备)
  httpClient = http.createHttpClient();
  httpClient.setTimeout(10000); // 超时10秒

  // 3. 配置定位参数(平衡精度与功耗)
  const locRequest = {
    priority: geoLocationManager.LocationRequestPriority.HIGH_ACCURACY, // 高精度模式
    interval: 30000, // 定位间隔30秒(避免频繁定位耗电)
    scenario: geoLocationManager.LocationScenario.NAVIGATION // 导航场景(适合轨迹记录)
  };

  // 4. 订阅位置变化(持续定位)
  locSubscriptionId = geoLocationManager.on('locationChange', locRequest, (location) => {
    console.log(`获取位置:纬度=${location.latitude},经度=${location.longitude}`);
    // 上传位置数据到服务器
    uploadLocData({
      userId: 'user_123456', // 实际开发替换为当前登录用户ID
      lat: location.latitude,
      lng: location.longitude,
      accuracy: location.accuracy,
      timestamp: Date.now()
    });
  });
}

/**
 * 上传位置数据到服务器(HTTPS加密)
 */
async function uploadLocData(data: { userId: string; lat: number; lng: number; accuracy: number; timestamp: number }) {
  if (!httpClient) return;
  try {
    const response = await httpClient.request('https://your-server.com/api/location/upload', {
      method: http.RequestMethod.POST,
      header: { 'Content-Type': 'application/json' },
      body: http.createHttpBody(JSON.stringify(data))
    });

    if (response.responseCode === 200) {
      console.log('位置数据上传成功');
    } else {
      console.error(`上传失败:状态码=${response.responseCode}`);
      // 失败重试机制(最多3次)
      retryUploadLocData(data, 3);
    }
  } catch (err) {
    console.error(`上传异常:${JSON.stringify(err)}`);
  }
}

/**
 * 上传失败重试机制
 */
async function retryUploadLocData(data: any, retryCount: number) {
  if (retryCount <= 0) return;
  setTimeout(async () => {
    try {
      await uploadLocData(data);
    } catch (err) {
      retryUploadLocData(data, retryCount - 1);
    }
  }, 5000 * (4 - retryCount)); // 重试间隔:5秒、10秒、15秒
}

3. 资源释放(避免内存泄漏)

scss 复制代码
/**
 * 释放定位与后台任务资源
 */
export function releaseLocAndBackgroundResource(context: common.UIAbilityContext) {
  // 1. 取消定位订阅
  if (locSubscriptionId !== null) {
    geoLocationManager.off('locationChange', locSubscriptionId);
    locSubscriptionId = null;
  }

  // 2. 停止后台任务
  stopLocBackgroundTask(context);

  // 3. 关闭HTTP客户端
  if (httpClient) {
    httpClient.close();
    httpClient = null;
  }

  console.log('资源释放完成');
}

4. UI 组件触发流程

scss 复制代码
@Entry
@Component
struct LocUploadPage {
  private context = getContext(this) as common.UIAbilityContext;

  build() {
    Column({ space: 30 })
      .width('100%')
      .height('100%')
      .padding(30)
      .backgroundColor('#f5f5f5') {
      
      Text('位置数据同步服务')
        .fontSize(32)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333')

      Button('开启同步服务')
        .type(ButtonType.Capsule)
        .width(280)
        .height(60)
        .backgroundColor('#2f54eb')
        .fontSize(20)
        .onClick(async () => {
          // 触发权限申请,成功后初始化服务
          const isPermGranted = await requestForegroundLocPerm(this.context);
          handlePermResult(isPermGranted, this.context);
        })

      Button('停止同步服务')
        .type(ButtonType.Capsule)
        .width(280)
        .height(60)
        .backgroundColor('#ff4d4f')
        .fontSize(20)
        .onClick(() => {
          // 释放资源,停止服务
          releaseLocAndBackgroundResource(this.context);
          Toast.show({ message: '同步服务已停止' });
        })
    }
  }
}

三、合规性避坑指南(实战经验总结)

后台任务合规红线

  • ❶ 未声明backgroundModes:长时任务必须在 Ability 中配置对应模式(如定位配置["location"]),否则启动失败;
  • ❷ 隐藏后台运行通知:系统自动生成的后台运行通知不可隐藏,这是鸿蒙合规硬性要求;
  • ❸ 定位间隔过短:频繁定位(如 1 秒 / 次)会被系统判定为恶意耗电,建议≥30 秒,电量低时可调整为 60 秒。

加入班级,一起学习鸿蒙开发

相关推荐
万少9 小时前
HarmonyOS官方模板集成创新活动-流蓝卡片
前端·harmonyos
FrameNotWork15 小时前
HarmonyOS 与 Android 架构对比:从“写页面”到“设计系统”的差异
android·架构·harmonyos
supe_rNiu15 小时前
鸿蒙版本 wanAndroid客户端
安卓·harmonyos·鸿蒙
Swift社区17 小时前
HarmonyOS 文件权限管理实战详解(含可运行 Demo)
华为·harmonyos
搬砖的kk21 小时前
鸿蒙PC端C++开发实战:轻量级网络端口扫描工具
华为·harmonyos
马剑威(威哥爱编程)1 天前
【鸿蒙学习笔记】基于HarmonyOS实现申请Push Token的功能
笔记·学习·harmonyos
不爱吃糖的程序媛1 天前
鸿蒙PC端运行C语言程序:从编译到部署的全流程实战
c语言·华为·harmonyos
进击的前栈1 天前
Flutter跨平台滚动视图scrollview_demo鸿蒙化使用指南
flutter·华为·harmonyos
特立独行的猫a1 天前
移植FFmpeg最新 8.1版本到鸿蒙PC(OpenHarmony)平台完整指南
ffmpeg·harmonyos·移植·交叉编译·鸿蒙pc
w139548564221 天前
Flutter跨平台路径解析鸿蒙化使用指南
flutter·华为·harmonyos