鸿蒙技术干货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 秒。

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

相关推荐
L、2183 小时前
统一日志与埋点系统:在 Flutter + OpenHarmony 混合架构中实现全链路可观测性
javascript·华为·智能手机·electron·harmonyos
hefengbao5 小时前
『京墨文库』鸿蒙版上线!
harmonyos·arkts·arkui·arkdata
赵浩生5 小时前
鸿蒙技术干货5:鸿蒙权限管理与后台任务开发指南(上)
harmonyos
kirk_wang6 小时前
Flutter插件跨平台适配技术分析之是否需要适配鸿蒙端-screenshot
flutter·华为·harmonyos
赵财猫._.7 小时前
React Native鸿蒙开发实战(七):性能优化与调试技巧
react native·性能优化·harmonyos
晚霞的不甘8 小时前
[鸿蒙2025领航者闯关] Flutter + OpenHarmony 模块化架构设计:大型应用的可维护性与协作之道
flutter·华为·harmonyos·鸿蒙·鸿蒙系统
cuicuiniu5219 小时前
释放数字生产力:浩辰CAD看图王适配HarmonyOS 6 系统
华为·harmonyos
晚霞的不甘9 小时前
[鸿蒙2025领航者闯关]:Flutter + OpenHarmony 插件开发指南:打通 Dart 与原生能力的桥梁
flutter·华为·harmonyos
汉堡黄•᷄ࡇ•᷅10 小时前
鸿蒙开发:案例集合List:多列表(List)相互拖拽(位置交换)
harmonyos·鸿蒙·鸿蒙系统