HarmonyOS权限管理应用

权限管理

1. 权限管理概述

系统有一些比较敏感的数据和功能(通讯录、麦克风等),不能让应用软件随便访问,所以华为提供了一套授权管理机制来保护系统数据和功能,避免它们被不当或者恶意使用。

应用权限保护的对象可以分为数据和功能:

● 数据包括个人数据(如照片、通讯录、日历、位置等)、设备数据(如设备标识、相机、麦克风等)。

● 功能包括设备功能(如访问摄像头/麦克风、打电话、联网等)、应用功能(如弹出悬浮窗、创建快捷方式等)。

2. 授权方式

根据授权方式的不同,权限类型可分为system_grant(系统授权)和user_grant(用户授权)。

2.1 system_grant(系统授权)

🌶 system_grant指的是系统授权类型,在该类型的权限许可下,应用被允许访问的数据不会涉及到用户或设备的敏感信息,应用被允许执行的操作对系统或者其他应用产生的影响可控。

应用中申请了system_grant权限,系统会在用户安装应用时自动把相应权限授予给用户。

下面是一些常用的系统授权,比如:网络,蓝牙等

ohos.permission.INTERNET

允许使用Internet网络。

权限级别:normal

授权方式:system_grant

起始版本:9

2.2 user_grant(用户授权)

user_grant指的是用户授权类型,在该类型的权限许可下,应用被允许访问的数据将会涉及到用户或设备的敏感信息,应用被允许执行的操作可能对系统或者其他应用产生严重的影响。

user_grant类型权限不仅需要在安装包中申请权限,还需要在应用动态运行时,通过发送弹窗的方式请求用户授权。

在用户手动允许授权后,应用才会真正获取相应权限,从而成功访问操作目标对象。

ohos.permission.MICROPHONE

允许应用使用麦克风。

权限级别:normal

授权方式:user_grant

起始版本:8

3. 申请网络权限

网络权限是属于系统权限,是最基本的功能,申请权限也比较简单。应用需要在module.json5配置文件的requestPermissions标签中声明权限

3.1 配置网络权限

bash 复制代码
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}

3.2 使用网络

bash 复制代码
Image("https://res2.vmallres.com/pimages/uomcdn/CN/pms/202403/gbom/6942103109577/428_428_326614F60FB96289584CA7B9E4AE7CB9mp.png")
    .width(200)
    .height(200)

4. 申请麦克风权限

4.1 配置ohos.permission.MICROPHONE权限

应用需要在module.json5的配置文件中逐个声明需要的权限,否则应用将无法获取授权

bash 复制代码
{
  "module" : {
    // ...
    "requestPermissions": [
      {
        "name": "ohos.permission.MICROPHONE",		//权限名称(这里是麦克风权限)
        "reason": "$string:MICROPHONE_REASON",	//原因
        "usedScene": {													//该权限由谁发起
          "abilities": ["EntryAbility"],				//由EntryAbility发起
          "when": "always"											//发起时机(inuse使用时允许、always总是允许)
        }
      }
    ],
  }
}

4.2 动态申请麦克风授权

动态申请授权指的是拉起系统授权弹窗,让用户选择"允许"或"禁止",只有用户选择"允许"的情况下,才可以执行目标操作。我们以获取麦克风权限为例,让用户选择是否允许授权

bash 复制代码
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager()
atManager.requestPermissionsFromUser(getContext(this),['ohos.permission.MICROPHONE']).then((data) => {
  let grantStatus: Array<number> = data.authResults
  let length: number = grantStatus.length;
  for (let i = 0; i < length; i++) {
    if (grantStatus[i] === 0) {
      // 用户授权成功,可以继续访问目标操作
      console.info("授权成功,可以继续访问目标操作")
    } else {
      // 用户授权失败,不可以执行目标操作
      console.info("授权失败,不可以执行目标操作")
    }
  }
}).catch((err: BusinessError) => {
  console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
});

4.3 校验当前应用是否已经授权

因为无法保证用户是否"允许"授权,所以每次在执行目标操作前,都需要进行检查是否有权限。可以通过调用checkAccessToken()方法来校验当前是否已经授权,如果已经授权,则可以直接访问目标操作;如果没有授权则提醒用户到系统设置手动打开应用权限。

bash 复制代码
//1.1 获取控制管理器
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager()

//1.2 获取应用程序的tokenId,它是应用程序的身份标识
let tokenId: number = 0;
try {
  let bundleInfo: bundleManager.BundleInfo =
    bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
  let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
  tokenId = appInfo.accessTokenId;
} catch (error) {
  const err: BusinessError = error as BusinessError;
  console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);
}

//1.3 校验应用是否被授予权限
let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED
try {
  grantStatus = atManager.checkAccessTokenSync(tokenId, 'ohos.permission.MICROPHONE');
} catch (error) {
  const err: BusinessError = error as BusinessError;
  console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`);
}

//1.4 根据授权状态,决定是否执行目标操作
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
  //TODO 授权成功,执行已经授权的业务代码
  console.info("已经有授权,可以执行目标操作")
} else if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
  //TODO 没有授权,引导用户去设置界面打开麦克风权限
  console.info("没有授权,不能执行目标操作")
}

下面是打开系统设置的代码

bash 复制代码
gotoSystemSetting() {
  const buildInfo =
    bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
  const context = getContext() as common.UIAbilityContext
  context.startAbility({
    bundleName: 'com.huawei.hmos.settings',
    abilityName: 'com.huawei.hmos.settings.MainAbility',
    uri: "application_info_entry",
    parameters: {
      pushParams: buildInfo.name
    }
  })
}

5. 封装权限工具类

5.1 权限工具类

bash 复制代码
import bundleManager from '@ohos.bundle.bundleManager';
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
import { BusinessError, Callback } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';

export class PermissionsUtils {
  /**
   * 校验应用是否具备制定的权限许可,返回权限许可状态
   * @param permission  指定权限
   * @returns 返回许可状态
   */
  public static checkPermissionGrant(permission: Permissions, callback: Callbacks) {
    //1.1 获取控制管理器
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager()

    //1.2 获取应用程序的tokenId,它是应用程序的身份标识
    let tokenId: number = 0;
    try {
      let bundleInfo: bundleManager.BundleInfo =
        bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
      let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
      tokenId = appInfo.accessTokenId;
    } catch (error) {
      const err: BusinessError = error as BusinessError;
      console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);
    }

    //1.3 校验应用是否被授予权限
    let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED
    try {
      grantStatus = atManager.checkAccessTokenSync(tokenId, permission);
    } catch (error) {
      const err: BusinessError = error as BusinessError;
      console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`);
    }

    //1.4 根据授权状态
    if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
      //授权成功,执行已经授权的业务代码
      callback.onSuccess && callback.onSuccess()
    } else if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
      if (callback.onFailed) {
        callback.onFailed()
      } else {
        //没有授权,引导用户去设置界面打开麦克风权限
        PermissionsUtils.gotoSystemSetting();
      }
    }
    return grantStatus
  }

  //2.动态请求用户授权
  public static requestPermissionsFromUser(permissions: Array<Permissions>,
    callback: Callbacks) {
    let context = getContext() as common.UIAbilityContext
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    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) {
          // 用户授权,可以继续访问目标操作
          callback.onSuccess && callback.onSuccess()
        } else {
          // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
          callback.onFailed && callback.onFailed();
        }
      }
      // 授权成功
    }).catch((err: BusinessError) => {
      console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
    });
  }

  public static gotoSystemSetting() {
    const buildInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
    const context = getContext() as common.UIAbilityContext;
    context.startAbility({
      bundleName: 'com.huawei.hmos.settings',
      abilityName: 'com.huawei.hmos.settings.MainAbility',
      uri: "application_info_entry",
      parameters: {
        pushParams: buildInfo.name
      }
    });
  }
}

interface Callbacks {
  onSuccess?: () => void
  onFailed?: () => void
}

5.2 工具类申请权限

bash 复制代码
PermissionsUtils.requestPermissionsFromUser(['ohos.permission.MICROPHONE'], {
  onSuccess: () => {
    console.info("申请麦克风权限成功")
  },
  onFailed:()=>{
    console.info("申请麦克风权限失败")
  }
})

5.3 工具类检查权限

bash 复制代码
PermissionsUtils.checkPermissionGrant("ohos.permission.MICROPHONE",{
  onSuccess:()=>{
    console.info("已经有权限,可以访问目标操作")
  },
  onFailed:()=>{
    console.info("没有权限,去系统设置打开权限")
    PermissionsUtils.gotoSystemSetting()
  }
})

6.申请地理位置权限

6.1 配置地理位置权限

ohos.permission.APPROXIMATELY_LOCATION

允许应用获取设备模糊位置信息。

权限级别:normal

授权方式:user_grant

起始版本:9

先在modeule.json5配置文件中加入权限配置

bash 复制代码
{
  "module" : {
    "requestPermissions":[
      {
        "name": "ohos.permission.APPROXIMATELY_LOCATION",
        "reason": "$string:permission_location",
        "usedScene": {
          "abilities": ["EntryAbility"]
        }
      }
    ]
  }
}

6.2 获取地理位置经纬度

bash 复制代码
import { geoLocationManager } from '@kit.LocationKit';
import { PermissionsUtils } from '../utils/PermissionsUtils';

@Entry
@Component
struct Index {
  @State result: geoLocationManager.Location = {} as geoLocationManager.Location
  @State lcoationPermission: boolean = false

  //进入页面,时申请位置权限
  aboutToAppear(): void {
    PermissionsUtils.requestPermissionsFromUser(
      ['ohos.permission.APPROXIMATELY_LOCATION'],
      {
        onSuccess: () => {
          this.lcoationPermission = true
        }
      }
    )
  }

  build() {
    Column() {
      //点击按钮时,获取经纬度
      Button('获取经纬度')
        .onClick(async () => {
          if (this.lcoationPermission) {
            this.result = await geoLocationManager.getCurrentLocation()
          }
        })
      Text('经度:' + this.result.latitude)
      Text('纬度:' + this.result.longitude)
    }.height('100%')
  }
}
相关推荐
小墙程序员6 小时前
一文了解 Android 5 到 16 期间跨进程通信(IPC) 的使用
android·android studio
MediaTea7 小时前
Python 第三方库:lxml(高性能 XML/HTML 解析与处理)
xml·开发语言·前端·python·html
西陵7 小时前
Nx带来极致的前端开发体验——使用MF进行增量构建
前端·javascript·架构
Nicholas687 小时前
flutter滚动视图之ProxyWidget、ProxyElement、NotifiableElementMixin源码解析(九)
前端
JackieDYH7 小时前
vue3中reactive和ref如何使用和区别
前端·javascript·vue.js
伍哥的传说7 小时前
解密 Vue 3 shallowRef:浅层响应式 vs 深度响应式的性能对决
javascript·vue.js·ecmascript·vue3.js·大数据处理·响应式系统·shallowref
ZZHow10248 小时前
React前端开发_Day4
前端·笔记·react.js·前端框架·web
zzz100668 小时前
Shell 编程基础(续):流程控制与实践
linux·运维·服务器
前端开发爱好者8 小时前
弃用 html2canvas!快 93 倍的截图神器
前端·javascript·vue.js