news 2026/8/25 19:07:07

HarmonyOS社交通讯应用开发 22 :权限申请机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HarmonyOS社交通讯应用开发 22 :权限申请机制

权限申请机制

引言

发布页能定位、能读剪贴板、能跨设备传文件,背后全靠权限支撑。HarmonyOS 的权限体系分为两类:

  • system_grant(系统授权):安装时静默授予,用户无感知,如访问网络;
  • user_grant(用户授权):运行时弹窗询问,用户可拒绝,如精确定位、读相册。

开发者需要做两件事:一是在module.json5声明权限(含授权理由、使用场景),二是在代码里请求user_grant 权限(requestPermissionsFromUser)。两件事缺一不可——只声明不请求,用户永远见不到授权弹窗;只请求不声明,直接报错。

本篇以发布页为例,把"声明层 + 请求层 + 消费层"三层权限机制讲透:CommonConstants里的权限数组、BottomToolbar.requestPermissions的运行时请求、以及module.json5中 6 个权限的完整声明。

知识点讲解

abilityAccessCtrl 与 AtManager

abilityAccessCtrl@kit.AbilityKit)是权限管理模块,核心入口是abilityAccessCtrl.createAtManager()返回的 AtManager(应用权限管理器)。最常用的方法是:

atManager.requestPermissionsFromUser(context,permissions)
  • context:UIAbilityContext,用于定位发起弹窗的页面上下文;
  • permissionsArray<Permissions>,要申请的权限名列表。

返回 Promise,授权完成(无论同意还是拒绝)后 resolve,可进一步用requestPermissionsFromUser的返回值检查授权结果。注意:该方法只能申请 user_grant 权限,且这些权限必须已在module.json5requestPermissions里声明。

module.json5 权限声明

module.json5requestPermissions数组每项包含:

  • name:权限名,如ohos.permission.LOCATION
  • reason:申请理由(资源引用$string:xxx),授权弹窗中展示给用户看;
  • usedScene:使用场景,abilities指明在哪个 Ability 使用,wheninuse(前台使用)或always(前后台均使用)。

系统对 user_grant 权限强制要求填写reasonusedScene,否则审核或安装阶段可能被拒。

定位权限的分级与联动

HarmonyOS 的定位权限比较特殊,分三级:

  • ohos.permission.APPROXIMATELY_LOCATION:模糊定位(精度约百米级);
  • ohos.permission.LOCATION:精确定位;
  • ohos.permission.LOCATION_IN_BACKGROUND:后台定位。

系统要求:申请LOCATION必须先申请APPROXIMATELY_LOCATION(捆绑授权);LOCATION_IN_BACKGROUND只在前台两个权限都授予后才可单独申请,且usedScene.when需为inuse。本项目在module.json5中三个都声明了,但运行时只弹窗申请前两个——后台定位权限在实际使用后台场景时才需申请(示例工程未触发)。

剪贴板与媒体库权限的"双轨"

ohos.permission.READ_PASTEBOARD(读剪贴板)和ohos.permission.READ_IMAGEVIDEO(读公共目录图片视频)也是 user_grant 权限。但工程代码巧妙地"绕开"了它们:图库选择走系统PhotoViewPicker(免权限)、粘贴走PasteButton安全控件(系统代读剪贴板)。权限仍然声明在module.json5里,属于"能力声明 + 备而不用"——保证将来用代码级接口(如getPasteDataTest直接读剪贴板)时不缺权限。

结合本项目源码分析

权限数组:CommonConstants.REQUEST_PERMISSIONS

文件路径:entry/src/main/ets/constants/CommonConstants.ets

import{Permissions}from'@kit.AbilityKit';/* * The request permission. */staticreadonlyREQUEST_PERMISSIONS:Array<Permissions> = ['ohos.permission.APPROXIMATELY_LOCATION',// 模糊定位'ohos.permission.LOCATION'// 精确定位];

把权限名收敛到常量类,类型用Permissions联合类型约束,编译期就能发现拼写错误;所有申请权限的地方引用CommonConstants.REQUEST_PERMISSIONS,改权限只需动一处。

运行时请求:BottomToolbar.requestPermissions

文件路径:entry/src/main/ets/view/contentEditor/BottomToolbar.ets

requestPermissions():void{// 创建应用权限管理器letatManager = abilityAccessCtrl.createAtManager();try{// 弹窗请求定位权限;授权成功后开启定位监听atManager.requestPermissionsFromUser(this.context,CommonConstants.REQUEST_PERMISSIONS).then(() =>{LocationUtil.geolocationOn(this.getGeolocationOn);// 成功(含拒绝)都走到这里}).catch((err: BusinessError) =>{ hilog.info(DOMAIN,TAG,FORMAT,`RequestPermissionsFromUser failed. Cause code:${err.code}, message:${err.message}`); }); }catch(err) { hilog.error(DOMAIN,TAG,FORMAT,'requestPermissionsFromUser err'+JSON.stringify(err)); } }

调用时机在aboutToAppear

aboutToAppear():void{this.requestPermissions(); }

这里的this.contextBottomToolbar在组件声明处通过this.getUIContext().getHostContext()拿到的 UIAbilityContext——同一个 context 贯穿了本模块的权限申请、图库选择(getPhotoAccessHelper(context))与分布式文件写入(writeDistributedFile(context, ...)),是各类系统服务共用的"身份凭证",声明一次、全组件复用。

三点值得注意:

  1. 时机前置:进入发布页立刻申请,授权弹窗尽早出现,用户还没开始操作就有心理预期;拒绝后应用仍能正常编辑内容,只是位置功能不可用——这是"权限失败要优雅降级"的示范。
  2. Promise 语义.then()在用户做出选择后触发,无论同意还是拒绝都会执行。示例工程未校验授权结果就开启定位——geolocationOn内部有 try/catch 兜底,即便未授权,监听注册失败也只记日志,不会崩溃。真实产品应检查返回值AuthResult判断授权结果再决定后续流程。
  3. 双重异常保护:外层 try/catch 捕获同步异常(如 context 无效),.catch捕获异步异常,错误都进 hilog 便于排查。

声明层:module.json5 的 6 个权限

文件路径:entry/src/main/module.json5

"requestPermissions": [ {"name":"ohos.permission.APPROXIMATELY_LOCATION",//模糊定位"reason":"$string:permission_approximately_location",//弹窗展示的申请理由"usedScene": {"abilities": ["EntryAbility"],"when":"inuse"//前台使用时 } }, {"name":"ohos.permission.LOCATION",//精确定位"reason":"$string:permission_location","usedScene": {"abilities": ["EntryAbility"],"when":"inuse"} }, {"name":"ohos.permission.LOCATION_IN_BACKGROUND",//后台定位"reason":"$string:permission_location_in_background","usedScene": {"abilities": ["EntryAbility"],"when":"inuse"} }, {"name":"ohos.permission.READ_PASTEBOARD",//读剪贴板"reason":"$string:permission_read_pasteboard","usedScene": {"abilities": ["EntryAbility"],"when":"inuse"} }, {"name":"ohos.permission.READ_IMAGEVIDEO",//读公共目录图片视频"reason":"$string:permission_read_imagevideo","usedScene": {"abilities": ["EntryAbility"],"when":"inuse"} }, {"name":"ohos.permission.DISTRIBUTED_DATASYNC",//分布式数据同步"reason":"$string:permission_distributed_datasync","usedScene": {"abilities": ["EntryAbility"],"when":"inuse"} } ]

6 个权限与理由资源的对应关系(resources/base/element/string.json中均有文案):

权限类型用途理由文案要点
APPROXIMATELY_LOCATIONuser_grant模糊定位"obtain fuzzy device location information"
LOCATIONuser_grant精确定位"obtain device location information"
LOCATION_IN_BACKGROUNDuser_grant后台定位"obtain device location information while running in the background"
READ_PASTEBOARDuser_grant读剪贴板"read the clipboard"
READ_IMAGEVIDEOuser_grant读公共图片视频"reading of image or video files in the user's public directory"
DISTRIBUTED_DATASYNCuser_grant跨设备数据同步"allow data exchange between different devices"

DISTRIBUTED_DATASYNC是分布式能力的"门禁":接续(Continue)、分布式文件同步都依赖它,未授权时跨设备功能不可用。它的授权同样走requestPermissionsFromUser运行时弹窗(本项目在主流程中未主动申请,由系统在需要时提示,属示例简化处理)。

理由文案:从声明到弹窗

reason字段指向的资源文案,最终会原样展示在授权弹窗里,是用户判断"要不要给权限"的重要依据。项目在resources/base/element/string.json中为每个权限准备了独立的理由文案,例如定位权限:

{"name":"permission_location","value":"When loading a list of location information, Allows applications to obtain device location information"}

文案采用"场景 + 能力"的结构:先说什么时候用(加载位置信息列表时),再说用到什么(获取设备位置信息),让用户对权限用途一目了然。同时zh_CNen_US目录下各有对应的翻译版本,系统按应用语言自动切换——权限理由的多语言维护,靠的是资源文件的目录约定,代码里零逻辑,这也是工程把reason写成$string:xxx引用而不是硬编码字符串的原因。

这里还藏着一个"声明与使用对应"的细节:usedScene.abilities填的是EntryAbilitywheninuseinuse表示"应用在前台运行时使用",这是定位、剪贴板这类敏感权限的推荐配置;若某个权限确实需要后台使用(如后台持续定位),才考虑always并配合LOCATION_IN_BACKGROUND单独申请。项目把六项权限的when统一设为inuse,与"仅在发布页使用"的实际情况一致,也符合最小授权原则——声明的内容与代码的实际使用范围一一对应,审计时一目了然。

三层机制如何协同

把发布页的权限体系串成一张图:

声明层module.json5 requestPermissions(6个权限 + reason + usedScene) ↓ 安装时校验(user_grant 必须带 reason/usedScene) 请求层 CommonConstants.REQUEST_PERMISSIONS(运行时申请的精确定位+模糊定位) ↓ requestPermissionsFromUser 弹窗 用户层 同意 → geolocationOn 开启定位 → 位置功能可用 拒绝 → 仅 hilog 记录 → 编辑功能照常,位置列表保留默认示例

声明 ≠ 请求:6 个权限声明了,但运行时只主动申请 2 个;其余权限要么走系统选择器/安全控件规避(图库、剪贴板),要么在功能真正触发时由系统引导授权(分布式)。这是"最小权限原则"的实践:能绕开的敏感权限就绕开,绕不开的才申请

小结

权限申请机制是发布页一切"敏感能力"的起点,本项目的做法可以总结为四句话:

  1. 声明在 module.json5:6 个权限全部声明,user_grant 权限补齐reasonusedScene,理由文案走资源文件便于多语言;
  2. 请求在代码层abilityAccessCtrl.createAtManager().requestPermissionsFromUser()运行时弹窗,授权成功即开启定位监听;
  3. 常量统一管理CommonConstants.REQUEST_PERMISSIONS集中定义权限数组,一处改动全局生效;
  4. 能规避就规避:图库选图走PhotoViewPicker、粘贴走PasteButton安全控件,把敏感权限的使用面压到最小。

至此,模块三"内容发布模块"的 9 篇文章全部完成。从发布页骨架(14)、焦点与键盘(15),到本地图库(16)、跨设备拉取(17)、AddMedia 详解(18)、文本编辑(19)、底部工具栏(20)、定位与逆地理编码(21)、权限机制(22),一条完整的发布链路已经被逐层拆解。下一篇开始,我们将进入模块四,探索"分布式数据与文件"——看看发布的内容是如何跨越设备无缝接续的。

(本文引用源码:entry/src/main/module.json5entry/src/main/ets/constants/CommonConstants.etsentry/src/main/ets/view/contentEditor/BottomToolbar.etsentry/src/main/ets/utils/LocationUtil.ets

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/25 18:51:35

Unity 2023 RPG游戏开发:从零搭建可交互的对话、任务与背包系统

1. 从零到一&#xff1a;一个完整RPG游戏的核心骨架是什么&#xff1f;如果你刚接触Unity&#xff0c;或者想从零开始做一个能玩、能分享的RPG游戏&#xff0c;最怕的不是代码有多难&#xff0c;而是不知道从哪里下手。网上教程要么太散&#xff0c;要么太深&#xff0c;做完一…

作者头像 李华
网站建设 2026/8/25 18:48:29

东华大学考研复试机试:动态规划、图论与字符串处理实战

1. 项目背景与核心价值作为一名计算机专业考研过来人&#xff0c;我深知东华大学复试机试环节的重要性。OJ&#xff08;Online Judge&#xff09;在线编程平台是检验考生算法能力和编码熟练度的关键战场&#xff0c;而"每日3题打卡"正是我去年备战期间总结出的高效训…

作者头像 李华
网站建设 2026/8/25 18:46:55

KeySteer:基于Windows原生OCR的全局键盘导航工具部署与实战指南

这次我们来看一个能让你用键盘“点击”屏幕上任意文字的工具——KeySteer。它不是一个传统的OCR软件&#xff0c;而是一个用Rust编写的、基于Windows原生OCR API的全局键盘导航工具。简单来说&#xff0c;它能把屏幕上任何区域的文字识别出来&#xff0c;然后你只需要按几个键&…

作者头像 李华
网站建设 2026/8/25 18:46:46

动手实测 Defuddle:拆解 Obsidian 创始人的网页内容提取引擎

动手实测 Defuddle&#xff1a;拆解 Obsidian 创始人的网页内容提取引擎本文所有内容均基于对 GitHub 源码的阅读和实际命令行测试&#xff0c;无任何厂家供稿或转载。从一次需求说起 上周在做一个知识库抓取工具时&#xff0c;需要把网页正文提取出来转成 Markdown。用了 Mozi…

作者头像 李华
网站建设 2026/8/25 18:40:59

AI Agent驱动开发实战:基于Cursor Origin的智能代码托管与自动化工作流

如果你最近关注AI编程工具&#xff0c;可能会发现一个现象&#xff1a;很多开发者开始讨论“AI Agent”和“代码托管平台”的结合。这背后其实是一个关键趋势&#xff1a; AI正在从“代码补全助手”向“自主执行任务的智能体&#xff08;Agent&#xff09;”演进&#xff0c;而…

作者头像 李华
网站建设 2026/8/25 18:40:28

电商和本地服务先别急,但GEO的埋伏已经开始了

# 电商与本地服务的 GEO 埋伏&#xff1a;不抢首发&#xff0c;但要做好结构化准备 电商与本地服务的搜索场景以「商品/商家 位置」为主&#xff0c;GEO 入口目前在通用 AI 引擎中渗透还不够&#xff0c;但趋势已经明确。本文给出低投入埋伏、待入口成熟的策略。一、为什么现在…

作者头像 李华