OpenHarmony 权限统一封装 PermissionUtil(动态权限申请全套方案 API23+)
摘要鸿蒙将权限分为安装时静态权限与运行时动态敏感权限相机、相册、文件、通知、位置等都必须动态申请原生权限 API 重复代码多、缺少永久拒绝跳转设置页逻辑、无统一弹窗提示、未做权限状态判断封装。本文基于ohos.accessToken封装全局权限工具类整合相机、相册、存储、通知、定位全套常用权限申请逻辑包含权限已授予 / 临时拒绝 / 永久拒绝三种状态分支处理搭配弹窗引导用户开启权限适配页面拍照、上传图片、本地文件读写、消息通知等业务场景。API23 重构 accessToken 权限校验、权限请求回调、应用设置页跳转接口修复多权限并发申请错乱、永久拒绝无引导、权限状态判断失效、页面销毁权限弹窗残留等问题。关键词OpenHarmonyArkTSAPI23accessToken动态权限Permission权限申请跳转应用设置页一、引言1.1 动态权限开发痛点每次调用相机 / 相册都要重复写权限判断、申请逻辑大量冗余代码用户选择永久拒绝权限后再次申请不会弹出授权框缺少跳转系统设置引导多权限同时申请存储 相机并发回调错乱无统一弹窗提示告知用户该功能需要对应权限页面销毁后权限申请回调执行页面变量报错无法统一封装权限授予 / 拒绝回调业务页面重复写分支逻辑。1.2 动态权限分类高频业务表格权限名称用途ohos.permission.CAMERA相机拍照ohos.permission.READ_MEDIA_IMAGES读取相册图片ohos.permission.WRITE_MEDIA保存图片到相册ohos.permission.NOTIFICATION_AGENT系统通知推送ohos.permission.READ_FOLDER沙盒外部文件读写ohos.permission.LOCATION定位获取坐标API23 accessToken 核心升级标准化checkAccessTokenSync同步校验权限状态简化异步判断权限请求结果细分三种状态已授权、临时拒绝、永久拒绝新增统一跳转应用权限设置接口无需拼接 want 参数多权限批量申请优化回调不会丢失单权限结果页面销毁自动终止未完成的权限申请杜绝内存泄漏。二、权限工具完整封装 utils/permission_util.etsetsimport accessToken from ohos.accessToken import common from ohos.app.ability.common import abilityAccessCtrl from ohos.abilityAccessCtrl import promptAction from ohos.promptAction import Want from ohos.app.ability.Want import UIAbility from ohos.app.ability.UIAbility import DialogUtil from ./dialog_util // 全局常用动态权限常量 export const PERMISSION { CAMERA: ohos.permission.CAMERA, READ_IMAGE: ohos.permission.READ_MEDIA_IMAGES, WRITE_MEDIA: ohos.permission.WRITE_MEDIA, NOTIFICATION: ohos.permission.NOTIFICATION_AGENT, LOCATION: ohos.permission.LOCATION } // 权限申请回调类型定义 export type PermissionCallback (granted: boolean) void class PermissionUtil { private static instance: PermissionUtil private ctx: common.UIAbilityContext | null null private atManager: abilityAccessCtrl.AbilityAccessCtrl | null null static getInstance() { if (!PermissionUtil.instance) { PermissionUtil.instance new PermissionUtil() } return PermissionUtil.instance } // 注入页面/Ability上下文 setContext(context: common.UIAbilityContext) { this.ctx context this.atManager abilityAccessCtrl.createAtManager() } // 同步校验单个权限是否已授予 checkPermission(permission: string): boolean { if (!this.ctx) return false const tokenId this.ctx.applicationInfo.accessTokenId const status accessToken.checkAccessTokenSync(tokenId, permission) return status accessToken.GrantStatus.PERMISSION_GRANTED } // 跳转系统应用权限设置页面 jumpAppSetting() { if (!this.ctx) return const want: Want { bundleName: com.ohos.settings, abilityName: com.ohos.settings.MainAbility, uri: settings://app/${this.ctx.bundleName}/permissions } this.ctx.startAbility(want) } // 申请单个动态权限 async requestPermission(permission: string, desc: string, callback: PermissionCallback) { if (!this.atManager || !this.ctx) { promptAction.showToast({ message: 上下文未初始化 }) return callback(false) } // 已授权直接执行回调 if (this.checkPermission(permission)) { return callback(true) } // 发起权限申请 const result await this.atManager.requestPermissionsFromUser(this.ctx, [permission]) const grantStatus result.authResults[0] // 1. 用户同意授权 if (grantStatus abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { return callback(true) } // 2. 永久拒绝弹窗引导跳转设置 if (result.deniedPermanent) { DialogUtil.confirm({ title: 权限提示, content: ${desc}需要对应权限才能正常使用请前往设置开启 }, () { this.jumpAppSetting() callback(false) }) } else { // 临时拒绝提示功能无法使用 promptAction.showToast({ message: 未授予权限功能无法使用 }) callback(false) } } // 批量申请多个权限相机相册 async requestMultiPermission(permissions: string[], desc: string, callback: PermissionCallback) { if (!this.atManager || !this.ctx) return callback(false) // 过滤未授权权限 const needReqList permissions.filter(p !this.checkPermission(p)) if (needReqList.length 0) return callback(true) const result await this.atManager.requestPermissionsFromUser(this.ctx, needReqList) // 判断全部权限是否授予 const allGranted result.authResults.every( s s abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ) if (allGranted) return callback(true) // 存在永久拒绝权限引导跳转设置 if (result.deniedPermanent) { DialogUtil.confirm({ title: 权限缺失, content: ${desc}需要相关权限请前往系统设置手动开启 }, () this.jumpAppSetting()) } else { promptAction.showToast({ message: 缺少必要权限功能不可用 }) } callback(false) } // 快捷申请相机权限 reqCamera(cb: PermissionCallback) { this.requestPermission(PERMISSION.CAMERA, 拍照功能, cb) } // 快捷申请相册读写权限 reqImage(cb: PermissionCallback) { this.requestMultiPermission([PERMISSION.READ_IMAGE, PERMISSION.WRITE_MEDIA], 相册选择/保存图片, cb) } // 快捷申请通知权限 reqNotify(cb: PermissionCallback) { this.requestPermission(PERMISSION.NOTIFICATION, 消息通知推送, cb) } // 快捷申请定位权限 reqLocation(cb: PermissionCallback) { this.requestPermission(PERMISSION.LOCATION, 获取位置信息, cb) } } export default PermissionUtil.getInstance()三、业务页面实战调用3.1 拍照上传页面相机权限etsimport PermissionUtil, { PERMISSION } from ../utils/permission_util import CameraUtil from ../utils/camera_util Entry Component struct CameraPage { async aboutToAppear() { PermissionUtil.setContext(getContext(this)) } openCamera() { PermissionUtil.reqCamera((granted: boolean) { if (granted) { // 权限通过打开相机 CameraUtil.startCapture() } }) } build() { Column() { Button(打开相机拍照) .width(300) .height(48) .onClick(() this.openCamera()) } .width(100%) .height(100%) .justifyContent(Center) } }3.2 头像选择页面相册批量权限etsimport PermissionUtil from ../utils/permission_util import ImagePickerUtil from ../utils/image_picker_util // 打开相册选择图片 function pickImage() { PermissionUtil.reqImage((granted) { if (granted) { ImagePickerUtil.openAlbum() } }) }3.3 通知设置页申请通知权限etsButton(开启消息通知) .onClick(() { PermissionUtil.reqNotify((granted) { if (granted) { NotifyUtil.sendBasicNotify(1001, 通知已开启, 您将收到应用资讯推送) } }) })3.4 定位功能页面etsfunction getLocation() { PermissionUtil.reqLocation(async (granted) { if (granted) { const loc await LocationUtil.getNowLocation() console.info(当前坐标, loc) } }) }四、module.json5 权限静态声明配置动态权限必须在 module.json5 提前声明否则申请直接失败jsonrequestPermissions: [ { name: ohos.permission.CAMERA, reason: 用于拍照上传图片 }, { name: ohos.permission.READ_MEDIA_IMAGES, reason: 读取相册图片 }, { name: ohos.permission.WRITE_MEDIA, reason: 保存图片至相册 }, { name: ohos.permission.NOTIFICATION_AGENT, reason: 推送系统消息通知 }, { name: ohos.permission.LOCATION, reason: 获取地理位置信息 } ]五、API23 权限开发编码规范5.1 上下文规范页面aboutToAppear注入页面上下文PermissionUtil.setContext(getContext(this))EntryAbility onCreate 全局初始化一次全局页面可复用。5.2 权限申请时机规范用户点击功能按钮时再申请禁止页面加载自动弹窗索要权限高危功能相机、相册操作前校验权限不提前静默申请。5.3 永久拒绝分支规范用户永久拒绝权限后弹出确认弹窗引导跳转系统设置弹窗说明权限用途提升用户开启概率。5.4 批量权限规范相册读取 保存配套批量申请避免分两次弹窗打扰用户无关权限禁止批量合并申请。5.5 页面生命周期规范页面销毁无需手动取消权限申请API23 底层自动终止未完成请求权限回调内操作页面变量增加判空防止页面已销毁。六、高频报错问题解决方案问题 1调用 requestPermissionsFromUser 无授权弹窗 解决module.json5 声明对应 permission 权限名称名称完全匹配。问题 2用户勾选永久拒绝后再次申请无弹窗 解决工具内判断 deniedPermanent弹窗引导跳转应用设置页手动开启。问题 3批量申请相册权限只授予其中一个 解决使用 requestMultiPermission 批量接口同时校验读写两张媒体权限。问题 4提示上下文为空权限校验失败 解决页面 aboutToAppear 调用 setContext 注入当前页面 context。问题 5升级 API23 旧版权限代码编译报错 解决替换废弃 requestPermissions 异步接口使用 atManager 标准 API同步校验改用 checkAccessTokenSync。问题 6跳转设置页面找不到应用权限 解决want 内 bundleName 使用当前应用真实包名工具自动读取上下文 bundleName 无需手写。七、总结PermissionUtil 统一封装鸿蒙动态权限全套逻辑整合相机、相册、通知、定位高频权限快捷方法自动区分已授权 / 临时拒绝 / 永久拒绝三种状态永久拒绝场景弹窗引导跳转系统设置解决原生权限代码冗余、无引导、多权限并发错乱等工程化痛点。 完全兼容前文相机、相册、通知、上传等业务工具是所有涉及媒体、通知、定位功能项目必备底层工具适配 API23 与 HarmonyOS NEXT 课程设计、毕设完整工程架构。

相关新闻

Chat2DB 实战:从 ChatGPT 写 SQL 到专业 AI 数据库工具

Chat2DB 实战:从 ChatGPT 写 SQL 到专业 AI 数据库工具

关键词:Chat2DB、数据库管理工具、智能问数、AI SQL、Text2SQL 很多开发者第一次体验 AI 写 SQL,通常是从 ChatGPT 这类通用大模型开始的。输入一句自然语言需求,模型很快给出 SQL 示例,看起来很高效。 但在真实团队里&#xff0…

2026/7/17 0:50:05阅读更多 →
【机器学习】(19)—— 数据特性与标签

【机器学习】(19)—— 数据特性与标签

数据特性与标签:划分前先摸清 文章目录数据特性与标签:划分前先摸清1. 为什么「先划分」还不够2. 数据特性四问2.1 类型:是什么数据2.2 数量:样本够不够2.3 数据质量2.4 可信度3. 不可靠数据从哪来4. 不完整样本:删除还…

2026/7/17 0:45:05阅读更多 →
商用 Kiosk 自助终端开发全流程:企业锁机应用资质到上线完整记录

商用 Kiosk 自助终端开发全流程:企业锁机应用资质到上线完整记录

一、前言:Kiosk商用锁机能力定位与落地门槛 鸿蒙7 API26 kioskManager 收敛至kit.AbilityKit,面向政务一体机、门店收银自助机、景区取票终端、广告触控一体机等企业无人值守商用场景,核心能力是设备开机后锁定单一应用,屏蔽桌面、…

2026/7/17 0:45:05阅读更多 →
AI Agent技能供应链安全:从ClawHavoc攻击看纵深防御实践

AI Agent技能供应链安全:从ClawHavoc攻击看纵深防御实践

1. 项目概述:当AI Agent的技能库成为攻击入口最近在跟进AI Agent安全研究时,一个名为“OpenClaw ClawHavoc”的供应链攻击事件引起了我的高度警觉。这不仅仅是一个孤立的安全漏洞,它像一把手术刀,精准地剖开了当前AI Agent生态&am…

2026/7/17 1:50:09阅读更多 →
MATLAB+Gurobi实现电力系统安全约束经济调度(SCED)建模与求解脚本

MATLAB+Gurobi实现电力系统安全约束经济调度(SCED)建模与求解脚本

本文还有配套的精品资源,点击获取 简介:一套开箱即用的MATLAB脚本(SCED_Gurobi.m),直接调用Gurobi求解器完成安全约束经济调度(SCED)计算。支持机组出力上下限、爬坡率限制、系统功率平衡、支…

2026/7/17 1:50:09阅读更多 →
Windows系统开机优化:原生工具提升性能

Windows系统开机优化:原生工具提升性能

1. 开机慢的真相:别被"优化"软件忽悠了每次按下电源键都要等上两三分钟才能用电脑?这种体验确实让人抓狂。但先别急着下载那些所谓的"电脑管家"类软件,它们往往才是拖慢系统的元凶。我在IT运维行业摸爬滚打十年&#xff…

2026/7/17 1:50:09阅读更多 →
终极指南:如何用FLUX.1-dev-Controlnet-Union Pro实现多模态图像控制

终极指南:如何用FLUX.1-dev-Controlnet-Union Pro实现多模态图像控制

终极指南:如何用FLUX.1-dev-Controlnet-Union Pro实现多模态图像控制 【免费下载链接】FLUX.1-dev-Controlnet-Union 项目地址: https://ai.gitcode.com/hf_mirrors/InstantX/FLUX.1-dev-Controlnet-Union 在AI图像生成领域,精确控制一直是开发者…

2026/7/17 1:50:09阅读更多 →
手机变启动盘:OTG安装电脑系统全攻略

手机变启动盘:OTG安装电脑系统全攻略

1. 为什么需要手机给电脑装系统?在维修店工作这些年,我遇到过太多客户带着无法启动的电脑来求救。最典型的就是系统崩溃后,手边没有U盘、没有光驱,甚至连第二台电脑都借不到的情况。这时候,手机这个随身设备就成了救命…

2026/7/17 1:50:09阅读更多 →
MATLAB版AES-256加密工具包:含ECB模式、PKCS#7填充与全轮函数实现

MATLAB版AES-256加密工具包:含ECB模式、PKCS#7填充与全轮函数实现

本文还有配套的精品资源,点击获取 简介:一套开箱即用的MATLAB AES-256加密解决方案,专为兼容MATLAB 2012b及以上版本设计。完整实现AES-256标准核心运算:字节替换(SubBytes/InvSubBytes)、行移位&#x…

2026/7/17 1:45:09阅读更多 →
VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异当你在VSCode中启动一个新的TypeScript项目时,第一个技术决策往往从安装方式开始。这个看似简单的选择——全局安装还是项目本地安装——实际上会深刻影响你的开发流程、团队协作和…

2026/7/16 8:28:11阅读更多 →
智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

2026/7/16 6:53:04阅读更多 →
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

2026/7/16 12:02:41阅读更多 →
VS Code 高效配置与个性化定制全攻略

VS Code 高效配置与个性化定制全攻略

1. VS Code 高效配置基础作为一款轻量级但功能强大的代码编辑器,VS Code 的默认配置已经能满足基本需求,但通过合理调整设置可以大幅提升编码效率。我使用 VS Code 已经有五年多时间,期间尝试过各种配置方案,总结出这套适合大多数…

2026/7/17 0:00:01阅读更多 →
从竞赛代码到桌面工具:让 SuperADD 与 SubspaceAD 真正跑进自己的图像

从竞赛代码到桌面工具:让 SuperADD 与 SubspaceAD 真正跑进自己的图像

在异常检测领域,很多优秀算法最初都是以研究代码的形式发布的。它们能够在固定测试集上复现实验结果,却不一定能被普通用户直接拿来测试自己的图片。尤其是最近很多算法仅提供在固定测试集的测试环境,而gradio的demo演示也不会提供。 对工程应用和在自己的图片上进行测试来…

2026/7/17 0:00:01阅读更多 →
WinRAR高效配置指南:从基础安装到高级压缩实战

WinRAR高效配置指南:从基础安装到高级压缩实战

前几天帮同事处理一个客户发来的压缩包,解压时系统自带的工具弹出一串乱码,换用 WinRAR 却顺利打开了。这种看似简单的场景,恰恰暴露了不同压缩工具在处理非标准编码、分卷压缩或加密文件时的差异。WinRAR 作为一款老牌工具,真正价…

2026/7/17 0:00:01阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/16 20:13:14阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/16 8:58:42阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/16 17:10:26阅读更多 →