Harmony OS5—访问权限控制

在 HarmonyOS/OpenHarmony 应用开发中,权限控制是保障用户隐私和数据安全的重要机制。

以下是完整的 ArkTS 权限控制实现方案,包含最佳实践和典型场景示例:

一、权限系统架构设计

1. 权限分级机制

js 复制代码
enum PermissionType {
  // 普通权限(无需用户授权)
  NORMAL = 0, 
  // 敏感权限(需动态申请)
  SENSITIVE = 1,
  // 特殊权限(需跳转设置页)
  SPECIAL = 2
}

2. 权限管理类封装

js 复制代码
class PermissionManager {
  private context: common.UIAbilityContext;
  private atManager: abilityAccessCtrl.AtManager;

  constructor(context: common.UIAbilityContext) {
    this.context = context;
    this.atManager = abilityAccessCtrl.createAtManager();
  }
}

二、动态权限申请实现

1. 基础权限申请

js 复制代码
async requestPermission(permission: string): Promise<boolean> {
  try {
    const grantStatus = await this.atManager.checkAccessToken(
      this.context.tokenId, 
      permission
    );
    
    if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
      return true;
    }

    const result = await this.atManager.requestPermissionsFromUser(
      this.context,
      [permission]
    );
    
    return result.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
  } catch (err) {
    console.error(`Permission request failed: ${err.code}, ${err.message}`);
    return false;
  }
}

2. 批量权限申请优化

js 复制代码
async requestMultiplePermissions(
  permissions: Array<string>
): Promise<Record<string, boolean>> {
  const results: Record<string, boolean> = {};
  
  // 先检查已授权状态
  await Promise.all(permissions.map(async (permission) => {
    const granted = await this.checkPermission(permission);
    if (granted) {
      results[permission] = true;
    }
  }));

  // 筛选未授权权限
  const needRequest = permissions.filter(p => !results[p]);
  if (needRequest.length === 0) return results;

  // 批量申请
  const requestResult = await this.atManager.requestPermissionsFromUser(
    this.context,
    needRequest
  );

  // 合并结果
  needRequest.forEach((permission, index) => {
    results[permission] = 
      requestResult.authResults[index] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
  });

  return results;
}

三、权限使用最佳实践

1. 带解释的权限申请

js 复制代码
async requestWithRationale(
  permission: string,
  rationale: {
    title: string;
    message: string;
    buttonText?: string;
  }
): Promise<boolean> {
  // 先检查是否已拒绝过
  const shouldShowRationale = await this.atManager.shouldShowRequestPermissionRationale(
    this.context,
    permission
  );

  if (shouldShowRationale) {
    await showDialog({
      title: rationale.title,
      message: rationale.message,
      buttons: [
        {
          text: rationale.buttonText || 'OK',
          action: async () => {
            return this.requestPermission(permission);
          }
        }
      ]
    });
  } else {
    return this.requestPermission(permission);
  }
}

2. 权限结果监听

js 复制代码
class PermissionStatusObserver {
  private callback: (permission: string, granted: boolean) => void;

  constructor(callback: (permission: string, granted: boolean) => void) {
    this.callback = callback;
    this.registerObserver();
  }

  private registerObserver() {
    abilityAccessCtrl.on('permissionStateChange', (data) => {
      this.callback(data.permission, data.granted);
    });
  }
}

// 使用示例
new PermissionStatusObserver((permission, granted) => {
  console.log(`Permission ${permission} changed to ${granted}`);
});

四、特殊场景处理

1. 跳转设置页面

js 复制代码
async openPermissionSettings(): Promise<void> {
  try {
    await this.context.startAbility({
      bundleName: 'com.android.settings',
      abilityName: 'com.android.settings.Settings',
      parameters: {
        'destination': 'PERMISSION' // 直达权限设置页
      }
    });
  } catch (err) {
    console.error('Failed to open settings:', err);
  }
}

2. 后台权限管理

js 复制代码
async checkBackgroundPermission(): Promise<boolean> {
  const backgroundPerms = [
    'ohos.permission.LOCATION_IN_BACKGROUND',
    'ohos.permission.READ_MEDIA_IN_BACKGROUND'
  ];

  const results = await this.requestMultiplePermissions(backgroundPerms);
  return Object.values(results).every(Boolean);
}

五、配置声明示例

module.json5 配置:

js 复制代码
{
  "requestPermissions": [
    {
      "name": "ohos.permission.CAMERA",
      "reason": "用于视频通话功能",
      "usedScene": {
        "abilities": ["MainAbility"],
        "when": "always"
      }
    },
    {
      "name": "ohos.permission.READ_MEDIA",
      "reason": "访问用户相册",
      "usedScene": {
        "abilities": ["GalleryAbility"],
        "when": "inuse"
      }
    }
  ]
}

六、关键注意事项:

  1. 最小权限原则:只申请必要的权限
  2. 适时申请:在具体使用场景时申请(如点击拍照按钮时申请相机权限)
  3. 持续监控:定期检查权限状态变化(特别是后台权限)
相关推荐
zandy10111 天前
Agentic BI 架构实战:当AI Agent接管数据建模、指标计算与可视化全链路
人工智能·架构
薪火铺子1 天前
微服务认证方案对比与选型
微服务·云原生·架构
运维全栈笔记1 天前
K8S部署Redis高可用全攻略:1主2从3哨兵架构实战
redis·docker·云原生·容器·架构·kubernetes·bootstrap
weixin_446260851 天前
城市智能化的底层基石:基于腾讯地图服务生态的移动定位与导航架构指引
大数据·人工智能·架构
@#¥&~是乱码鱼啦2 天前
Spring分层架构:Controller、Service、Mapper数据链路,IOC的真实工作意义
java·spring·架构
vortex52 天前
SafeLine 雷池WAF 真实体验,谈谈架构与原理
架构
该昵称用户已存在2 天前
MyEMS 开源能源管理系统:模块化架构赋能精细化能源管控
架构·开源·能源
Ulyanov2 天前
《现代 Python 桌面应用架构实战:PySide6 + QML 从入门到工程化》 开发环境搭建与工具链极简主义 —— 拒绝臃肿,构建工业级基座
开发语言·python·qt·ui·架构·系统仿真
郭龙_Jack2 天前
Kubernetes 架构一张图讲透
架构
渣渣盟2 天前
数据仓库 vs 数据湖 vs 湖仓一体:架构演进与选型
数据仓库·架构