• 作者:老汪软件技巧
  • 发表时间:2024-12-13 11:08
  • 浏览量:

为什么访问需要权限?

默认情况下,应用只能访问有限的系统资源。但某些情况下,应用存在扩展功能的诉求,需要访问额外的系统数据(包括用户个人数据)和功能,系统也必须以明确的方式对外提供接口来共享其数据或功能。

试想一下,如果不需要权限就可以访问一些手机的敏感数据不需要权限,某个恶意的app挂羊头卖狗肉,在用户不知情的情况下就扫描完了手机内的相册、视频、联系人等。这是非常危险的行为。

鸿蒙的访问控制权限大体如下图:

企业微信截图_17339855572660.png

权限级别整体分为三大类,从安全程度以及申请的难易程度,从浅到深为系统授权(system_grant)、用户授权(user_grant)和受限开放权限。

一、系统授权(system_grant)

系统授权只需在module.json5声明即可,无需在代码里面弹窗向用户确认,比如网络权限ohos.permission.INTERNET

权限列表可以参考/consumer/cn…

{
  "module" : {
    // ...
    "requestPermissions":[
      {
        "name" : "ohos.permission.PERMISSION1",
        "reason": "$string:reason",
        "usedScene": {
          "abilities": [
            "FormAbility"
          ],
          "when":"inuse"
        }
      },
      {
        "name" : "ohos.permission.PERMISSION2",
        "reason": "$string:reason",
        "usedScene": {
          "abilities": [
            "FormAbility"
          ],
          "when":"always"
        }
      }
    ]
  }
}

二、用户授权(user_grant)

这部分权限除了要在module.json内声明,还需要在代码里面弹窗向用户确认,让用户能够显示的感知到app在申请这个权限。当然一般是要求app在使用时才申请权限,比如用户想拍照时才弹窗申请camera权限,而不是一启动app就把camera权限申请了。

向用户申请权限:

// 使用UIExtensionAbility:将import { UIAbility } from '@kit.AbilityKit' 替换为import { UIExtensionAbility } from '@kit.AbilityKit';
import { abilityAccessCtrl, common, Permissions, UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
​
const permissions: Array<Permissions> = ['ohos.permission.LOCATION','ohos.permission.APPROXIMATELY_LOCATION'];
// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext
function reqPermissionsFromUser(permissions: Array, context: common.UIAbilityContext): void {
  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
  atManager.requestPermissionsFromUser(context, permissions).then((data) => {
    let grantStatus: Array<number> = data.authResults;
    let length: number = grantStatus.length;
    for (let i = 0; i < length; i++) {
      if (grantStatus[i] === 0) {
        // 用户授权,可以继续访问目标操作
      } else {

鸿蒙系统管理员权限获取__鸿蒙权限访问记录

       // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限        return;     }   }    // 授权成功 }).catch((err: BusinessError) => {    console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); }) } // 使用UIExtensionAbility:将 UIAbility 替换为UIExtensionAbility export default class EntryAbility extends UIAbility {  onWindowStageCreate(windowStage: window.WindowStage): void {    // ...    windowStage.loadContent('pages/Index', (err, data) => {      reqPermissionsFromUser(permissions, this.context);    // ...   }); } ​  // ... }

其中也有一些需要注意的点,比如申请前先通过checkAccessToken()检查是否已授权。

用户拒绝授权后,通过requestPermissionsFromUser()和requestPermissionOnSetting()申请二次授权等。

三、受限开放权限

这部分权限属于安全级别最高,普通三方应用都没有权限去开通。如果一定是强需求,可以通过官网的申请流程向应用商店发起流程申请。

四、系统picker和安全控件

user_agent以上的权限都需要用户弹窗感知同意,开发者也要多写一些代码来处理这块逻辑。鸿蒙推出了系统picker和安全控件,目的是为了在一些通用场景减少开发者和用户的负担。

4.1系统picker

应用拉起系统Picker组件(文件选择器、照片选择器、联系人选择器等),由用户在Picker上选择对应的文件、照片、联系人等资源,应用即可获取到Picker的返回结果。

由于系统Picker已经获取了对应权限的预授权,开发者使用系统Picker时,无需再次申请权限也可临时受限访问对应的资源。例如,当应用需要读取用户图片时,可通过使用照片Picker,在用户选择所需要的图片资源后,直接返回该图片资源,而不需要授予应用读取图片文件的权限。

以选择联系人号码为例子:

    contact.selectContacts({
      isMultiSelect: false
    }, (err: BusinessError, data) => {
      if (err) {
        console.error(`selectContact callback: err->${JSON.stringify(err)}`);
        success('')
        return;
      }
      console.log(`selectContact callback: success data->${JSON.stringify(data)}`);
      try {
        success(data[0]?.phoneNumbers?.[0]?.phoneNumber ?? '')
      } catch (e) {
        success('')
      }
    });

无需上面提到的检查权限、动态申请权限这么麻烦,直接拿着内置的contact类用就行了。

4.2 安全控件

安全控件分为粘贴控件、保存控件、位置控件。

分别对应剪切板共享、保存文件、获取位置信息的场景,也是不需要额外申请权限。

安全控件和picker不太一样的是,控件属于ui组件会有统一的系统级别ui。

从用户角度看,不管在哪个app 安全控件的ui都是差不多的。因为系统限制了安全控件ui没法自由定制,需要按照系统的模板来。目的应该也是让用户一看就知道这个是安全控件的按钮。

五、总结

鸿蒙的权限随着安全程度提高,使用的复杂度也跟着提高。整体来看是为了让用户能感知到权限被使用了。

包括user_grant的弹窗,以及更高的受限开放权限。picker需要跳到系统应用,用户能感知到;安全控件有特定的ui用户也能感知到。