当前位置: 首页 > article >正文

鸿蒙中 应用的权限:申请授权(三)

本文同步发表于我的微信公众号微信搜索程语新视界即可关注每个工作日都有文章更新鸿蒙应用开发中当应用需要访问用户的隐私信息或使用系统能力时如获取位置、使用相机、访问日历等必须向用户申请授权。这些权限属于user_grant类型。user_grant权限指的是需要用户明确授权的权限通常涉及用户隐私信息或系统能力。常见user_grant权限位置信息精确/模糊相机拍摄麦克风录音日历访问通讯录读取健身运动数据user_grant权限的申请原则原则说明用户可知可控必须由用户主动授权系统弹窗提示最小化原则只申请业务必需的权限动态申请在需要使用权限时申请而非启动时全部申请不频繁弹窗避免频繁打扰用户二、user_grant权限申请流程2.1 四步走流程步骤1在配置文件中声明权限 ↓ 步骤2将权限与目标操作关联开发阶段 ↓ 步骤3运行时检查权限 → 未授权则动态申请 ↓ 步骤4处理授权结果同意/拒绝2.2 步骤1声明权限module.json5{ module: { requestPermissions: [ { name: ohos.permission.LOCATION, reason: $string:location_permission_reason, usedScene: { abilities: [EntryAbility], when: inuse } }, { name: ohos.permission.APPROXIMATELY_LOCATION, reason: $string:approximately_location_permission_reason, usedScene: { abilities: [EntryAbility], when: inuse } } ] } }注意user_grant权限必须填写reason和usedScene字段用于上架审核和用户知情。2.3 步骤2权限与目标操作关联在代码层面将需要权限的操作与权限检查逻辑关联。三、核心开发步骤步骤3-43.1 导入所需模块import { abilityAccessCtrl, bundleManager, Permissions, common } from kit.AbilityKit; import { BusinessError } from kit.BasicServicesKit;3.2 检查权限是否已授权在进行权限申请之前需要先检查当前应用是否已被授予权限。// PermissionUtil.ets import { abilityAccessCtrl, bundleManager, Permissions } from kit.AbilityKit; import { BusinessError } from kit.BasicServicesKit; async function checkPermissionGrant(permission: Permissions): PromiseabilityAccessCtrl.GrantStatus { let atManager: abilityAccessCtrl.AtManager abilityAccessCtrl.createAtManager(); let grantStatus: abilityAccessCtrl.GrantStatus abilityAccessCtrl.GrantStatus.PERMISSION_DENIED; // 1. 获取应用程序的accessTokenID let tokenId: number 0; try { let bundleInfo: bundleManager.BundleInfo await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); let appInfo: bundleManager.ApplicationInfo bundleInfo.appInfo; tokenId appInfo.accessTokenId; } catch (error) { const err: BusinessError error as BusinessError; console.error(Failed to get bundle info, code: ${err.code}, message: ${err.message}); } // 2. 校验应用是否被授予权限 try { grantStatus await atManager.checkAccessToken(tokenId, permission); } catch (error) { const err: BusinessError error as BusinessError; console.error(Failed to check access token, code: ${err.code}, message: ${err.message}); } return grantStatus; } // 检查多个权限的状态 async function checkPermissions(): Promisevoid { // 获取精确定位权限状态 let grantStatus1: boolean await checkPermissionGrant(ohos.permission.LOCATION) abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED; // 获取模糊定位权限状态 let grantStatus2: boolean await checkPermissionGrant(ohos.permission.APPROXIMATELY_LOCATION) abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED; // 精确定位权限只能跟模糊定位权限一起申请或者已经有模糊定位权限才能申请精确定位权限 if (grantStatus2 !grantStatus1) { // 已有模糊权限需要申请精确定位权限 console.info(Need to request precise location permission); } else if (!grantStatus1 !grantStatus2) { // 两种权限都没有需要申请模糊定位权限与精确定位权限 console.info(Need to request both permissions); } else { // 已经授权可以继续访问目标操作 console.info(Permissions already granted); } }3.3 动态向用户申请授权通过requestPermissionsFromUser()方法向用户请求授权。方式一在UIAbility中申请授权// SecondAbility.ets import { abilityAccessCtrl, common, Permissions, UIAbility } from kit.AbilityKit; import { window } from kit.ArkUI; import { BusinessError } from kit.BasicServicesKit; const permissions: Permissions[] [ ohos.permission.LOCATION, ohos.permission.APPROXIMATELY_LOCATION ]; function reqPermissionsFromUser(permissions: ArrayPermissions, context: common.UIAbilityContext): void { let atManager: abilityAccessCtrl.AtManager abilityAccessCtrl.createAtManager(); // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗 atManager.requestPermissionsFromUser(context, permissions) .then((data) { let grantStatus: number[] data.authResults; for (let i 0; i grantStatus.length; i) { if (grantStatus[i] 0) { // 用户授权 console.info(${permissions[i]} is granted by user.); } else { // 用户拒绝授权 console.warn(${permissions[i]} is denied by user.); // 引导用户到设置中开启 this.guideToSettings(); } } }) .catch((err: BusinessError) { console.error(Failed to request permissions, code: ${err.code}, message: ${err.message}); }); } export default class SecondAbility extends UIAbility { onWindowStageCreate(windowStage: window.WindowStage): void { // 重要需要在loadContent回调中申请权限 windowStage.loadContent(secondpages/Index, (err) { if (!err) { reqPermissionsFromUser(permissions, this.context); } }); } private guideToSettings(): void { // 引导用户去设置页面 console.info(Guide user to settings); } }方式二在UI中申请授权// Index.ets import { abilityAccessCtrl, common, Permissions } from kit.AbilityKit; import { BusinessError } from kit.BasicServicesKit; const permissions: Permissions[] [ ohos.permission.LOCATION, ohos.permission.APPROXIMATELY_LOCATION ]; function reqPermissionsFromUser(permissions: ArrayPermissions, context: common.UIAbilityContext): void { let atManager: abilityAccessCtrl.AtManager abilityAccessCtrl.createAtManager(); atManager.requestPermissionsFromUser(context, permissions) .then((data) { let grantStatus: number[] data.authResults; for (let i 0; i grantStatus.length; i) { if (grantStatus[i] 0) { console.info(${permissions[i]} is granted.); } else { console.warn(${permissions[i]} is denied.); // 可以在UI上提示用户 } } }) .catch((err: BusinessError) { console.error(Failed to request permissions, code: ${err.code}); }); } Entry Component struct Index { aboutToAppear() { const context: common.UIAbilityContext this.getUIContext().getHostContext() as common.UIAbilityContext; reqPermissionsFromUser(permissions, context); } build() { Column() { Text(位置权限示例) .fontSize(20) .margin(20) Button(获取位置) .onClick(() { // 每次使用前最好再检查一次权限 // 因为用户可能在设置中关闭了权限 }) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }3.4 处理授权结果用户同意授权if (grantStatus[i] 0) { // 用户授权可以继续访问目标操作 this.accessLocation(); }用户拒绝授权当用户拒绝授权时有几种处理方式方式1引导用户到系统设置中开启import { common } from kit.AbilityKit; private guideToSettings() { let context getContext(this) as common.UIAbilityContext; context.startAbility({ action: action.settings.app.info, parameters: { bundleName: com.example.myapp } }); }方式2调用requestPermissionOnSetting拉起权限设置弹窗// 从API 12开始支持 async function requestPermissionInSetting(permission: Permissions) { let atManager abilityAccessCtrl.createAtManager(); try { await atManager.requestPermissionOnSetting(this.context, permission); // 用户已在设置中授权 console.info(Permission granted in settings); } catch (error) { console.error(Failed to request permission in setting); } }四、限制4.1 弹窗规则规则说明不可被遮挡系统权限弹窗不可被其他组件或控件遮挡完整展示弹窗信息需完整展示便于用户识别优先级最高如果与其他组件同时展示系统权限弹窗将默认覆盖其他组件4.2 调用时机限制场景要求在UIAbility的onWindowStageCreate中申请需要等待loadContent/setUIContent执行结束后或在回调中调用在UIExtensionAbility中申请需要在onWindowStageCreate函数执行结束后或在回调中调用原因在Content加载完成前requestPermissionsFromUser会调用失败4.3 权限状态不可持久化// 错误做法缓存授权状态 let cachedPermission true; // 假设用户之前授权了 if (cachedPermission) { this.accessLocation(); // 可能失败因为用户可能在设置中关闭了权限 } // 正确做法每次使用前检查 async function accessLocation() { let grantStatus await checkPermissionGrant(ohos.permission.LOCATION); if (grantStatus abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { // 已授权可以访问 } else { // 未授权重新申请 } }原因用户可能在动态授予权限后通过系统设置来取消应用的权限因此不能将之前授予的授权状态持久化。五、完整示例5.1 权限声明module.json5{ module: { requestPermissions: [ { name: ohos.permission.APPROXIMATELY_LOCATION, reason: $string:approximately_location_permission_reason, usedScene: { abilities: [EntryAbility], when: inuse } }, { name: ohos.permission.LOCATION, reason: $string:location_permission_reason, usedScene: { abilities: [EntryAbility], when: inuse } } ] } }5.2 权限工具类// PermissionManager.ets import { abilityAccessCtrl, bundleManager, Permissions, common } from kit.AbilityKit; import { BusinessError } from kit.BasicServicesKit; export class PermissionManager { private static instance: PermissionManager; private atManager: abilityAccessCtrl.AtManager; private constructor() { this.atManager abilityAccessCtrl.createAtManager(); } static getInstance(): PermissionManager { if (!PermissionManager.instance) { PermissionManager.instance new PermissionManager(); } return PermissionManager.instance; } // 检查单个权限 async checkPermission(permission: Permissions): Promiseboolean { try { let bundleInfo await bundleManager.getBundleInfoForSelf( bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION ); let tokenId bundleInfo.appInfo.accessTokenId; let grantStatus await this.atManager.checkAccessToken(tokenId, permission); return grantStatus abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED; } catch (error) { console.error(Check permission failed, error); return false; } } // 申请权限 async requestPermissions(permissions: Permissions[], context: common.UIAbilityContext): Promiseboolean { try { let result await this.atManager.requestPermissionsFromUser(context, permissions); // 检查是否所有权限都被授予 return result.authResults.every(status status 0); } catch (error) { console.error(Request permissions failed, error); return false; } } // 检查并申请权限一步到位 async checkAndRequestPermissions(permissions: Permissions[], context: common.UIAbilityContext): Promiseboolean { // 先检查是否都已授权 for (let perm of permissions) { let granted await this.checkPermission(perm); if (!granted) { // 有未授权的权限发起申请 return await this.requestPermissions(permissions, context); } } return true; // 全部已授权 } }5.3 在页面中使用// LocationPage.ets import { PermissionManager } from ./PermissionManager; import { common } from kit.AbilityKit; Entry Component struct LocationPage { State hasPermission: boolean false; State locationText: string 未知位置; async aboutToAppear() { const context this.getUIContext().getHostContext() as common.UIAbilityContext; const permissions [ ohos.permission.LOCATION, ohos.permission.APPROXIMATELY_LOCATION ]; // 检查并申请权限 this.hasPermission await PermissionManager.getInstance() .checkAndRequestPermissions(permissions, context); } async getLocation() { if (!this.hasPermission) { // 再次尝试申请 const context this.getUIContext().getHostContext() as common.UIAbilityContext; this.hasPermission await PermissionManager.getInstance() .requestPermissions([ohos.permission.LOCATION], context); if (!this.hasPermission) { // 引导用户去设置 this.showSettingsDialog(); return; } } // 获取位置逻辑 this.locationText 北京市朝阳区; } showSettingsDialog() { AlertDialog.show({ message: 需要位置权限才能使用此功能请在设置中开启, primaryButton: { value: 去设置, action: () { // 跳转到应用设置页 } }, secondaryButton: { value: 取消 } }); } build() { Column() { Text(this.locationText) .fontSize(16) .margin(20) Button(获取当前位置) .enabled(this.hasPermission) .onClick(() this.getLocation()) if (!this.hasPermission) { Text(需要位置权限才能使用此功能) .fontColor(#FF0000) .fontSize(14) .margin(10) } } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }

相关文章:

鸿蒙中 应用的权限:申请授权(三)

本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新 鸿蒙应用开发中,当应用需要访问用户的隐私信息或使用系统能力时(如获取位置、使用相机、访问日历等),必须向用户申请授…...

私有知识库问答合规失效真相:当Dify RAG遇上《金融消费者权益保护实施办法》,这2类元数据缺失=自动违规

第一章:私有知识库问答合规失效真相:当Dify RAG遇上《金融消费者权益保护实施办法》,这2类元数据缺失自动违规在金融行业部署基于 Dify 的 RAG(检索增强生成)系统时,仅保障答案准确性和响应速度远不足以满足…...

环境变量解密:从基础概念到云原生实践

1. 环境变量基础:从图书馆到代码世界 第一次听说环境变量时,我正坐在大学图书馆里啃着C语言教材。管理员突然广播:"考试周期间,每人限借3本书,借期缩短为15天。"看着同学们手忙脚乱地归还超额书籍&#xff0…...

遗传算法实战:从编码到优化的全流程解析

1. 初识遗传算法:从“适者生存”到代码实现 如果你玩过《文明》这类策略游戏,肯定对“迭代”和“进化”不陌生。你开局只有几个农民,通过不断探索、发展科技、调整策略,最终建立起强大的帝国。遗传算法的核心思想,和这…...

零基础玩转LobeChat:一键部署开源聊天机器人,支持语音和多模态

零基础玩转LobeChat:一键部署开源聊天机器人,支持语音和多模态 想不想拥有一个完全属于自己的智能聊天助手?它界面漂亮,反应迅速,不仅能像ChatGPT一样和你聊天,还能听懂你的语音,看懂你上传的图…...

文墨共鸣模型深度解析:卷积神经网络在文本特征提取中的角色

文墨共鸣模型深度解析:卷积神经网络在文本特征提取中的角色 最近在和一些朋友交流时,发现一个挺有意思的现象。大家一提到像文墨共鸣这类基于Transformer架构的大模型,注意力机制(Self-Attention)总是当之无愧的明星。…...

从勒索病毒到流量分析:一次完整的Solar应急响应实战复盘

1. 勒索病毒入侵的初始迹象 那天早上刚到公司,财务部同事就火急火燎地跑过来:"所有文件都打不开了!"我赶到现场一看,电脑卡得连任务管理器都要等十几秒才能弹出来。仔细检查发现CPU被一个陌生进程占满,所有文…...

智慧校园管理系统平台选型指南:如何评估未来 3-5 年扩展性

✅作者简介:合肥自友科技 📌核心产品:智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…...

Message Pack 协议深度解析与实战指南

1. Message Pack协议的前世今生 第一次接触Message Pack是在2013年做游戏服务器开发时。当时我们的实时对战游戏遇到了严重的网络带宽瓶颈,JSON序列化后的玩家状态数据太大,导致同步延迟明显。尝试了各种优化方案后,同事推荐了这个来自日本的…...

Colab免费GPU+Unsloth:快速微调大模型,打造专属智能助手

Colab免费GPUUnsloth:快速微调大模型,打造专属智能助手 1. 引言 1.1 为什么选择Colab和Unsloth? 大型语言模型(LLM)如Llama、Mistral等在通用任务上表现出色,但要让它们适应特定领域(如医疗问答、法律咨询等),就需要…...

低代码≠低安全,Dify集成必须做的4项合规检查,错过将面临等保2.0一票否决!

第一章:低代码≠低安全:Dify集成中的认知误区与合规警醒在企业级AI应用快速落地的背景下,Dify作为主流低代码LLM应用开发平台,常被误读为“安全责任弱化”的代名词。事实上,低代码仅降低开发门槛,绝不稀释安…...

企业安全必看:如何检测和修复深信服NGAF防火墙文件读取漏洞

企业级防火墙安全实战:NGAF文件读取漏洞深度防御指南 在数字化转型浪潮中,防火墙作为企业网络安全的第一道防线,其安全性直接关系到核心业务系统的稳定运行。近期曝光的某主流防火墙文件读取漏洞,再次为企业安全团队敲响警钟——即…...

Granite-4.0-H-350M部署实战:Windows 11系统环境配置

Granite-4.0-H-350M部署实战:Windows 11系统环境配置 1. 为什么选择Granite-4.0-H-350M在Windows上运行 最近试用Granite-4.0-H-350M时,最直观的感受是它在普通Windows笔记本上跑得特别顺。不像一些大模型需要高端显卡和大量内存,这个350M参…...

解决OpenWRT在M93p上的Intel I217-LM网卡硬件挂起问题:驱动更新与offload关闭实战

1. 问题现象与初步诊断 最近在Lenovo M93p上部署OpenWRT时,遇到了一个让人头疼的问题——系统日志中频繁出现"Detected Hardware Unit Hang"的错误提示。这台设备使用的是Intel I217-LM网卡,在负载较高时会出现网络连接中断的情况。通过ethtoo…...

C++ 核心概念全景解析+实战思维导图

1. C知识体系全景图 第一次接触C时,我被它庞大的知识体系震撼到了。记得当时看着厚厚的《C Primer》,感觉像面对一座高不可攀的山峰。但后来我发现,只要掌握了核心脉络,C其实并没有想象中那么可怕。 C的知识体系可以形象地比作一座…...

【图文讲解】Excel如何筛选重复项?四种简单有效的筛选重复项方法

一、问题背景在用Excel整理数据时,碰到重复数据内容不仅让表格看着乱糟糟的,还容易搞乱数据统计、核算的结果,像学生成绩表里重复的分数、员工信息表里重复的姓名,都得筛选出来处理。其实筛选重复项一点都不难,掌握几个…...

Clawdbot汉化版快速部署:Docker Compose一键启停+多实例隔离(微信/WhatsApp分环境)

Clawdbot汉化版快速部署:Docker Compose一键启停多实例隔离(微信/WhatsApp分环境) 1. 项目概述 Clawdbot汉化版是一个可以在微信、WhatsApp、Telegram等社交平台中使用的智能对话助手。它让你能够在熟悉的聊天软件中直接与AI对话&#xff0…...

华为路由器实战:OSPF NSSA区域配置避坑指南(附完整拓扑实验)

华为路由器实战:OSPF NSSA区域配置避坑指南(附完整拓扑实验) 在大型企业或服务提供商网络的设计与运维中,OSPF作为核心的IGP协议,其区域化设计是控制路由信息泛洪、优化设备性能的关键。对于许多从理论走向实践的工程师…...

RK3588路由器实战:如何用netplan+hostapd搭建稳定无线AP(避坑指南)

RK3588路由器实战:从零构建高性能无线AP的完整指南 在智能家居和物联网设备爆发的时代,拥有一台可完全自定义的路由器变得越来越重要。RK3588作为一款高性能ARM处理器,凭借其出色的网络处理能力和低功耗特性,成为DIY路由器的理想选…...

RustFS性能调优实战:5个生产环境必改参数让你的存储集群起飞

RustFS性能调优实战:5个生产环境必改参数让你的存储集群起飞 当你的存储集群在业务高峰期出现响应延迟飙升、吞吐量骤降时,作为运维负责人的你是否经历过这样的噩梦?去年双十一大促前,某电商平台就遭遇了这样的危机——他们的Rust…...

从零到一:在云服务器上构建你的专属Audiobookshelf有声图书馆

1. 为什么你需要一个专属的有声图书馆? 不知道你有没有这样的困扰:手机里存了几十部有声书和播客,每次想听的时候都要翻半天;不同平台的会员换来换去,收藏列表散落在五六个APP里;最头疼的是有些小众资源&am…...

Xinference惊艳效果:同一WebUI界面切换Qwen3-32B、GLM4-9B、Phi-3-mini对比演示

Xinference惊艳效果:同一WebUI界面切换Qwen3-32B、GLM4-9B、Phi-3-mini对比演示 注意:本文所有演示基于Xinference v1.17.1版本,不同版本可能存在细微差异 1. 为什么需要多模型切换能力? 在日常的AI应用开发中,我们经…...

毕业设计Java实战:从零构建高内聚低耦合的Spring Boot项目架构

作为一名即将毕业的计算机专业学生,我深知完成一个高质量的毕业设计是多么重要,它不仅关乎最后的答辩成绩,更是对自己四年学习成果的一次综合检验。然而,现实往往是:项目结构混乱得像一团乱麻,业务逻辑东一…...

在校学生如何利用教育邮箱快速申请GEE账号

1. 为什么在校学生一定要抓住GEE这个“神器”? 如果你是在校学生,尤其是地理、环境、生态、遥感、计算机这些专业的朋友,还没听说过或者没用过GEE,那真的有点亏了。GEE,全称Google Earth Engine,你可以把它…...

雪女-斗罗大陆-造相Z-Turbo多风格生成效果展:从正经史传到戏说改编

雪女-斗罗大陆-造相Z-Turbo多风格生成效果展:从正经史传到戏说改编 最近在折腾一个挺有意思的AI模型,叫“雪女-斗罗大陆-造相Z-Turbo”。名字有点长,但功能很直接:它能根据你的要求,把一段故事用完全不同的风格重写出…...

S7-200SMART PLC与MCGS触摸屏组网实战:从单台到多台控制的升级指南

S7-200SMART PLC与MCGS触摸屏组网实战:从单台到多台控制的升级指南 在工业自动化领域,单台PLC与触摸屏的通信控制已经不能满足复杂生产场景的需求。当产线扩展、设备增加时,如何实现多台S7-200SMART PLC与MCGS触摸屏的高效组网,成…...

2026大专商务数据分析与应用毕业后可以自主创业吗?

数据时代,手握分析能力手握商业世界的方向盘。最近收到不少同学的提问:“老师,我学商务数据分析与应用专业的,大专学历,2026年毕业,将来创业有可能吗?”我的回答是:不仅能&#xff0…...

bug2026.03.15

必做工作开发需要的数据库bug1dashboard 打不开。解决:解决成功...

2026高职大数据技术毕业生就业方向主要有哪些?

数据时代,每一比特都蕴藏着机遇。你准备好了吗?在大数据技术专业的课堂上,总会有学生问我:“老师,我们毕业了到底能做什么?”这问题背后,既有对未来的期待,也有对未知的焦虑。如果你…...

《全球芯片图鉴》:全球最值得了解的芯片厂商清单

STM32、ESP32、骁龙、Core、Xeon、GPU、FPGA……但很多时候,我们只是在“使用”这些芯片,很少真正了解:这些芯片来自哪家公司这些公司擅长做什么类型的芯片不同芯片之间的定位和应用领域为了系统地梳理这些信息,我开始整理这个系列…...