uni-app x 权限申请监听 API 实战指南:uni.createRequestPermissionListener 详解
2026/9/20 19:32:34 网站建设 项目流程
  • 示例工程
  • 前端
  • 移动开发
  • 跨平台

【免费下载链接】uni-app

A cross-platform framework using Vue.js

项目地址:https://gitcode.com/gh_mirrors/un/uni-app
点击查看免费下载

本篇指南围绕 uni-app x(当前开源仓库gh_mirrors/un/uni-app)中的uni.createRequestPermissionListener()API 展开,讲解如何在 App 端全局监听系统权限申请确认框的弹出与关闭,并结合 Android 平台源码实现、uni.requestSystemPermission配套调用以及华为应用市场合规要求,给出可复制、可运行的完整示例。读完本文,你将掌握权限监听对象RequestPermissionListener的创建、onRequest/onConfirm/onComplete/stop四个方法的使用要点、底层实现原理与全局合规弹窗的落地写法。

API 概述与适用场景

uni.createRequestPermissionListener()用于创建一个监听权限申请的对象。在 app-android 平台上,无论业务代码在哪一处申请权限,只要系统权限申请确认框弹出或关闭,都会触发对应的监听事件。

该能力最典型的应用场景是合规告知:华为应用市场审核要求“APP 在调用终端权限时,应同步告知用户申请该权限的目的”。此时即可使用本 API,在app.uvue里做全局监听,在系统确认框弹出的同时,展示自定义的“申请权限目的说明”,既满足审核要求,也提升用户体验。

监听对象创建后返回RequestPermissionListener,随后可调起其onRequestonConfirmonComplete

  • 当权限申请的确认框在手机端弹出时,触发onConfirm
  • 当权限申请的确认框被用户关闭后,触发onComplete
  • 当业务代码发起系统权限申请时,触发onRequest(申请前的时机点)。

兼容性说明

| Web | Android | iOS | HarmonyOS | | :- | :- | :- | :- | | x | 4.0+ | x | x |

该 API 仅支持app-android平台(HBuilderX 4.0 及以上版本),不支持 Web、iOS、HarmonyOS。从 接口类型声明 中的@uniPlatform标注也可确认:android 平台为uniVer: "4.0+",其余平台均为x(不支持)。

返回值与 RequestPermissionListener 方法

调用uni.createRequestPermissionListener()后返回一个 RequestPermissionListener 实例,其接口定义如下:

export interface RequestPermissionListener { /** * 监听申请系统权限 * @param callback 申请系统权限回调,permissions为触发权限申请的所有权限 */ onRequest(callback: RequestPermissionListenerRequestCallback): void /** * 监听弹出系统权限授权框 * @param callback 弹出系统权限授权框回调,permissions为触发弹出权限授权框的所有权限 */ onConfirm(callback: RequestPermissionListenerConfirmCallback): void /** * 监听权限申请完成 * @param callback 权限申请完成回调,permissions为申请完成的所有权限 */ onComplete(callback: RequestPermissionListenerCompleteCallback): void /** * 取消所有监听 */ stop(): void } export type RequestPermissionListenerRequestCallback = (permissions: Array<string>) => void export type RequestPermissionListenerConfirmCallback = (permissions: Array<string>) => void export type RequestPermissionListenerCompleteCallback = (permissions: Array<string>) => void

onRequest(callback):监听申请系统权限

| 参数 | 类型 | 必填 | 描述 | | :- | :- | :-: | :- | | callback | (permissions: Array<string>) => void | 是 | 申请系统权限回调,permissions为触发权限申请的所有权限 |

当任意业务代码发起系统权限申请时触发,回调参数为本次申请涉及的全部权限字符串(如["android.permission.READ_CALENDAR"])。

onConfirm(callback):监听弹出系统权限授权框

| 参数 | 类型 | 必填 | 描述 | | :- | :- | :-: | :- | | callback | (permissions: Array<string>) => void | 是 | 弹出系统权限授权框回调,permissions为触发弹出权限授权框的所有权限 |

系统权限确认框在手机端弹出时触发。这是展示“申请权限目的”说明的最佳时机,也是满足华为应用市场审核要求的关键钩子。

onComplete(callback):监听权限申请完成

| 参数 | 类型 | 必填 | 描述 | | :- | :- | :-: | :- | | callback | (permissions: Array<string>) => void | 是 | 权限申请完成回调,permissions为申请完成的所有权限 |

权限申请确认框被用户关闭后触发,可用于隐藏全局提示、清理定时器等收尾工作。

stop():取消所有监听

无参数。调用后取消当前监听对象注册的所有回调(onRequest/onConfirm/onComplete),通常在页面卸载或应用退出时调用,避免泄漏。

源码级实现原理

仓库中的 uni-createRequestPermissionListener 插件实现 展示了该 API 在 Android 平台的底层实现。入口函数如下:

export const createRequestPermissionListener: CreateRequestPermissionListener = function (): RequestPermissionListener { return new AndroidPermissionRequestManager() }

AndroidPermissionRequestManager内部持有三个回调字段,分别对应requestCallbackconfirmCallbackcompleteCallback。以onConfirm为例:

onConfirm(callback: RequestPermissionListenerConfirmCallback) { if (this.confirmCallback == null) { this.confirmCallback = callback } else { UTSAndroid.offPermissionConfirm(this.confirmCallback!) this.confirmCallback = callback } UTSAndroid.onPermissionConfirm(this.confirmCallback!) }

可以看到,该 API 本质上是封装了 UTSAndroid 底层的权限事件总线:

  • 注册时调用UTSAndroid.onPermissionRequest/onPermissionConfirm/onPermissionComplete
  • 重复注册时先offPermissionConfirm等取消旧回调,再注册新回调,保证始终只保留最新监听;
  • stop()则依次offPermissionCompleteoffPermissionConfirmoffPermissionRequest,并把三个回调字段置为null,彻底解除监听。

从该实现可以推断:同一监听对象上,每个事件同时只会生效一个回调,重复调用onConfirm等注册方法会用新回调覆盖旧回调;而stop()是幂等的清理操作,即使未注册任何回调也可安全调用。

插件配置 config.json 中声明了"minSdkVersion": "19",即要求 Android 最低系统版本为 4.4(API 19)。

完整示例:监听日历权限申请

仓库示例页面 create-request-permission-listener.uvue 与该文档示例同步,演示了监听 + 发起申请 + 顶部提示条的完整闭环。核心逻辑如下(节选):

<script setup lang="uts"> const isPermissionAlertShow = ref(false) const timeoutId = ref(-1) const permissionListener = ref(null as RequestPermissionListener | null) onUnload(() => { permissionListener.value?.stop() permissionListener.value = null clearTimeout(timeoutId.value) }) const watchPermissionRRequest = () => { permissionListener.value = uni.createRequestPermissionListener() permissionListener.value!.onConfirm((_) => { // 注意:onConfirm 触发时机与系统弹窗存在微小时间差,示例中延迟 100ms 再展示提示条 timeoutId.value = setTimeout(() => { isPermissionAlertShow.value = true }, 100) }) permissionListener.value!.onComplete((_) => { clearTimeout(timeoutId.value) isPermissionAlertShow.value = false }) } const requestPermission = () => { // #ifdef APP-ANDROID uni.requestSystemPermission({ permissions: ["android.permission.READ_CALENDAR"], success: (res) => { console.log(res.grantedList) console.log(res.deniedList) }, fail: (err) => { uni.showToast({ title: "权限被拒绝了", position: "bottom" }) console.log(err.errCode) } }) // #endif } onReady(() => { watchPermissionRRequest() }) </script>

模板部分包含一个可滑入滑出的“权限申请说明”提示条和一个申请按钮:

<template> <!-- #ifdef APP && !VUE3-VAPOR --> <scroll-view style="flex:1"> <!-- #endif --> <page-head title="权限申请监听"></page-head> <view class="permission-alert" id="permission-alert" :style="{'transform':isPermissionAlertShow ? 'translateY(0)':'translateY(-110px)'}"> <text style="font-size: 20px;margin-bottom: 10px;margin-top: 5px;">访问日历权限申请说明:</text> <text style="color: darkgray;">uni-app x正在申请访问日历权限用于演示,允许或拒绝均不会获取任何隐私信息。</text> </view> <button type="primary" style="margin: 10px;" @click="requestPermission">点击申请日历权限</button> <!-- #ifdef APP && !VUE3-VAPOR --> </scroll-view> <!-- #endif --> </template>

需要说明的是,示例页面中的弹框仅用于演示,实际开发中监听权限申请的代码应放在app.uvue中,弹框应全局处理(可参考插件uni-prompt的 app-android 实现,自行封装一个 uts 全局弹框)。

另外,仓库示例在发起申请前还使用了UTSAndroid.checkSystemPermissionGranted做预检查,若权限已授予则直接提示“权限已经同意了,不需要再申请”,避免重复弹窗:

if (UTSAndroid.checkSystemPermissionGranted(UTSAndroid.getUniActivity()!, ["android.permission.READ_CALENDAR"])) { uni.showToast({ title: "权限已经同意了,不需要再申请", position: "bottom" }) return } UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, ["android.permission.READ_CALENDAR"], ...)

与 uni.requestSystemPermission 的配合使用

本 API 监听的是通过uni.requestSystemPermissionUTSAndroid.requestSystemPermission申请的权限。相关配套 API uni.requestSystemPermission 的参数与回调如下:

| 名称 | 类型 | 必填 | 描述 | | :- | :- | :-: | :- | | options | RequestSystemPermissionOptions | 是 | 请求系统权限参数 |

其中options支持:

  • permissions: Array<string>(必填):申请的系统权限列表,如["android.permission.CAMERA"]["android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION"]
  • success: (result) => void:成功回调,结果包含:
    • grantedList: Array<string>:已授权权限列表,仅包含当前系统支持的权限;
    • deniedList: Array<string>:已拒绝权限列表;
    • doNotAskAgainList: Array<string>:不再询问权限列表;
  • fail: (result) => void:失败回调,可通过errCode区分原因,例如1560601表示“申请权限为空”,1560604表示“不支持申请权限”;
  • complete: (result) => void:申请结束(无论成败)均会触发的回调。

建议的权限字符串(Android)包括但不限于:android.permission.CAMERAandroid.permission.READ_CALENDARandroid.permission.ACCESS_FINE_LOCATIONandroid.permission.ACCESS_COARSE_LOCATION等,完整列表可参考仓库文档 app-nativeresource-android 中的权限章节。

全局合规监听的最佳实践(app.uvue 落地)

针对华为应用市场“调用终端权限时同步告知申请目的”的审核要求,推荐把监听放到app.uvue中全局注册,并使用全局弹框组件展示说明:

<script setup lang="uts"> let permissionListener: RequestPermissionListener | null = null onLaunch(() => { permissionListener = uni.createRequestPermissionListener() // 申请发起时:可在此记录即将申请的权限 permissionListener.onRequest((permissions: Array<string>) => { console.log('正在申请权限:', permissions) }) // 确认框弹出时:展示全局“权限用途说明” permissionListener.onConfirm((permissions: Array<string>) => { // TODO 根据 permissions 内容匹配对应文案,全局弹框提示 }) // 确认框关闭时:收起全局弹框 permissionListener.onComplete((permissions: Array<string>) => { // TODO 隐藏全局弹框 }) }) onUnload(() => { permissionListener?.stop() permissionListener = null }) </script>

全局弹框建议封装为独立的 uts 插件/组件(类似仓库中uni-prompt插件的实现思路),保证在任何页面发起权限申请时都能同步展示合规说明,而无需在每个业务页面重复编写监听代码。

Tips 与注意事项

综合文档提示与源码实现,使用时需注意以下几点:

  1. 已授权权限不触发 onConfirm:如果权限已经申请并且允许之后,onConfirm不会触发。因此已授权权限的二次申请不会重复弹窗,展示层逻辑应兼容这种情况。
  2. onComplete 可能多次触发:如果同时申请多个权限,onComplete可能会触发多次(例如系统对多个权限分别弹框确认),UI 收尾逻辑需做幂等处理。
  3. 永久拒绝后的特殊行为:uni-app x 中如果请求一个已经被永久拒绝的权限,可能会触发onConfirm,此时提示文案应避免“已拒绝不再询问”的误判。
  4. 监听范围有限:权限监听仅支持通过调用uni.requestSystemPermissionUTSAndroid.requestSystemPermission申请的权限;通过原生三方 SDK 内部直接发起的权限申请可能不会被监听到。
  5. 及时清理:页面卸载时务必调用stop()取消监听(参见示例中的onUnload),防止监听回调持有页面上下文造成泄漏。
  6. 平台限制:该 API 不支持 Web、iOS、HarmonyOS,使用前建议用条件编译// #ifdef APP-ANDROID包裹相关代码,并在非 Android 平台提供降级处理。
  7. onConfirm 时机精度:从仓库示例代码中的注释(“目前 onConfirm 监听实现的在时间上不够精确,暂时需要延迟弹框”)可以推断,onConfirm与系统弹窗的实际展示存在微小时间差,生产环境可通过setTimeout微调提示条展示时机。
  8. 全局监听可参考现成插件:全局监听权限申请可参考插件uni-registerRequestPermissionTips,快速复用成熟方案。

通用类型

监听回调与多数 uni API 一样,可统一处理GeneralCallbackResult

| 名称 | 类型 | 必备 | 描述 | | :- | :- | :-: | :- | | errMsg | string | 是 | 错误信息 |

参考阅读

  • API 文档:create-request-permission-listener.md
  • 配套申请 API:request-system-permission.md
  • 插件源码:uni-createRequestPermissionListener 实现
  • 接口声明:interface.uts
  • 可运行示例:create-request-permission-listener.uvue
  • Android 权限清单说明:app-nativeresource-android

提示:该 API 不支持 Web,请将 hello uni-app x 运行到 App 平台体验完整效果。

  • 示例工程
  • 前端
  • 移动开发
  • 跨平台

【免费下载链接】uni-app

A cross-platform framework using Vue.js

项目地址:https://gitcode.com/gh_mirrors/un/uni-app
点击查看免费下载

相关推荐

上一篇:电话号码地理编码缓存:libphonenumber离线查询性能优化
下一篇:Prepack性能测试报告:基于真实项目的执行效率对比分析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询