HarmonyOS开发:权限测试——权限场景测试

举报
Jack20 发表于 2026/06/24 16:24:23 2026/06/24
【摘要】 HarmonyOS开发:权限测试——权限场景测试📌 核心要点:权限是鸿蒙安全体系的核心防线——运行时权限申请、权限拒绝处理、权限撤销响应、ACL权限配置——任何一个环节处理不当,轻则功能异常,重则安全漏洞。权限测试就是验证你的应用在所有权限场景下的行为是否正确。 一、背景与动机你有没有遇到过这种Bug?用户拒绝了相机权限,你的App直接崩了——因为代码里没处理权限拒绝的情况。或者更隐蔽的...

HarmonyOS开发:权限测试——权限场景测试

📌 核心要点:权限是鸿蒙安全体系的核心防线——运行时权限申请、权限拒绝处理、权限撤销响应、ACL权限配置——任何一个环节处理不当,轻则功能异常,重则安全漏洞。权限测试就是验证你的应用在所有权限场景下的行为是否正确。


一、背景与动机

你有没有遇到过这种Bug?用户拒绝了相机权限,你的App直接崩了——因为代码里没处理权限拒绝的情况。或者更隐蔽的:用户授权了位置权限,用了一会儿又去设置里把权限关了,你的App还在用旧的位置数据,完全不知道权限已经没了。

权限问题有个特点——开发时很难发现,因为开发者通常都点了"允许"。你测了100遍,每次都允许了,所以一切正常。但用户第一次打开App,看到"是否允许访问相机",点了"拒绝"——然后你的App就炸了。

手动测试权限场景?你得去设置里来回开关权限,每改一次就跑一遍功能。权限多了(相机、位置、麦克风、存储、通讯录……),组合场景爆炸——你根本测不过来。权限测试就是用代码系统性地覆盖这些场景,确保无论用户怎么操作,你的App都能正确响应。


二、核心原理

2.1 HarmonyOS权限体系

flowchart TB
    A[HarmonyOS权限体系] --> B[系统权限]
    A --> C[自定义权限]
    A --> D[ACL权限]

    B --> B1[normal级权限<br/>安装时自动授予]
    B --> B2[system_basic级权限<br/>需系统签名]
    B --> B3[system_core级权限<br/>仅系统应用]

    B --> B4[用户授权权限<br/>运行时弹窗申请]
    B --> B5[受限开放权限<br/>需申请ACL]

    C --> C1[自定义权限声明]
    C --> C2[权限级别定义]
    C --> C3[权限使用校验]

    D --> D1[ACL配置]
    D --> D2[权限审批流程]
    D --> D3[受限权限使用]

    classDef mainStyle fill:#4CAF50,stroke:#388E3C,color:#fff,font-weight:bold
    classDef sysStyle fill:#3498DB,stroke:#2980B9,color:#fff
    classDef customStyle fill:#2ECC71,stroke:#27AE60,color:#fff
    classDef aclStyle fill:#F39C12,stroke:#E67E22,color:#fff

    class A mainStyle
    class B,B1,B2,B3,B4,B5 sysStyle
    class C,C1,C2,C3 customStyle
    class D,D1,D2,D3 aclStyle

2.2 权限测试场景矩阵

场景 用户操作 预期行为 常见Bug
首次申请-允许 点击"允许" 功能正常使用
首次申请-拒绝 点击"拒绝" 优雅降级,提示用户 崩溃/功能异常
再次申请-允许 去设置手动开启 功能恢复正常 未监听权限变化
永久拒绝 勾选"不再询问"+拒绝 引导用户去设置页 反复弹窗/无引导
权限撤销 运行中在设置关闭权限 停止使用受保护功能 继续使用旧数据
权限恢复 运行中在设置开启权限 恢复功能 未监听权限恢复
ACL权限缺失 未申请ACL 安装失败或运行时报错 静默失败

2.3 权限API核心流程

import abilityAccessCtrl from '@ohos.abilityAccessCtrl'
import bundleManager from '@ohos.bundle.bundleManager'

// 检查权限状态
const atManager = abilityAccessCtrl.createAtManager()
const grantStatus = await atManager.checkAccessToken(
  bundleManager.getBundleInfoForSelfSync().appId,
  'ohos.permission.CAMERA'
)

// 申请权限
const result = await atManager.requestPermissionsFromUser(context, [
  'ohos.permission.CAMERA',
  'ohos.permission.LOCATION'
])

// result.authResults 数组,0=已授权,-1=未授权

三、代码实战

3.1 基础用法:运行时权限测试

// PermissionTestHelper.ets - 权限测试辅助工具
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'
import bundleManager from '@ohos.bundle.bundleManager'
import { Context } from '@ohos.abilityAccessCtrl'

export class PermissionTestHelper {
  private atManager: abilityAccessCtrl.AtManager
  private context: Context

  constructor(context: Context) {
    this.atManager = abilityAccessCtrl.createAtManager()
    this.context = context
  }

  // 检查单个权限状态
  async checkPermission(permission: Permissions): Promise<boolean> {
    try {
      const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
      const grantStatus = await this.atManager.checkAccessToken(
        bundleInfo.appId,
        permission
      )
      return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
    } catch (e) {
      return false
    }
  }

  // 申请权限
  async requestPermissions(permissions: Array<Permissions>): Promise<Array<number>> {
    const result = await this.atManager.requestPermissionsFromUser(this.context, permissions)
    return result.authResults
  }

  // 获取所有权限状态
  async getAllPermissionStatus(permissions: Array<Permissions>): Promise<Record<string, boolean>> {
    const status: Record<string, boolean> = {}
    for (const permission of permissions) {
      status[permission] = await this.checkPermission(permission)
    }
    return status
  }
}

// ==================== 运行时权限测试 ====================
import { describe, it, beforeAll, assertEqual, assertTrue, assertFalse } from '@ohos/hypium'
import { PermissionTestHelper } from '../PermissionTestHelper'

export default function runtimePermissionTest() {
  describe('运行时权限测试', () => {
    let permHelper: PermissionTestHelper

    beforeAll(() => {
      permHelper = new PermissionTestHelper(getContext(this))
    })

    it('checkPermission_未申请时返回false', 0, async () => {
      // 假设相机权限尚未申请
      const granted = await permHelper.checkPermission('ohos.permission.CAMERA')
      // 注意:这个断言取决于当前权限状态
      // 在测试环境中,通常初始状态是未授权
      assertFalse(granted, '未申请的权限应为false')
    })

    it('requestPermissions_申请相机权限', 0, async () => {
      const results = await permHelper.requestPermissions(['ohos.permission.CAMERA'])
      // 在自动化测试中,权限弹窗可能自动授权
      // 验证返回结果格式正确
      assertEqual(results.length, 1, '应返回1个权限的结果')
    })

    it('checkPermission_授权后返回true', 0, async () => {
      // 先申请权限
      await permHelper.requestPermissions(['ohos.permission.CAMERA'])
      // 再检查权限
      const granted = await permHelper.checkPermission('ohos.permission.CAMERA')
      assertTrue(granted, '授权后权限应为true')
    })

    it('requestPermissions_批量申请多个权限', 0, async () => {
      const results = await permHelper.requestPermissions([
        'ohos.permission.CAMERA',
        'ohos.permission.LOCATION',
        'ohos.permission.MICROPHONE'
      ])
      assertEqual(results.length, 3, '应返回3个权限的结果')
    })
  })
}

3.2 进阶用法:权限拒绝与撤销场景测试

// PermissionAwareService.ets - 权限感知的服务层
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'

export class PermissionAwareService {
  private permissionCache: Map<string, boolean> = new Map()

  // 执行需要权限的操作
  async executeWithPermission(
    permission: Permissions,
    action: () => Promise<void>,
    onDenied: () => void,
    onError: (error: Error) => void
  ): Promise<void> {
    try {
      // 检查权限缓存
      if (this.permissionCache.get(permission) === false) {
        onDenied()
        return
      }

      // 检查实际权限状态
      const atManager = abilityAccessCtrl.createAtManager()
      const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
      const grantStatus = await atManager.checkAccessToken(bundleInfo.appId, permission)

      if (grantStatus !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
        this.permissionCache.set(permission, false)
        onDenied()
        return
      }

      this.permissionCache.set(permission, true)
      await action()
    } catch (e) {
      onError(e as Error)
    }
  }

  // 清除权限缓存(权限变化时调用)
  clearCache(): void {
    this.permissionCache.clear()
  }

  // 更新权限缓存
  updatePermissionCache(permission: string, granted: boolean): void {
    this.permissionCache.set(permission, granted)
  }
}

// ==================== 权限拒绝场景测试 ====================
import { describe, it, beforeAll, beforeEach, assertEqual, assertTrue } from '@ohos/hypium'
import { PermissionAwareService } from '../PermissionAwareService'

export default function permissionDeniedTest() {
  describe('权限拒绝场景测试', () => {
    let service: PermissionAwareService
    let lastAction: string = ''
    let lastError: string = ''

    beforeAll(() => {
      service = new PermissionAwareService()
    })

    beforeEach(() => {
      service.clearCache()
      lastAction = ''
      lastError = ''
    })

    it('权限被拒绝_执行降级逻辑', 0, async () => {
      // 模拟权限被拒绝(缓存设为false)
      service.updatePermissionCache('ohos.permission.CAMERA', false)

      await service.executeWithPermission(
        'ohos.permission.CAMERA',
        async () => { lastAction = '拍照' },
        () => { lastAction = '提示用户授权' },
        (e) => { lastError = e.message }
      )

      assertEqual(lastAction, '提示用户授权', '权限拒绝时应执行降级逻辑')
    })

    it('权限被撤销_停止受保护操作', 0, async () => {
      // 先模拟有权限
      service.updatePermissionCache('ohos.permission.LOCATION', true)

      await service.executeWithPermission(
        'ohos.permission.LOCATION',
        async () => { lastAction = '获取位置' },
        () => { lastAction = '提示用户授权' },
        (e) => { lastError = e.message }
      )
      assertEqual(lastAction, '获取位置', '有权限时应正常执行')

      // 模拟权限被撤销
      service.updatePermissionCache('ohos.permission.LOCATION', false)
      lastAction = ''

      await service.executeWithPermission(
        'ohos.permission.LOCATION',
        async () => { lastAction = '获取位置' },
        () => { lastAction = '提示用户授权' },
        (e) => { lastError = e.message }
      )

      assertEqual(lastAction, '提示用户授权', '权限撤销后应执行降级逻辑')
    })

    it('权限恢复_自动恢复正常功能', 0, async () => {
      // 模拟权限从无到有
      service.updatePermissionCache('ohos.permission.MICROPHONE', false)

      await service.executeWithPermission(
        'ohos.permission.MICROPHONE',
        async () => { lastAction = '录音' },
        () => { lastAction = '提示用户授权' },
        (e) => { lastError = e.message }
      )
      assertEqual(lastAction, '提示用户授权', '无权限时应降级')

      // 模拟权限恢复
      service.clearCache()  // 清除缓存,重新检查
      service.updatePermissionCache('ohos.permission.MICROPHONE', true)
      lastAction = ''

      await service.executeWithPermission(
        'ohos.permission.MICROPHONE',
        async () => { lastAction = '录音' },
        () => { lastAction = '提示用户授权' },
        (e) => { lastError = e.message }
      )
      assertEqual(lastAction, '录音', '权限恢复后应正常执行')
    })

    it('多个权限_部分拒绝部分允许', 0, async () => {
      // 相机允许,位置拒绝
      service.updatePermissionCache('ohos.permission.CAMERA', true)
      service.updatePermissionCache('ohos.permission.LOCATION', false)

      let cameraResult = ''
      let locationResult = ''

      await service.executeWithPermission(
        'ohos.permission.CAMERA',
        async () => { cameraResult = '正常' },
        () => { cameraResult = '降级' },
        (e) => { cameraResult = '错误' }
      )

      await service.executeWithPermission(
        'ohos.permission.LOCATION',
        async () => { locationResult = '正常' },
        () => { locationResult = '降级' },
        (e) => { locationResult = '错误' }
      )

      assertEqual(cameraResult, '正常', '相机权限允许应正常')
      assertEqual(locationResult, '降级', '位置权限拒绝应降级')
    })
  })
}

3.3 完整示例:ACL权限测试

// AclPermissionConfig.ets - ACL权限配置验证器
export interface AclPermissionCheck {
  permission: string
  reason: string            // 使用该权限的原因
  aclRequired: boolean      // 是否需要ACL
  aclApplied: boolean       // 是否已申请ACL
  usedInCode: boolean       // 代码中是否实际使用
}

export class AclPermissionValidator {
  // 检查module.json5中的权限配置
  static validateAclPermissions(
    declaredPermissions: Array<string>,    // module.json5中声明的权限
    aclPermissions: Array<string>,         // 已获得ACL的权限
    codeUsedPermissions: Array<string>     // 代码中实际使用的权限
  ): Array<AclPermissionCheck> {
    // 受限开放权限列表(需要ACL)
    const restrictedPermissions = [
      'ohos.permission.READ_CONTACTS',
      'ohos.permission.WRITE_CONTACTS',
      'ohos.permission.READ_CALENDAR',
      'ohos.permission.WRITE_CALENDAR',
      'ohos.permission.READ_CALL_LOG',
      'ohos.permission.WRITE_CALL_LOG',
      'ohos.permission.READ_MESSAGES',
      'ohos.permission.SEND_MESSAGES',
      'ohos.permission.APPROXIMATELY_LOCATION',
      'ohos.permission.LOCATION',
      'ohos.permission.CAMERA',
      'ohos.permission.MICROPHONE'
    ]

    const results: Array<AclPermissionCheck> = []

    for (const permission of declaredPermissions) {
      const isRestricted = restrictedPermissions.includes(permission)
      const hasAcl = aclPermissions.includes(permission)
      const isUsed = codeUsedPermissions.includes(permission)

      results.push({
        permission,
        reason: isRestricted ? '受限开放权限,需要ACL审批' : '普通用户授权权限',
        aclRequired: isRestricted,
        aclApplied: hasAcl,
        usedInCode: isUsed
      })
    }

    return results
  }
}

// ==================== ACL权限测试 ====================
import { describe, it, assertEqual, assertTrue } from '@ohos/hypium'
import { AclPermissionValidator, AclPermissionCheck } from '../AclPermissionValidator'

export default function aclPermissionTest() {
  describe('ACL权限测试', () => {
    it('受限权限_未申请ACL应标记为缺失', 0, () => {
      const declaredPermissions = [
        'ohos.permission.INTERNET',           // normal级,不需要ACL
        'ohos.permission.CAMERA',             // 受限开放,需要ACL
        'ohos.permission.LOCATION'            // 受限开放,需要ACL
      ]
      const aclPermissions = [
        'ohos.permission.CAMERA'              // 只申请了相机的ACL
      ]
      const codeUsedPermissions = [
        'ohos.permission.INTERNET',
        'ohos.permission.CAMERA',
        'ohos.permission.LOCATION'
      ]

      const results = AclPermissionValidator.validateAclPermissions(
        declaredPermissions, aclPermissions, codeUsedPermissions
      )

      // 验证INTERNET不需要ACL
      const internetCheck = results.find(r => r.permission === 'ohos.permission.INTERNET')
      assertEqual(internetCheck?.aclRequired, false, 'INTERNET不需要ACL')

      // 验证CAMERA已申请ACL
      const cameraCheck = results.find(r => r.permission === 'ohos.permission.CAMERA')
      assertEqual(cameraCheck?.aclRequired, true, 'CAMERA需要ACL')
      assertEqual(cameraCheck?.aclApplied, true, 'CAMERA已申请ACL')

      // 验证LOCATION未申请ACL(问题!)
      const locationCheck = results.find(r => r.permission === 'ohos.permission.LOCATION')
      assertEqual(locationCheck?.aclRequired, true, 'LOCATION需要ACL')
      assertEqual(locationCheck?.aclApplied, false, 'LOCATION未申请ACL——这是配置缺陷')
    })

    it('声明了但未使用的权限_应标记为冗余', 0, () => {
      const declaredPermissions = [
        'ohos.permission.INTERNET',
        'ohos.permission.CAMERA',
        'ohos.permission.MICROPHONE'       // 声明了但没用
      ]
      const aclPermissions: Array<string> = []
      const codeUsedPermissions = [
        'ohos.permission.INTERNET',
        'ohos.permission.CAMERA'
      ]

      const results = AclPermissionValidator.validateAclPermissions(
        declaredPermissions, aclPermissions, codeUsedPermissions
      )

      const micCheck = results.find(r => r.permission === 'ohos.permission.MICROPHONE')
      assertEqual(micCheck?.usedInCode, false, 'MICROPHONE声明了但未使用——冗余权限')
    })

    it('代码中使用了但未声明的权限_应标记为缺失', 0, () => {
      const declaredPermissions = [
        'ohos.permission.INTERNET'
      ]
      const aclPermissions: Array<string> = []
      const codeUsedPermissions = [
        'ohos.permission.INTERNET',
        'ohos.permission.CAMERA'           // 代码中用了但没声明
      ]

      const results = AclPermissionValidator.validateAclPermissions(
        declaredPermissions, aclPermissions, codeUsedPermissions
      )

      // CAMERA不在声明列表中,所以results里不会有它
      // 但代码中使用了它——这是一个配置缺陷
      const cameraDeclared = results.find(r => r.permission === 'ohos.permission.CAMERA')
      assertEqual(cameraDeclared, undefined, 'CAMERA未在module.json5中声明但代码中使用了——配置缺失')
    })

    it('完整权限配置验证_生成报告', 0, () => {
      const declaredPermissions = [
        'ohos.permission.INTERNET',
        'ohos.permission.CAMERA',
        'ohos.permission.LOCATION',
        'ohos.permission.MICROPHONE'
      ]
      const aclPermissions = [
        'ohos.permission.CAMERA',
        'ohos.permission.LOCATION'
      ]
      const codeUsedPermissions = [
        'ohos.permission.INTERNET',
        'ohos.permission.CAMERA',
        'ohos.permission.LOCATION'
      ]

      const results = AclPermissionValidator.validateAclPermissions(
        declaredPermissions, aclPermissions, codeUsedPermissions
      )

      // 统计问题
      const missingAcl = results.filter(r => r.aclRequired && !r.aclApplied)
      const redundant = results.filter(r => !r.usedInCode)
      const allGood = missingAcl.length === 0 && redundant.length === 0

      assertTrue(missingAcl.length === 0, `缺少ACL的权限: ${missingAcl.map(r => r.permission).join(', ')}`)
      assertTrue(redundant.length <= 1, `冗余权限: ${redundant.map(r => r.permission).join(', ')}`)
    })
  })
}

四、踩坑与注意事项

坑点1:权限申请时机不对

用户刚打开App,还没看到任何内容,就弹出一堆权限申请——“允许访问相机?”“允许访问位置?”“允许访问麦克风?”——用户一脸懵,全点了拒绝。

建议:权限申请遵循"用的时候再申请"原则。用户点拍照按钮时才申请相机权限,点定位按钮时才申请位置权限。首次启动只申请必须的权限(如网络权限)。

坑点2:权限拒绝后反复弹窗

用户拒绝了相机权限,你每次打开拍照页面都弹一次权限申请——用户烦了,直接卸载。

建议:检测到用户选择"拒绝且不再询问"后,不再弹窗,而是显示一个说明页面,解释为什么需要这个权限,并提供"去设置"按钮让用户手动开启。

坑点3:权限缓存导致状态不一致

你缓存了权限状态,用户在设置里改了权限,你的缓存还是旧的——代码以为有权限,实际已经没了。

建议:权限缓存的生命周期要短。在关键操作前重新检查权限状态,不要完全依赖缓存。或者在onPageShow/onWindowStageCreate等生命周期回调中刷新缓存。

坑点4:module.json5权限声明和代码不同步

你在module.json5里声明了5个权限,但代码里只用了3个——多声明的2个权限是安全风险。反过来,代码里用了5个权限,但只声明了3个——运行时直接报错。

建议:写一个构建脚本,自动扫描代码中的权限使用,和module.json5中的声明做对比,不一致就报错。

坑点5:ACL权限审批周期长

受限开放权限需要向华为申请ACL,审批可能要几天。如果你在项目后期才发现需要ACL,发布时间就得推迟。

建议:项目初期就梳理所有需要的权限,特别是受限开放权限,尽早申请ACL。把权限清单作为需求评审的一部分。

坑点6:多用户/多设备权限不同步

平板上授权了相机权限,手机上没授权——同一个账号,不同设备的权限状态是独立的。如果你的逻辑假设"授权过就永远有权限",在多设备场景下会出问题。

建议:不要假设权限状态,每次使用前都检查。

坑点7:测试环境中权限弹窗行为不同

真机上权限弹窗有"允许/拒绝/拒绝且不再询问"三个选项,模拟器上可能只有"允许/拒绝"。自动化测试中权限弹窗可能自动授权,导致你测不到拒绝场景。

建议:权限拒绝场景的测试用Mock权限状态,而不是依赖真实的权限弹窗。在PermissionAwareService中注入权限状态,可以模拟任何场景。


五、HarmonyOS 6适配说明

API差异表

功能/接口 HarmonyOS 5 HarmonyOS 6 变更说明
权限申请 requestPermissionsFromUser requestPermissionsFromUser 新增权限说明回调
权限检查 checkAccessToken checkAccessToken 新增批量检查API
权限监听 onPermissionChange 权限变更实时通知
ACL管理 手动配置 @ohos.aclManager ACL自动校验
权限测试 手动模拟 @PermissionTest装饰器 自动权限场景测试

行为变更

  1. 权限说明回调:申请权限时必须提供权限使用说明(reason),系统会在弹窗中展示。如果reason为空,权限申请直接失败。

  2. onPermissionChange实时监听:HarmonyOS 6支持监听权限状态变化,用户在设置中修改权限后,应用能实时收到通知,不再需要手动轮询检查。

  3. @PermissionTest装饰器:测试框架新增权限场景装饰器,可以自动模拟权限授予、拒绝、撤销等场景,不需要手动Mock。

适配代码

// HarmonyOS 6权限测试
import { describe, it, assertEqual, assertTrue } from '@ohos/hypium'
import { PermissionTest, PermissionScenario } from '@ohos/hypium'

export default function harmonyOS6PermissionTest() {
  describe('HarmonyOS 6权限测试', () => {
    // 自动模拟权限拒绝场景
    @PermissionTest({
      permission: 'ohos.permission.CAMERA',
      scenario: PermissionScenario.DENIED
    })
    it('相机权限被拒绝_优雅降级', 0, async () => {
      const result = await cameraService.takePhoto()
      assertTrue(!result.success, '权限拒绝时拍照应失败')
      assertEqual(result.error, 'PERMISSION_DENIED', '错误码应为PERMISSION_DENIED')
    })

    // 自动模拟权限撤销场景
    @PermissionTest({
      permission: 'ohos.permission.LOCATION',
      scenario: PermissionScenario.REVOKED
    })
    it('位置权限被撤销_停止定位', 0, async () => {
      const result = await locationService.getCurrentLocation()
      assertTrue(!result.success, '权限撤销时定位应失败')
    })

    // 权限变更实时监听
    it('onPermissionChange_权限变更通知', 0, async () => {
      let permissionChanged = false
      const atManager = abilityAccessCtrl.createAtManager()
      atManager.onPermissionChange(bundleInfo.appId, ['ohos.permission.CAMERA'], (changeList) => {
        permissionChanged = true
        assertEqual(changeList[0].permission, 'ohos.permission.CAMERA')
      })
      // 模拟权限变更...
      assertTrue(permissionChanged, '权限变更应触发回调')
    })
  })
}

六、总结

维度 评价
学习难度 ⭐⭐⭐
使用频率 ⭐⭐⭐⭐
重要程度 ⭐⭐⭐⭐⭐

权限测试的核心就一句话:永远不要假设用户会点"允许"。你的代码必须在权限被拒绝、被撤销、被恢复的每一种场景下都能正确响应。权限申请时机要合理(用的时候再申请),拒绝处理要优雅(降级而不是崩溃),撤销响应要及时(停止使用受保护功能)。ACL权限是鸿蒙特有的安全机制,受限开放权限必须提前申请ACL,否则上线前才发现就晚了。权限测试不是可选项,是安全合规的硬性要求

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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