权限申请与状态说明:弹窗之前先把边界讲清楚

举报
蓝瘦的蜕变 发表于 2026/07/24 17:30:38 2026/07/24
【摘要】 权限页只讲四件事:先声明、再检查、按需申请、展示结果。不要把真实分布式同步、拍照、定位这类业务流程混进权限入门页。 本 Demo 复用项目已经声明的 ohos.permission.DISTRIBUTEDDATASYNC,只演示权限申请和状态反馈,不执行真实同步。 交互预期 点击“检查权限”,页面显示当前权限是否已授权

权限申请与状态说明:弹窗之前先把边界讲清楚

权限页只讲四件事:先声明、再检查、按需申请、展示结果。不要把真实分布式同步、拍照、定位这类业务流程混进权限入门页。

本 Demo 复用项目已经声明的 ohos.permission.DISTRIBUTED_DATASYNC,只演示权限申请和状态反馈,不执行真实同步。

交互预期

  • 点击“检查权限”,页面显示当前权限是否已授权。
  • 点击“申请权限”,系统可能弹出授权框;页面会显示用户同意、拒绝或请求无效。
  • 点击“重置状态”,只清空页面展示,不修改系统授权状态。
  • API 抛出 BusinessError 时,页面显示 code/message

完整示例代码

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

const ENGINEERING_PERMISSION: Permissions = 'ohos.permission.DISTRIBUTED_DATASYNC'

class PermissionStep {
  title: string
  desc: string

  constructor(title: string, desc: string) {
    this.title = title
    this.desc = desc
  }
}

@Entry
@Component
struct PermissionStateDemo {
  @State permissionState: string = '尚未检查'
  @State requestState: string = '尚未申请'
  @State feedback: string = '本页只演示权限状态和申请结果,不执行真实分布式同步。'
  @State resultDetail: string = '等待操作'

  private atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager()
  private steps: PermissionStep[] = [
    new PermissionStep('先声明', '权限需要先在 module.json5 中声明,运行时只负责申请和展示结果。'),
    new PermissionStep('再检查', '检查当前应用 accessTokenId 对应权限是否已授权。'),
    new PermissionStep('按需申请', '只有用户触发相关能力时才申请,并把同意、拒绝或无效结果展示出来。')
  ]

  private errorToText(error: BusinessError): string {
    return `code=${error.code}, message=${error.message}`
  }

  private grantStatusText(status: abilityAccessCtrl.GrantStatus): string {
    if (status === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
      return '已授权'
    }
    return '未授权'
  }

  private requestResultText(result: number): string {
    if (result === 0) {
      return '用户已授权'
    }
    if (result === -1) {
      return '用户拒绝授权'
    }
    if (result === 2) {
      return '请求无效'
    }
    return `未知结果:${result}`
  }

  private async checkPermission(): Promise<void> {
    this.permissionState = '正在检查'
    this.feedback = '已点击检查权限'
    try {
      const bundleInfo: bundleManager.BundleInfo =
        await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
      const tokenId: number = bundleInfo.appInfo.accessTokenId
      const status: abilityAccessCtrl.GrantStatus =
        await this.atManager.checkAccessToken(tokenId, ENGINEERING_PERMISSION)
      this.permissionState = this.grantStatusText(status)
      this.resultDetail = `权限:${ENGINEERING_PERMISSION}\n检查结果:${this.permissionState}`
      this.feedback = `检查完成:${this.permissionState}`
    } catch (error) {
      const businessError = error as BusinessError
      this.permissionState = '检查失败'
      this.resultDetail = this.errorToText(businessError)
      this.feedback = `检查失败:${this.errorToText(businessError)}`
    }
  }

  private async requestPermission(): Promise<void> {
    this.requestState = '正在申请'
    this.feedback = '已点击申请权限'
    try {
      const context = getContext(this) as common.UIAbilityContext
      const result: PermissionRequestResult =
        await this.atManager.requestPermissionsFromUser(context, [ENGINEERING_PERMISSION])
      const firstResult: number = result.authResults.length > 0 ? result.authResults[0] : 2
      this.requestState = this.requestResultText(firstResult)
      this.permissionState = firstResult === 0 ? '已授权' : '未授权'
      this.resultDetail = `权限:${result.permissions[0]}\n申请结果:${this.requestState}`
      this.feedback = `申请完成:${this.requestState}`
    } catch (error) {
      const businessError = error as BusinessError
      this.requestState = '申请失败'
      this.resultDetail = this.errorToText(businessError)
      this.feedback = `申请失败:${this.errorToText(businessError)}`
    }
  }

  private resetState(): void {
    this.permissionState = '尚未检查'
    this.requestState = '尚未申请'
    this.resultDetail = '等待操作'
    this.feedback = '已重置页面状态。'
  }

  @Builder
  stepCard(index: number) {
    Column({ space: 6 }) {
      Text(this.steps[index].title)
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .fontColor('#111827')
      Text(this.steps[index].desc)
        .fontSize(13)
        .fontColor('#4B5563')
        .lineHeight(20)
    }
    .width('100%')
    .padding(14)
    .borderRadius(12)
    .backgroundColor('#FFFFFF')
    .border({ width: 1, color: '#E5E7EB' })
    .alignItems(HorizontalAlign.Start)
  }

  @Builder
  statusPanel() {
    Column({ space: 10 }) {
      Text('当前权限')
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .fontColor('#111827')
      Text(ENGINEERING_PERMISSION)
        .fontSize(13)
        .fontColor('#4B5563')
      Text(`检查状态:${this.permissionState}`)
        .fontSize(15)
        .fontColor('#2563EB')
      Text(`申请状态:${this.requestState}`)
        .fontSize(15)
        .fontColor('#0F766E')
    }
    .width('100%')
    .padding(16)
    .borderRadius(14)
    .backgroundColor('#FFFFFF')
    .border({ width: 1, color: '#E5E7EB' })
    .alignItems(HorizontalAlign.Start)
  }

  build() {
    Scroll() {
      Column({ space: 20 }) {
        Column({ space: 8 }) {
          Text('权限申请与状态说明')
            .fontSize(28)
            .fontWeight(FontWeight.Bold)
            .fontColor('#111827')
          Text('权限 Demo 只讲声明、检查、申请和反馈,不把真实业务能力混进来。')
            .fontSize(14)
            .fontColor('#4B5563')
            .lineHeight(22)
        }
        .width('100%')
        .alignItems(HorizontalAlign.Start)

        ForEach(this.steps, (item: PermissionStep, index: number) => {
          this.stepCard(index)
        }, (item: PermissionStep) => item.title)

        this.statusPanel()

        Row({ space: 10 }) {
          Button('检查权限')
            .height(48)
            .layoutWeight(1)
            .fontSize(15)
            .backgroundColor('#2563EB')
            .onClick(() => {
              this.checkPermission()
            })
          Button('申请权限')
            .height(48)
            .layoutWeight(1)
            .fontSize(15)
            .backgroundColor('#0F766E')
            .onClick(() => {
              this.requestPermission()
            })
        }
        .width('100%')

        Button('重置状态')
          .height(46)
          .width('100%')
          .fontSize(15)
          .fontColor('#334155')
          .backgroundColor('#E5E7EB')
          .onClick(() => {
            this.resetState()
          })

        Text(this.feedback)
          .width('100%')
          .fontSize(14)
          .fontColor('#1D4ED8')
          .lineHeight(22)
          .padding(12)
          .backgroundColor('#EFF6FF')
          .borderRadius(10)

        Text(this.resultDetail)
          .width('100%')
          .fontSize(13)
          .fontColor('#4B5563')
          .lineHeight(22)
          .padding(16)
          .backgroundColor('#FFFFFF')
          .border({ width: 1, color: '#E5E7EB' })
          .borderRadius(14)
      }
      .width('100%')
      .padding(24)
      .alignItems(HorizontalAlign.Start)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F8FAFC')
  }
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。