|
|
@@ -0,0 +1,293 @@
|
|
|
+import { abilityAccessCtrl, common, Context } from '@kit.AbilityKit';
|
|
|
+import { LogHelper } from '../log/LogHelper';
|
|
|
+import { DialogHelper } from '../dialog/DialogHelper';
|
|
|
+
|
|
|
+const TAG = "PermissionHelper";
|
|
|
+
|
|
|
+// HarmonyOS API 类型定义辅助
|
|
|
+// requestPermissionsFromUser 返回的数据结构
|
|
|
+interface PermissionRequestData {
|
|
|
+ authResults: Array<number>; // GrantStatus 数组
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 权限管理封装
|
|
|
+ *
|
|
|
+ * 统一封装 HarmonyOS 权限请求功能,提供便捷的权限管理方式
|
|
|
+ *
|
|
|
+ * 使用方式:
|
|
|
+ * ```typescript
|
|
|
+ * // 检查权限(异步方法)
|
|
|
+ * const hasPermission = await PermissionHelper.checkPermission(context, 'ohos.permission.CAMERA');
|
|
|
+ *
|
|
|
+ * // 请求单个权限
|
|
|
+ * PermissionHelper.requestPermission(context, 'ohos.permission.CAMERA', (granted) => {
|
|
|
+ * if (granted) {
|
|
|
+ * // 权限已授予
|
|
|
+ * }
|
|
|
+ * })
|
|
|
+ *
|
|
|
+ * // 请求多个权限
|
|
|
+ * PermissionHelper.requestPermissions(context, [
|
|
|
+ * 'ohos.permission.CAMERA',
|
|
|
+ * 'ohos.permission.READ_MEDIA'
|
|
|
+ * ], (permissions) => {
|
|
|
+ * // 处理权限结果
|
|
|
+ * })
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+export class PermissionHelper {
|
|
|
+ /**
|
|
|
+ * 检查权限是否已授予(异步方法)
|
|
|
+ *
|
|
|
+ * HarmonyOS 权限检查是异步的,必须使用此方法
|
|
|
+ *
|
|
|
+ * @param context Context 实例
|
|
|
+ * @param permission 权限名称(如 'ohos.permission.CAMERA')
|
|
|
+ * @return Promise<boolean> true 表示已授予,false 表示未授予
|
|
|
+ */
|
|
|
+ static async checkPermission(context: Context, permission: string): Promise<boolean> {
|
|
|
+ try {
|
|
|
+ const atManager = abilityAccessCtrl.createAtManager();
|
|
|
+ // HarmonyOS 权限检查:使用 checkAccessToken,需要 tokenId 和 permission
|
|
|
+ // tokenId 通过 context 获取,permission 需要转换为正确的类型
|
|
|
+ const tokenId = context.applicationInfo?.accessTokenId ?? 0;
|
|
|
+ if (tokenId === 0) {
|
|
|
+ LogHelper.w(TAG, "无法获取 tokenId,权限检查失败");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // checkAccessToken 接受 permission 参数,需要类型转换
|
|
|
+ // Permissions 类型未导出,使用类型断言处理
|
|
|
+ // 使用函数类型断言绕过类型检查
|
|
|
+ const checkAccessTokenFunc = atManager.checkAccessToken as (
|
|
|
+ tokenId: number,
|
|
|
+ permission: string
|
|
|
+ ) => Promise<abilityAccessCtrl.GrantStatus>;
|
|
|
+ const grantStatus = await checkAccessTokenFunc(tokenId, permission);
|
|
|
+ return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
|
|
|
+ } catch (e) {
|
|
|
+ LogHelper.e(TAG, `检查权限失败: ${permission}`, e as Error);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查多个权限是否已授予(异步方法)
|
|
|
+ *
|
|
|
+ * @param context Context 实例
|
|
|
+ * @param permissions 权限名称数组
|
|
|
+ * @return Promise<Map<权限名, 是否授予>>
|
|
|
+ */
|
|
|
+ static async checkPermissions(context: Context, permissions: string[]): Promise<Record<string, boolean>> {
|
|
|
+ const result: Record<string, boolean> = {};
|
|
|
+ for (let i = 0; i < permissions.length; i++) {
|
|
|
+ const permission = permissions[i];
|
|
|
+ result[permission] = await PermissionHelper.checkPermission(context, permission);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查所有权限是否都已授予(异步方法)
|
|
|
+ *
|
|
|
+ * @param context Context 实例
|
|
|
+ * @param permissions 权限名称数组
|
|
|
+ * @return Promise<boolean> true 表示所有权限都已授予
|
|
|
+ */
|
|
|
+ static async checkAllPermissionsGranted(context: Context, permissions: string[]): Promise<boolean> {
|
|
|
+ const results = await PermissionHelper.checkPermissions(context, permissions);
|
|
|
+ return Object.values(results).every(granted => granted);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 请求单个权限
|
|
|
+ *
|
|
|
+ * 外部接口与 Android 保持一致,内部使用 HarmonyOS 推荐方式
|
|
|
+ *
|
|
|
+ * @param context Context 实例(必须是 UIAbilityContext)
|
|
|
+ * @param permission 权限名称
|
|
|
+ * @param onResult 权限请求结果回调(是否授予)
|
|
|
+ */
|
|
|
+ static async requestPermission(
|
|
|
+ context: Context,
|
|
|
+ permission: string,
|
|
|
+ onResult: (granted: boolean) => void
|
|
|
+ ): Promise<void> {
|
|
|
+ try {
|
|
|
+ // 先异步检查权限是否已授予
|
|
|
+ const hasPermission = await PermissionHelper.checkPermission(context, permission);
|
|
|
+ if (hasPermission) {
|
|
|
+ onResult(true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 请求权限(HarmonyOS 推荐方式)
|
|
|
+ const atManager = abilityAccessCtrl.createAtManager();
|
|
|
+ const permissionsArray: Array<string> = [permission];
|
|
|
+
|
|
|
+ // HarmonyOS API 类型定义问题:requestPermissionsFromUser 要求 Permissions[] 类型
|
|
|
+ // 但 Permissions 类型未导出,实际运行时接受 string[]
|
|
|
+ // 使用类型断言处理:将 string[] 断言为方法期望的类型
|
|
|
+ // 注意:这是 HarmonyOS API 类型定义的问题,运行时不会有问题
|
|
|
+ // 使用双重类型断言绕过类型检查
|
|
|
+ const requestResult = await (atManager.requestPermissionsFromUser as (
|
|
|
+ context: Context,
|
|
|
+ permissions: Array<string>
|
|
|
+ ) => Promise<PermissionRequestData>)(context, permissionsArray);
|
|
|
+
|
|
|
+ const grantResults = requestResult.authResults;
|
|
|
+ const grantStatus = grantResults[0];
|
|
|
+ const granted = grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
|
|
|
+ onResult(granted);
|
|
|
+ } catch (e) {
|
|
|
+ LogHelper.e(TAG, `请求权限异常: ${permission}`, e as Error);
|
|
|
+ onResult(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 请求多个权限
|
|
|
+ *
|
|
|
+ * 外部接口与 Android 保持一致,内部使用 HarmonyOS 推荐方式
|
|
|
+ *
|
|
|
+ * @param context Context 实例(必须是 UIAbilityContext)
|
|
|
+ * @param permissions 权限名称数组
|
|
|
+ * @param onResult 权限请求结果回调(Map<权限名, 是否授予>)
|
|
|
+ */
|
|
|
+ static async requestPermissions(
|
|
|
+ context: Context,
|
|
|
+ permissions: string[],
|
|
|
+ onResult: (permissions: Record<string, boolean>) => void
|
|
|
+ ): Promise<void> {
|
|
|
+ try {
|
|
|
+ // 先异步检查已授予的权限
|
|
|
+ const checkedPermissions: Record<string, boolean> = {};
|
|
|
+ const ungrantedPermissions: string[] = [];
|
|
|
+
|
|
|
+ for (let i = 0; i < permissions.length; i++) {
|
|
|
+ const permission = permissions[i];
|
|
|
+ const hasPermission = await PermissionHelper.checkPermission(context, permission);
|
|
|
+ checkedPermissions[permission] = hasPermission;
|
|
|
+ if (!hasPermission) {
|
|
|
+ ungrantedPermissions.push(permission);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ungrantedPermissions.length === 0) {
|
|
|
+ // 所有权限都已授予
|
|
|
+ onResult(checkedPermissions);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 请求未授予的权限(HarmonyOS 推荐方式)
|
|
|
+ const atManager = abilityAccessCtrl.createAtManager();
|
|
|
+ const permissionsArray: Array<string> = [];
|
|
|
+ for (let i = 0; i < ungrantedPermissions.length; i++) {
|
|
|
+ permissionsArray.push(ungrantedPermissions[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // HarmonyOS API 类型定义问题:requestPermissionsFromUser 要求 Permissions[] 类型
|
|
|
+ // 但 Permissions 类型未导出,实际运行时接受 string[]
|
|
|
+ // 使用函数类型断言绕过类型检查
|
|
|
+ const requestPermissionsFunc = atManager.requestPermissionsFromUser as (
|
|
|
+ context: Context,
|
|
|
+ permissions: Array<string>
|
|
|
+ ) => Promise<PermissionRequestData>;
|
|
|
+ const requestResult = await requestPermissionsFunc(context, permissionsArray);
|
|
|
+
|
|
|
+ const grantResults = requestResult.authResults;
|
|
|
+ const result: Record<string, boolean> = {};
|
|
|
+ // 复制已检查的权限结果
|
|
|
+ const checkedKeys = Object.keys(checkedPermissions);
|
|
|
+ for (let i = 0; i < checkedKeys.length; i++) {
|
|
|
+ const key = checkedKeys[i];
|
|
|
+ result[key] = checkedPermissions[key];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新请求的权限结果
|
|
|
+ for (let i = 0; i < ungrantedPermissions.length; i++) {
|
|
|
+ const permission = ungrantedPermissions[i];
|
|
|
+ const grantStatus = grantResults[i];
|
|
|
+ result[permission] = grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
|
|
|
+ }
|
|
|
+
|
|
|
+ onResult(result);
|
|
|
+ } catch (e) {
|
|
|
+ LogHelper.e(TAG, `请求多个权限异常`, e as Error);
|
|
|
+ // 返回已检查的结果(即使有异常也返回部分结果)
|
|
|
+ const checkedPermissions: Record<string, boolean> = {};
|
|
|
+ for (let i = 0; i < permissions.length; i++) {
|
|
|
+ const permission = permissions[i];
|
|
|
+ try {
|
|
|
+ checkedPermissions[permission] = await PermissionHelper.checkPermission(context, permission);
|
|
|
+ } catch (checkError) {
|
|
|
+ checkedPermissions[permission] = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ onResult(checkedPermissions);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 请求权限(带说明对话框)
|
|
|
+ *
|
|
|
+ * 外部接口与 Android 保持一致,内部使用 HarmonyOS 推荐方式
|
|
|
+ *
|
|
|
+ * @param context Context 实例
|
|
|
+ * @param permission 权限名称
|
|
|
+ * @param rationale 权限说明文本
|
|
|
+ * @param onResult 权限请求结果回调
|
|
|
+ */
|
|
|
+ static async requestPermissionWithRationale(
|
|
|
+ context: Context,
|
|
|
+ permission: string,
|
|
|
+ rationale: string,
|
|
|
+ onResult: (granted: boolean) => void
|
|
|
+ ): Promise<void> {
|
|
|
+ // 先异步检查权限是否已授予
|
|
|
+ const hasPermission = await PermissionHelper.checkPermission(context, permission);
|
|
|
+ if (hasPermission) {
|
|
|
+ onResult(true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // HarmonyOS 权限系统与 Android 不同,这里简化处理
|
|
|
+ // 直接显示说明对话框,然后请求权限
|
|
|
+ DialogHelper.showConfirm(
|
|
|
+ context,
|
|
|
+ "权限说明",
|
|
|
+ rationale,
|
|
|
+ "确定",
|
|
|
+ "取消",
|
|
|
+ () => {
|
|
|
+ // 用户确认后请求权限
|
|
|
+ PermissionHelper.requestPermission(context, permission, onResult);
|
|
|
+ },
|
|
|
+ () => {
|
|
|
+ // 用户取消
|
|
|
+ onResult(false);
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取权限说明文本(根据权限类型)
|
|
|
+ *
|
|
|
+ * @param permission 权限名称
|
|
|
+ * @return 权限说明文本
|
|
|
+ */
|
|
|
+ static getPermissionRationale(permission: string): string {
|
|
|
+ const rationaleMap: Record<string, string> = {
|
|
|
+ 'ohos.permission.CAMERA': '需要访问相机以拍摄照片',
|
|
|
+ 'ohos.permission.READ_MEDIA': '需要访问媒体文件以选择图片',
|
|
|
+ 'ohos.permission.WRITE_MEDIA': '需要保存文件到设备',
|
|
|
+ 'ohos.permission.READ_CONTACTS': '需要访问通讯录',
|
|
|
+ 'ohos.permission.WRITE_CONTACTS': '需要修改通讯录',
|
|
|
+ 'ohos.permission.LOCATION': '需要访问位置信息',
|
|
|
+ 'ohos.permission.MICROPHONE': '需要访问麦克风以录制音频',
|
|
|
+ };
|
|
|
+
|
|
|
+ return rationaleMap[permission] || `需要${permission}权限以完成操作`;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|