Skip to content

权限管理

HarmonyOS 采用分级权限管理机制,权限分为 system_grant(系统授权)和 user_grant(用户授权)两种类型。应用需要在 module.json5 中声明权限,敏感权限还需在运行时动态申请。

权限类型

类型说明申请方式
system_grant系统授权权限module.json5 中声明即可,安装时自动授予
user_grant用户授权权限需在 module.json5 声明,并在运行时动态申请

前置配置

module.json5 权限声明

module.json5requestPermissions 数组中声明应用需要的权限:

json5
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:reason_internet",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.CAMERA",
        "reason": "$string:reason_camera",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.LOCATION",
        "reason": "$string:reason_location",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "always"
        }
      }
    ]
  }
}

字段说明

字段必填说明
name权限名称
reason权限申请理由,建议引用字符串资源
usedScene.abilities需要使用该权限的 Ability 列表
usedScene.when使用时机:inuse(使用时)/ always(始终)

字符串资源

resources/base/element/string.json 中定义权限理由:

json
{
  "string": [
    {
      "name": "reason_internet",
      "value": "用于访问网络数据"
    },
    {
      "name": "reason_camera",
      "value": "用于拍照和扫描二维码"
    },
    {
      "name": "reason_location",
      "value": "用于获取当前位置信息"
    }
  ]
}

API 列表

API说明起始版本
abilityAccessCtrl.createAtManager()创建权限管理器API 9
AtManager.requestPermissionsFromUser()向用户申请权限API 9
AtManager.checkAccessToken()检查权限授权状态API 9
AtManager.requestPermissionOnSetting()跳转设置页申请权限API 9

常用权限清单

网络相关

权限类型说明
ohos.permission.INTERNETsystem_grant访问网络
ohos.permission.GET_NETWORK_INFOsystem_grant获取网络信息

定位相关

权限类型说明
ohos.permission.APPROXIMATELY_LOCATIONuser_grant获取大概位置
ohos.permission.LOCATIONuser_grant获取精确位置

相机与媒体

权限类型说明
ohos.permission.CAMERAuser_grant使用相机
ohos.permission.MICROPHONEuser_grant使用麦克风
ohos.permission.READ_IMAGEVIDEOuser_grant读取图片/视频
ohos.permission.WRITE_IMAGEVIDEOuser_grant写入图片/视频

存储相关

权限类型说明
ohos.permission.READ_MEDIAuser_grant读取媒体文件
ohos.permission.WRITE_MEDIAuser_grant写入媒体文件

系统相关

权限类型说明
ohos.permission.NOTIFICATIONuser_grant发送通知
ohos.permission.KEEP_BACKGROUND_RUNNINGuser_grant后台运行

权限状态检查

检查单个权限

typescript
import { abilityAccessCtrl } from '@kit.AbilityKit'

function checkPermission(permission: string): boolean {
  const atManager = abilityAccessCtrl.createAtManager()
  const tokenId = getContext().applicationInfo.accessTokenId

  try {
    const result = atManager.checkAccessToken(tokenId, permission)
    return result === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
  } catch (error) {
    console.error('检查权限失败:', JSON.stringify(error))
    return false
  }
}

// 使用示例
const hasCamera = checkPermission('ohos.permission.CAMERA')
console.info('相机权限:', hasCamera ? '已授权' : '未授权')

检查多个权限

typescript
import { abilityAccessCtrl } from '@kit.AbilityKit'

interface PermissionCheckResult {
  permission: string
  granted: boolean
}

function checkPermissions(permissions: string[]): PermissionCheckResult[] {
  const atManager = abilityAccessCtrl.createAtManager()
  const tokenId = getContext().applicationInfo.accessTokenId

  return permissions.map(permission => {
    try {
      const result = atManager.checkAccessToken(tokenId, permission)
      return {
        permission,
        granted: result === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
      }
    } catch (error) {
      return { permission, granted: false }
    }
  })
}

// 使用示例
const results = checkPermissions([
  'ohos.permission.CAMERA',
  'ohos.permission.LOCATION',
  'ohos.permission.MICROPHONE'
])

results.forEach(({ permission, granted }) => {
  console.info(`${permission}: ${granted ? '已授权' : '未授权'}`)
})

动态申请权限

申请单个权限

typescript
import { abilityAccessCtrl } from '@kit.AbilityKit'

async function requestPermission(permission: string): Promise<boolean> {
  const atManager = abilityAccessCtrl.createAtManager()

  try {
    const result = await atManager.requestPermissionsFromUser(
      getContext(),
      [permission]
    )

    return result.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
  } catch (error) {
    console.error('申请权限失败:', JSON.stringify(error))
    return false
  }
}

// 使用示例
async function useCamera() {
  const granted = await requestPermission('ohos.permission.CAMERA')
  if (granted) {
    console.info('相机权限已获取,可以使用相机')
  } else {
    console.info('相机权限被拒绝')
  }
}

申请多个权限

typescript
import { abilityAccessCtrl, PermissionRequestResult } from '@kit.AbilityKit'

interface PermissionRequest {
  permission: string
  granted: boolean
}

async function requestMultiplePermissions(permissions: string[]): Promise<PermissionRequest[]> {
  const atManager = abilityAccessCtrl.createAtManager()

  try {
    const result: PermissionRequestResult = await atManager.requestPermissionsFromUser(
      getContext(),
      permissions
    )

    return result.permissions.map((permission, index) => ({
      permission,
      granted: result.authResults[index] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
    }))
  } catch (error) {
    console.error('申请权限失败:', JSON.stringify(error))
    return permissions.map(permission => ({ permission, granted: false }))
  }
}

// 使用示例
async function initApp() {
  const results = await requestMultiplePermissions([
    'ohos.permission.CAMERA',
    'ohos.permission.LOCATION',
    'ohos.permission.MICROPHONE'
  ])

  results.forEach(({ permission, granted }) => {
    console.info(`${permission}: ${granted ? '已授权' : '未授权'}`)
  })
}

完整权限管理封装

typescript
import { abilityAccessCtrl, PermissionRequestResult } from '@kit.AbilityKit'
import { promptAction } from '@kit.ArkUI'

interface PermissionConfig {
  permission: string
  reason: string
  required: boolean  // 是否为必需权限
}

class PermissionManager {
  private static instance: PermissionManager

  static getInstance(): PermissionManager {
    if (!PermissionManager.instance) {
      PermissionManager.instance = new PermissionManager()
    }
    return PermissionManager.instance
  }

  // 检查权限是否已授权
  checkPermission(permission: string): boolean {
    const atManager = abilityAccessCtrl.createAtManager()
    const tokenId = getContext().applicationInfo.accessTokenId

    try {
      const result = atManager.checkAccessToken(tokenId, permission)
      return result === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
    } catch {
      return false
    }
  }

  // 检查多个权限
  checkPermissions(permissions: string[]): Record<string, boolean> {
    const results: Record<string, boolean> = {}
    permissions.forEach(permission => {
      results[permission] = this.checkPermission(permission)
    })
    return results
  }

  // 申请单个权限
  async requestPermission(permission: string): Promise<boolean> {
    if (this.checkPermission(permission)) {
      return true
    }

    const atManager = abilityAccessCtrl.createAtManager()
    try {
      const result = await atManager.requestPermissionsFromUser(getContext(), [permission])
      return result.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
    } catch {
      return false
    }
  }

  // 申请多个权限
  async requestPermissions(permissions: string[]): Promise<Record<string, boolean>> {
    const atManager = abilityAccessCtrl.createAtManager()
    const results: Record<string, boolean> = {}

    // 先检查哪些权限未授权
    const uncheckedPermissions = permissions.filter(p => !this.checkPermission(p))

    if (uncheckedPermissions.length === 0) {
      permissions.forEach(p => results[p] = true)
      return results
    }

    try {
      const result: PermissionRequestResult = await atManager.requestPermissionsFromUser(
        getContext(),
        uncheckedPermissions
      )

      uncheckedPermissions.forEach((permission, index) => {
        results[permission] = result.authResults[index] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
      })

      // 已授权的权限
      permissions.forEach(permission => {
        if (!uncheckedPermissions.includes(permission)) {
          results[permission] = true
        }
      })
    } catch {
      permissions.forEach(permission => {
        results[permission] = this.checkPermission(permission)
      })
    }

    return results
  }

  // 申请必需权限(带提示)
  async requestRequiredPermissions(configs: PermissionConfig[]): Promise<boolean> {
    const permissions = configs.map(c => c.permission)
    const results = await this.requestPermissions(permissions)

    const deniedRequired = configs.filter(
      config => config.required && !results[config.permission]
    )

    if (deniedRequired.length > 0) {
      const names = deniedRequired.map(c => c.reason).join('、')
      promptAction.showToast({
        message: `需要授权 ${names} 才能继续使用`,
        duration: 3000
      })
      return false
    }

    return true
  }

  // 跳转设置页
  async openPermissionSettings(): Promise<void> {
    const atManager = abilityAccessCtrl.createAtManager()
    try {
      await atManager.requestPermissionOnSetting(getContext(), [])
    } catch (error) {
      console.error('跳转设置页失败:', JSON.stringify(error))
    }
  }
}

export const permissionManager = PermissionManager.getInstance()

使用示例

typescript
import { permissionManager } from '../utils/PermissionManager'

// 定义应用需要的权限
const APP_PERMISSIONS = [
  { permission: 'ohos.permission.CAMERA', reason: '相机', required: true },
  { permission: 'ohos.permission.LOCATION', reason: '定位', required: false },
  { permission: 'ohos.permission.MICROPHONE', reason: '麦克风', required: false }
]

@Entry
@Component
struct PermissionDemo {
  @State cameraGranted: boolean = false
  @State locationGranted: boolean = false
  @State microphoneGranted: boolean = false

  aboutToAppear() {
    this.checkPermissions()
  }

  checkPermissions() {
    this.cameraGranted = permissionManager.checkPermission('ohos.permission.CAMERA')
    this.locationGranted = permissionManager.checkPermission('ohos.permission.LOCATION')
    this.microphoneGranted = permissionManager.checkPermission('ohos.permission.MICROPHONE')
  }

  async requestCamera() {
    const granted = await permissionManager.requestPermission('ohos.permission.CAMERA')
    this.cameraGranted = granted
  }

  async requestAllPermissions() {
    const results = await permissionManager.requestPermissions([
      'ohos.permission.CAMERA',
      'ohos.permission.LOCATION',
      'ohos.permission.MICROPHONE'
    ])

    this.cameraGranted = results['ohos.permission.CAMERA']
    this.locationGranted = results['ohos.permission.LOCATION']
    this.microphoneGranted = results['ohos.permission.MICROPHONE']
  }

  build() {
    Column({ space: 16 }) {
      Text('权限管理')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      Column({ space: 12 }) {
        PermissionRow('相机', this.cameraGranted, () => this.requestCamera())
        PermissionRow('定位', this.locationGranted, async () => {
          const granted = await permissionManager.requestPermission('ohos.permission.LOCATION')
          this.locationGranted = granted
        })
        PermissionRow('麦克风', this.microphoneGranted, async () => {
          const granted = await permissionManager.requestPermission('ohos.permission.MICROPHONE')
          this.microphoneGranted = granted
        })
      }
      .width('100%')
      .padding(16)

      Button('一键申请所有权限')
        .onClick(() => this.requestAllPermissions())
    }
    .width('100%')
    .height('100%')
    .padding(16)
  }
}

@Component
struct PermissionRow {
  @Prop name: string
  @Prop granted: boolean
  onRequest: () => void = () => {}

  build() {
    Row() {
      Text(this.name)
        .fontSize(16)
        .layoutWeight(1)

      Text(this.granted ? '已授权' : '未授权')
        .fontSize(14)
        .fontColor(this.granted ? '#52c41a' : '#ff4d4f')

      if (!this.granted) {
        Button('申请')
          .fontSize(12)
          .onClick(this.onRequest)
      }
    }
    .width('100%')
    .height(48)
  }
}

权限申请最佳实践

  1. 最小权限原则:只申请应用必需的最小权限集合
  2. 按需申请:在需要使用某项功能时再申请对应权限,不要一次性申请所有权限
  3. 说明理由:申请权限时向用户说明用途,提高授权率
  4. 处理拒绝:用户拒绝权限后,提供降级方案或引导用户到设置页开启
  5. 检查状态:使用敏感功能前始终检查权限状态,不要假设权限已授权
  6. 及时释放:不需要定位等持续权限时及时停止,减少用户顾虑
  7. 权限分组:相关权限一起申请,减少弹窗次数

参考链接