第31篇:权限管理——PermissionUtil 二次授权策略

img

一、引言

鸿蒙系统对权限管理有严格的要求,用户首次拒绝后应用需要提供二次授权引导。DriverLicenseExam 项目的 PermissionUtil 工具类封装了完整的权限申请流程,包括首次申请、二次授权、状态检查等。本文将深入解析其实现。

二、权限管理架构

2.1 权限状态枚举

enum PermissionStatus {
  GRANTED = 0,   // 已授权
  DENIED = -1,   // 已拒绝
  UNKNOWN = 2,   // 未知
}

2.2 权限管理器

export class PermissionUtil {
  private static _atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  private static _context: Context;
}

三、权限申请流程

3.1 首次申请

public static async requestPermissions(permissions: Permissions[]) {
  const needAuthorized: Permissions[] = [];
  let permissive = true;

  // 检查每个权限的状态
  for (let permission of permissions) {
    const isGranted: boolean = await PermissionUtil._checkPermissions(permission);
    if (!isGranted) {
      needAuthorized.push(permission);
    }
  }

  // 全部已授权,直接返回
  if (!needAuthorized.length) {
    return permissive;
  }

  // 向用户请求授权
  try {
    const data = await PermissionUtil._atManager
      .requestPermissionsFromUser(PermissionUtil._context, needAuthorized);
    let grantStatus: number[] = data.authResults;
    const needAuthorizedAgain: Permissions[] = [];

    for (let i = 0; i < grantStatus.length; i++) {
      if (grantStatus[i] === PermissionStatus.GRANTED) {
        Logger.info(TAG, 'request permission success: ' + needAuthorized[i]);
      } else if (grantStatus[i] === PermissionStatus.DENIED) {
        permissive = false;
        needAuthorizedAgain.push(needAuthorized[i]);
      }
    }

    // 对拒绝的权限进行二次申请
    PermissionUtil._requestPermissionsOnSetting(needAuthorizedAgain);
    return permissive;
  } catch (error) {
    return false;
  }
}

3.2 二次授权

// 用户首次拒绝后,引导用户到设置页面授权
private static async _requestPermissionsOnSetting(permissions: Permissions[]) {
  PermissionUtil._atManager.requestPermissionOnSetting(PermissionUtil._context, permissions)
    .then((data: abilityAccessCtrl.GrantStatus[]) => {
      Logger.info(TAG, 'request permission on setting success: ' + JSON.stringify(data));
    })
    .catch((err: BusinessError) => {
      Logger.error(TAG, 'Failed to request permissions on setting: ' + err.message);
    });
}

3.3 权限状态检查

private static async _checkPermissions(permission: Permissions): Promise<boolean> {
  let grantStatus = await PermissionUtil._checkAccessToken(permission);
  return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
}

private static async _checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {
  let grantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
  let tokenId: number = 0;

  try {
    let bundleInfo = bundleManager.getBundleInfoForSelfSync(
      bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
    let appInfo = bundleInfo.appInfo;
    if (appInfo) {
      tokenId = appInfo.accessTokenId;
    }
  } catch (error) {
    Logger.error(TAG, 'Failed to get bundle info: ' + error.message);
  }

  try {
    grantStatus = await PermissionUtil._atManager.checkAccessToken(tokenId, permission);
  } catch (error) {
    Logger.error(TAG, 'Failed to check access token: ' + error.message);
  }
  return grantStatus;
}

四、权限声明

在 module.json5 中声明应用所需权限:

{
  "requestPermissions": [
    {
      "name": "ohos.permission.INTERNET",
      "reason": "用于网络请求"
    },
    {
      "name": "ohos.permission.APPROXIMATELY_LOCATION",
      "reason": "用于获取当前位置"
    },
    {
      "name": "ohos.permission.LOCATION",
      "reason": "用于获取精确位置"
    },
    {
      "name": "ohos.permission.GET_NETWORK_INFO",
      "reason": "用于获取网络状态"
    },
    {
      "name": "ohos.permission.VIBRATE",
      "reason": "用于答题振动反馈"
    }
  ]
}

五、权限使用场景

// 定位权限申请
Utils.applyLocationPermission().then((city) => {
  if (city) {
    this.guideService.updateCity(city);
  }
});

// 通知权限申请
notificationManager.requestEnableNotification(this.context).then(() => {
  hilog.info(0x0000, 'testTag', '[ANS] requestEnableNotification success');
});

六、总结

PermissionUtil 实现了完整的权限管理流程,包括状态检查、首次申请、二次授权引导,确保应用在最小权限原则下正常运行。


关键源码文件:

  • commons/commonLib/src/main/ets/utils/PermissionUtil.ets
Logo

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

更多推荐