🔐 一、HarmonyOS 权限体系概述

HarmonyOS 的权限管理基于 最小权限原则用户可控原则,确保应用只能访问其必需且用户明确授权的资源。权限系统主要分为以下几类:

权限类别 描述 示例 授权方式
普通权限 (normal) 访问不涉及用户敏感数据或系统关键能力的权限。 ohos.permission.INTERNET 安装时自动授予
敏感权限 (system_grant) 访问用户敏感数据或系统受保护资源的权限。 ohos.permission.READ_MEDIA 运行时可申请,系统自动授予
用户授权权限 (user_grant) 访问用户高度敏感数据或核心系统功能的权限。 ohos.permission.ACCELEROMETER 运行时可申请,必须经用户明确授权
受限权限 (restricted) 访问极其敏感数据或能力,有严格的使用限制。 ohos.permission.GET_SENSITIVE_DATA 特殊流程,通常需审核

Stage模型下的权限上下文获取

在 Stage 模型中,不再通过 featureAbility,而是通过 UIAbilityExtensionAbilitycontext来管理权限。

import common from '@ohos.app.ability.common';
// 在UIAbility或自定义类中获取context
let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;

⚙️ 二、权限声明与静态配置

所有权限必须在项目的 module.json5配置文件中预先声明,否则无法在运行时申请或使用。

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET", // 普通权限,自动授予
        "reason": "$string:internet_permission_reason", // 可选,说明权限用途
        "usedScene": { // 可选,说明使用场景
          "abilities": ["MainAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.READ_MEDIA", // 敏感权限,系统授权
        "reason": "$string:read_media_reason",
        "usedScene": {
          "abilities": ["MainAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.ACCELEROMETER", // 用户授权权限
        "reason": "$string:accelerometer_reason", // 必须提供理由,会在弹窗中向用户展示
        "usedScene": {
          "abilities": ["MainAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC", // 分布式数据同步权限
        "reason": "$string:distributed_datasync_reason",
        "usedScene": {
          "abilities": ["MainAbility", "ServiceAbility"],
          "when": "always"
        }
      }
    ]
  }
}
  • reason: 必须用 $string引用资源,用于在系统弹窗中向用户解释为什么需要此权限。描述应清晰、诚实。
  • usedScene: 明确说明权限在哪个(或哪些)Ability中,在什么场景下(alwaysinuse)使用。

📲 三、动态权限申请 (User_grant)

对于需要用户授权的权限,必须在运行时动态申请。以下是标准流程和最佳实践。

1. 检查权限状态

在申请权限或执行敏感操作前,先检查当前是否已拥有该权限。

import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import { BusinessError } from '@ohos.base';

async function checkPermission(permission: string): Promise<number> {
  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  try {
    let grantStatus: number = await atManager.checkAccessToken(abilityAccessCtrl.AccessTokenID.INVALID_TOKEN, permission);
    return grantStatus;
  } catch (error) {
    console.error(`checkAccessToken failed, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message}`);
    return abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
  }
}

// 使用示例
let permission: string = 'ohos.permission.ACCELEROMETER';
let grantStatus: number = await checkPermission(permission);

if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
  // 已授权,执行操作
  startAccelerometer();
} else {
  // 未授权,需要申请
  requestPermission(permission);
}

2. 申请权限

使用 requestPermissionsFromUserAPI 向用户发起授权请求。可以同时申请多个权限。

import common from '@ohos.app.ability.common';

async function requestPermissions(permissions: Array<string>, context: common.UIAbilityContext): Promise<void> {
  try {
    let result = await context.requestPermissionsFromUser(permissions);
    console.info(`Permission request result: ${JSON.stringify(result)}`);

    let grantResult: Record<string, number> = result.authResult;
    let length: number = permissions.length;
    for (let i = 0; i < length; i++) {
      let permission: string = permissions[i];
      if (grantResult[permission] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
        // 用户授权
        console.info(`User granted permission: ${permission}`);
        proceedWithGrantedPermission(permission); // 执行授权后的操作
      } else {
        // 用户拒绝
        console.info(`User denied permission: ${permission}`);
        handlePermissionDenied(permission); // 处理拒绝情况
      }
    }
  } catch (error) {
    console.error(`Request permissions failed, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message}`);
  }
}

// 在UIAbility的onWindowStageCreate或页面组件的aboutToAppear中调用
let permissions: Array<string> = ['ohos.permission.ACCELEROMETER', 'ohos.permission.LOCATION'];
requestPermissions(permissions, this.context);

重要提示requestPermissionsFromUser是一个模态弹窗,一个应用在同一时间只能有一个权限申请弹窗。重复调用会导致错误。

3. 处理授权结果

用户可能授予或拒绝权限,应用需要妥善处理各种情况。

function handlePermissionResult(permission: string, grantStatus: number): void {
  switch (grantStatus) {
    case abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED:
      // 授权成功,执行相关操作
      console.info(`Permission ${permission} is granted`);
      break;
    case abilityAccessCtrl.GrantStatus.PERMISSION_DENIED:
      // 首次拒绝
      console.warn(`Permission ${permission} is denied for the first time`);
      // 可以在此处解释权限的重要性,并引导用户去设置中开启
      showPermissionGuide(permission);
      break;
    case abilityAccessCtrl.GrantStatus.PERMISSION_DENIED_ONCE:
      // 再次拒绝(用户选择了“不再询问”)
      console.error(`Permission ${permission} is denied permanently`);
      // 此时再调用requestPermissionsFromUser也不会弹出系统弹窗
      // 必须引导用户手动到系统设置中为应用开启权限
      guideToAppSettings();
      break;
    default:
      console.error(`Unknown permission status: ${grantStatus}`);
      break;
  }
}

🌐 四、分布式权限管理

在跨设备场景下,权限管理需额外考虑源设备和目标设备的权限状态与用户信任关系。

1. 分布式权限特点

  • 信任关系是基础:设备间需通过同一华为账号登录并互信,才能发起分布式调用。
  • 权限映射:目标设备上,远程调用所需的权限会被映射到本地相应的权限并进行校验。
  • 用户感知:敏感操作可能需要在目标设备上再次征得用户同意,以确保透明和控制。

2. 检查分布式权限

在执行分布式操作前,建议检查目标设备的权限状态。

import distributedPermission from '@ohos.distributedPermission';
import deviceManager from '@ohos.distributedDeviceManager';

async function checkDistributedPermission(deviceId: string, permission: string): Promise<boolean> {
  let dmClass: deviceManager.DeviceManager | null = null;
  try {
    // 获取设备管理器实例
    dmClass = deviceManager.createDeviceManager(getContext(this).bundleName);
    // 获取可信设备列表
    let trustedDeviceList: Array<deviceManager.DeviceInfo> = await dmClass.getTrustedDeviceListSync();
    let isTrusted: boolean = trustedDeviceList.some(device => device.deviceId === deviceId);

    if (!isTrusted) {
      console.error('Target device is not trusted.');
      return false;
    }

    // 检查分布式权限状态(此处为概念性代码,具体API可能有所不同)
    // let result = await distributedPermission.verifyPermission(deviceId, permission);
    // return result;
    return true; // 假设已授权
  } catch (error) {
    console.error(`Check distributed permission failed: ${(error as BusinessError).message}`);
    return false;
  } finally {
    if (dmClass != null) {
      // 释放资源
    }
  }
}

🛡️ 五、权限使用的最佳实践与安全考量

  1. 按需申请:仅在需要时才申请权限,避免在应用启动时一次性申请所有权限,这可能会吓到用户导致拒绝。
  2. 充分解释:在调用 requestPermissionsFromUser前,最好在应用的 UI 中先解释为什么需要这个权限(例如,“需要位置权限来为您推荐附近的店铺”),这能显著提高授权通过率。
  3. 优雅降级:如果用户拒绝授予某个非核心功能的权限,应用应能优雅降级,继续提供其他功能,而不是崩溃或无法使用。
  4. 持续可用性:用户可能随时在系统设置中更改权限。对于关键权限,在相关操作前再次检查其状态是良好的习惯。
  5. 最小化数据访问:即使获得了权限,也只访问和存储业务所必需的最小数据量。
  6. 安全存储:通过权限获取的敏感数据必须进行安全存储和传输,例如使用加密的分布式数据库。

🧪 六、测试与调试

1. 使用 hdc命令管理权限

通过 HiSilicon Debugger (hdc) 工具,可以模拟授权和撤销权限,方便测试。

# 授予权限
hdc shell aa grant <packageName> <permission>

# 撤销权限
hdc shell aa revoke <packageName> <permission>

# 示例:为包名为 com.example.myapp 的应用授予地理位置权限
hdc shell aa grant com.example.myapp ohos.permission.LOCATION

2. 处理权限错误码

权限操作可能会抛出错误,应妥善处理。

import { BusinessError } from '@ohos.base';

try {
  // ... 权限操作
} catch (error) {
  let err: BusinessError = error as BusinessError;
  switch (err.code) {
    case 201: // 权限未授权
      console.error('Permission is not granted.');
      break;
    case 202: // 权限操作失败
      console.error('Permission operation failed.');
      break;
    // ... 其他错误码
    default:
      console.error(`Unknown error code: ${err.code}, message: ${err.message}`);
  }
}

💡 七、常见问题与解决方案

  1. 调用 requestPermissionsFromUser无弹窗
    • 原因:权限已在 module.json5中声明为 system_grantnormal;或用户已选择“不再询问”。
    • 解决:检查权限类型;引导用户去系统设置中手动开启。
  2. 分布式调用失败,提示权限不足
    • 原因:目标设备未授权相应权限;设备间信任关系失效。
    • 解决:检查目标设备权限;确保设备已重新互信。
  3. 权限已被授予,但访问资源仍失败
    • 原因:可能使用了错误的 API 或参数;资源本身不可用。
    • 解决:检查 API 文档;验证资源路径或标识符是否正确。
  4. requestPermissionsFromUser抛出错误
    • 原因:通常是因为已有另一个权限请求弹窗正在显示。
    • 解决:确保同一时间只有一个权限请求。

通过遵循以上指南和最佳实践,你可以在 HarmonyOS 5 应用中实现一套健壮、用户友好且安全的权限管理机制,为应用的功能实现和用户的数据安全奠定坚实基础。

需要参加鸿蒙认证的请点击 鸿蒙认证链接

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐