3. 权限模型基础:权限分类与申请流程

权限管理,说白了就是系统给应用发的一张「通行证」。

我刚开始接触鸿蒙时,第一反应是:这玩意儿跟 Android 的权限有啥区别?后来踩了几个坑才明白——鸿蒙的权限模型,其实更细、更严,也更灵活。今天咱们就把它拆开揉碎了讲清楚。

3.1 权限分类:系统、应用、自定义

鸿蒙把权限分成了三大类。我个人习惯把它们比作「官方许可」「用户授权」「私人定制」。

3.1.1 系统权限

这类权限由系统预定义,普通应用拿不到。比如访问系统设置、修改网络配置、调用硬件底层接口等。说白了,只有系统级应用或系统服务才能申请。

特点:

  • 定义在系统框架层
  • 通常需要 signature 等级
  • 普通开发者基本不用操心

3.1.2 应用权限

这是咱们开发中最常打交道的。比如读取联系人、访问相册、使用摄像头等。鸿蒙把这些权限分成了几个等级,后面会细说。

我记得刚做鸿蒙适配时,有个同事直接把 Android 的权限声明搬过来用,结果应用死活跑不起来。嗯,鸿蒙的权限名称和 Android 不完全一样,得用 ohos.permission.xxx 这种格式。

3.1.3 自定义权限

这个就有点意思了。如果你的应用暴露了一些接口给其他应用调用,你可以自己定义一套权限来控制访问。

举个例子:你做了一个支付 SDK,其他应用想调用你的支付接口。你可以定义一个 com.example.payment.PAY 权限,只有声明了这个权限的应用才能调用。

自定义权限声明示例:
// 在 config.json 或 module.json5 中声明
{
  "permissions": [
    {
      "name": "com.example.payment.PAY",
      "label": "支付权限",
      "description": "允许应用调用支付接口",
      "level": "dangerous"
    }
  ]
}

3.2 权限等级:normal / dangerous / signature

权限等级决定了「申请流程有多麻烦」。鸿蒙分了三个等级,我一个个说。

等级 含义 申请方式 典型例子
normal 普通权限,风险低 声明即授权,无需弹窗 访问网络、读取设备信息
dangerous 危险权限,涉及隐私 需动态申请,用户弹窗确认 读取联系人、使用摄像头
signature 签名权限,系统级 仅同签名应用可获取 系统设置修改、硬件控制

normal 权限:说白了就是「你声明了,系统就给你」。比如网络访问权限,你只需要在配置文件中写上,系统安装时自动授予。

dangerous 权限:这个就得走动态申请流程了。用户得在弹窗里点「允许」才行。我曾经遇到过一个坑——用户拒绝了权限,应用直接崩溃了。后来我加了个判断:如果用户拒绝,就引导去设置里手动开启。

signature 权限:这个最严格。只有跟你用同一个签名证书签名的应用才能获取。说白了,这是系统给「自己人」用的权限。

注意:signature 权限不是你想用就能用的。如果你的应用没有系统签名,声明了也白搭,系统会直接忽略。

3.3 权限申请流程

流程其实不复杂,但细节很多。我把它拆成三步:声明、申请、处理回调。

3.3.1 声明权限

module.json5requestPermissions 字段里声明。注意,这里只声明你需要的权限,不是所有权限都要写。

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.CAMERA",
        "reason": "用于扫码功能"
      },
      {
        "name": "ohos.permission.READ_CONTACTS",
        "reason": "用于导入联系人"
      }
    ]
  }
}

这里有个小细节:reason 字段是必填的。系统会在弹窗时显示这个原因,告诉用户「为什么你需要这个权限」。我建议写得诚恳一点,别写「用于优化体验」这种废话。

3.3.2 动态申请权限

对于 dangerous 权限,需要在代码里调用 API 申请。鸿蒙提供了 requestPermissionsFromUser 方法。

import abilityAccessCtrl from '@ohos.abilityAccessCtrl';

let atManager = abilityAccessCtrl.createAtManager();
let permissions = ['ohos.permission.CAMERA'];

atManager.requestPermissionsFromUser(this.context, permissions).then((data) => {
  // 申请结果
  console.log('权限申请结果:' + JSON.stringify(data));
}).catch((err) => {
  console.error('权限申请失败:' + JSON.stringify(err));
});

我个人习惯在申请前先检查一下权限状态。如果已经授权了,就别再弹窗了,用户体验会好很多。

3.3.3 处理授权结果

用户点击「允许」或「拒绝」后,系统会回调结果。你需要根据结果做相应的处理。

避坑指南:我曾经遇到过用户点击「拒绝」后,应用直接卡死的情况。后来我加了个判断:如果用户拒绝了,就弹个 Toast 提示,然后引导去设置里手动开启。千万别直接崩溃或闪退。
// 检查权限是否授予
if (data.authResults[0] === 0) {
  // 权限已授予,执行操作
  startCamera();
} else {
  // 权限被拒绝,提示用户
  showToast('需要相机权限才能扫码');
  // 可选:跳转到设置页面
  jumpToSettings();
}

3.4 小结

权限模型这块,说白了就是三件事:

  • 分类:系统权限、应用权限、自定义权限
  • 等级:normal(声明即得)、dangerous(动态申请)、signature(同签名才给)
  • 流程:声明 → 申请 → 处理回调

你想想看,如果每个应用都能随便拿权限,那用户的隐私就成筛子了。鸿蒙这套机制,虽然开发时多写几行代码,但换来了用户的安全感。值不值?我觉得值。

下一章咱们聊聊权限组和权限校验的底层实现,到时候我会分享一个我在系统级应用开发中遇到的真实案例。