DEV Community

SameX
SameX

Posted on

鸿蒙 Next 权限申请进阶:权限组与单次授权全解析

本文旨在深入探讨华为鸿蒙HarmonyOS Next系统(截止目前 API12)在开发多语言电商平台方面的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。

在鸿蒙 Next 系统的权限管理体系中,权限组与单次授权是两个重要的进阶概念,它们为开发者提供了更优化的权限申请策略,进一步提升了用户体验。今天,我们就深入探讨这两个功能的具体细节。

一、权限组:优化权限申请流程

(一)权限组的概念与功能

权限组是鸿蒙 Next 系统为了减少权限弹窗对用户的打扰而引入的一种管理机制。它将逻辑紧密相关的 user_grant 权限组合在一起,当应用请求权限时,同一个权限组的权限将会在一个弹窗内一起请求用户授权。这就好比将一系列相关的物品打包成一个包裹,一次性递送给用户,而不是逐个递送,从而提高了交互效率。

例如,位置信息权限组可能包含获取精确位置和获取模糊位置等相关权限。通过将这些权限组合在一起,当应用需要获取位置信息时,只需要弹出一个权限申请弹窗,向用户一次性说明应用获取位置信息的目的和所需的具体权限,而不是针对每个位置相关权限分别弹窗,大大减少了弹窗的数量,提升了用户体验。

(二)系统支持的权限组展示

以下是鸿蒙 Next 系统目前支持的一些权限组及其包含的子权限:

权限组 子权限
位置信息权限组 ohos.permission.APPROXIMATELY_LOCATION(获取设备模糊位置信息)、ohos.permission.LOCATION(获取设备位置信息)
通讯录权限组 ohos.permission.READ_CONTACTS(读取联系人数据)、ohos.permission.WRITE_CONTACTS(添加、移除或更改联系人数据)
通话记录权限组 (具体通话记录相关权限,根据实际情况而定)
电话权限组 (具体电话相关权限,如拨打电话、获取通话状态等权限)
信息权限组 (具体信息相关权限,如发送短信、读取短信等权限)
日历权限组 ohos.permission.READ_CALENDAR(读取日历信息)、ohos.permission.WRITE_CALENDAR(添加、移除或更改日历活动)

(三)使用权限组减少弹窗数量的示例代码

以申请位置信息和相机权限为例,假设我们的应用在一个功能中需要同时获取用户的位置信息和使用相机进行拍照操作。按照权限组的方式申请权限,代码如下:

import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

// 定义需要申请的权限列表,包含位置信息权限组和相机权限
const permissions: Array<Permissions> = ['ohos.permission.APPROXIMATELY_LOCATION', 'ohos.permission.LOCATION', 'ohos.permission.CAMERA'];

function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
  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) {
        // 用户授权,可以继续访问目标操作
      } else {
        // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
        return;
      }
    }
    // 授权成功
  }).catch((err: BusinessError) => {
    console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
  });
}

// 在应用启动或需要使用这些权限的地方调用 reqPermissionsFromUser() 函数来申请权限
reqPermissionsFromUser(permissions, globalThis.context as common.UIAbilityContext);
Enter fullscreen mode Exit fullscreen mode

在上述代码中,我们将位置信息权限组中的两个权限(ohos.permission.APPROXIMATELY_LOCATIONohos.permission.LOCATION)以及相机权限(ohos.permission.CAMERA)一起放入权限列表中进行申请。当应用执行到requestPermissionsFromUser()函数时,系统会根据权限组的规则,将位置信息相关的两个权限合并在一个弹窗中展示给用户,而相机权限则在另一个弹窗中展示(因为相机权限属于不同的权限组),这样就有效地减少了弹窗的数量,提升了用户体验。

二、单次授权:提升用户交互体验

(一)单次授权的概念与功能

单次授权是基于授权最小化原则而设计的一种权限授予方式。在某些情况下,应用可能只需要在特定的一次操作中获取某个敏感权限,而不需要长期持有该权限。单次授权允许用户在应用弹窗申请授权时,选择“允许本次使用”,应用将获得临时的权限,仅在本次前台期间或满足特定条件下保持有效。这既满足了应用的临时需求,又避免了应用过度获取权限,有效保护了用户隐私,提升了用户对应用权限管理的信任度。

例如,一个语音识别应用在用户点击录音按钮时,需要使用麦克风权限进行一次短暂的录音操作。通过单次授权,用户可以选择仅在本次操作中允许应用使用麦克风,录音完成后,应用的麦克风权限自动失效,下次需要录音时再重新申请授权。

(二)使用单次授权提升用户体验的示例代码

以下是一个使用单次授权申请麦克风权限的示例代码:

import { abilityAccessCtrl, bundleManager, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

// 定义需要申请的麦克风权限
const permission: Permissions = 'ohos.permission.MICROPHONE';

// 检查当前应用是否已被授予麦克风权限
async function checkPermissionGrant(): Promise<abilityAccessCtrl.GrantStatus> {
  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
  // 获取应用程序的 accessTokenID
  let tokenId: number = 0;
  try {
    let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(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}`);
  }
  // 校验应用是否被授予权限
  try {
    grantStatus = await atManager.checkAccessToken(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}`);
  }
  return grantStatus;
}

// 申请麦克风权限的主函数
async function requestPermission(): Promise<void> {
  let grantStatus: abilityAccessCtrl.GrantStatus = await checkPermissionGrant();
  if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
    // 已经授权,可以继续访问目标操作,这里可以添加使用麦克风的相关代码
    console.log('已获得麦克风权限,可以进行录音等操作。');
  } else {
    // 申请麦克风权限
    reqPermissionFromUser();
  }
}

// 使用 API 动态请求用户授权麦克风权限
function reqPermissionFromUser(): void {
  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  atManager.requestPermissionsFromUser(globalThis.context as common.UIAbilityContext, [permission]).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.log('用户已授权麦克风权限,可以进行录音等操作。');
      } else {
        // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
        console.log('用户拒绝授权麦克风权限,请前往系统设置中手动授予权限。');
        return;
      }
    }
    // 授权成功
  }).catch((err: BusinessError) => {
    console.error(`Failed to request permission from user. Code is ${err.code}, message is ${err.message}`);
  });
}

// 在应用启动或需要使用麦克风的地方调用 requestPermission() 函数来启动权限申请流程
requestPermission();
Enter fullscreen mode Exit fullscreen mode

在这个示例中,当应用需要使用麦克风权限时,首先检查是否已经获得授权。如果未获得授权,通过requestPermissionsFromUser()函数向用户申请授权。用户在弹窗中可以看到“允许本次使用”的选项,如果选择该选项,应用将获得临时的麦克风权限,在本次前台操作期间可以使用麦克风进行录音等操作。一旦应用切后台、灭屏或完成本次录音操作后,临时权限将自动失效,下次需要使用时需重新申请授权。

综上所述,权限组和单次授权是鸿蒙 Next 系统权限管理中的两个重要特性。我们合理运用这两个特性,能够在满足应用功能需求的同时,最大程度地减少对用户的干扰,提升用户体验,构建更加安全、友好的应用环境。希望通过本文的介绍,我们都能够更好地掌握这两个权限申请的进阶功能,为用户带来更加优质的应用体验。

Top comments (0)