更新记录

1.0.0(2026-01-02)

首次发布


平台兼容性

xc-sys-permission

一套跨端权限工具,统一封装 Android / iOS / 鸿蒙 的权限检查、申请与跳转设置页,适用于 uni-app 及 uni-app x。

功能特点

  • 同一份 API 覆盖 Android、iOS、鸿蒙(OpenHarmony/HarmonyOS)
  • checkPermissions / requestPermissions / openSystemPermissionPage 三个核心方法,返回统一的 PermissionResult
  • 使用原生 API 实现,不依赖第三方库
  • 原生权限常量格式(android.permission.XXX, ohos.permission.XXX, iOS Info.plist key)
  • 权限结果按传参顺序返回,保持原始顺序
  • 支持在用户拒绝权限时,通过 doNotAskAgain 标识引导到系统设置

安装与引入

插件市场直接安装或将代码放入 uni_modules/xc-sys-permission

页面中引入:

import { checkPermissions, requestPermissions, openSystemPermissionPage } from '@/uni_modules/xc-sys-permission'

调用时需保证页面已启动(如 onLoad / onShow 后),以便 Android/Harmony 拿到有效 Activity/UIAbilityContext

支持的权限名约定

Android

支持所有 Android 系统权限常量(不限于示例),权限名称必须以 android.permission. 开头,如:

  • android.permission.CAMERA - 相机权限
  • android.permission.RECORD_AUDIO - 麦克风权限
  • android.permission.ACCESS_FINE_LOCATION - 精确位置权限
  • android.permission.ACCESS_COARSE_LOCATION - 粗略位置权限
  • android.permission.READ_MEDIA_IMAGES - 读取图片(Android 13+,API 33+)
  • android.permission.READ_MEDIA_VIDEO - 读取视频(Android 13+,API 33+)
  • android.permission.READ_MEDIA_AUDIO - 读取音频(Android 13+,API 33+)
  • android.permission.READ_EXTERNAL_STORAGE - 读取外部存储(Android 12 及以下,API < 33)
  • android.permission.WRITE_EXTERNAL_STORAGE - 写入外部存储(Android 9 及以下,API < 29)
  • android.permission.POST_NOTIFICATIONS - 通知权限(Android 13+,API 33+)
  • android.permission.READ_CONTACTS - 读取通讯录权限
  • android.permission.WRITE_CONTACTS - 写入通讯录权限
  • android.permission.READ_CALENDAR - 读取日历权限
  • android.permission.WRITE_CALENDAR - 写入日历权限
  • 等等... 支持所有 Android 系统权限常量

注意

  • 权限名称可以不带 android.permission. 前缀,系统会自动补全
  • 对于媒体权限(READ_MEDIA_IMAGESREAD_MEDIA_VIDEOREAD_MEDIA_AUDIO),在 Android 12 及以下会自动映射为 READ_EXTERNAL_STORAGE
  • 对于通知权限(POST_NOTIFICATIONS),仅在 Android 13+(API 33+)有效,需要跳转到系统设置

iOS

直接使用 Info.plist 中的权限说明 key(原生常量),支持所有 iOS 系统权限 key,如:

基础权限

  • NSPhotoLibraryUsageDescription - 相册权限(读取)
  • NSPhotoLibraryAddUsageDescription - 相册权限(仅添加)
  • NSCameraUsageDescription - 相机权限
  • NSMicrophoneUsageDescription - 麦克风权限
  • NSLocationWhenInUseUsageDescription - 定位权限(使用时)
  • NSLocationAlwaysAndWhenInUseUsageDescription - 定位权限(始终和使用时,iOS 11+)

系统服务权限

  • NSContactsUsageDescription - 通讯录权限
  • NSCalendarsUsageDescription - 日历权限(iOS 17+ 需要完整访问)
  • NSCalendarsFullAccessUsageDescription - 日历完整访问权限(iOS 17+)
  • NSCalendarsWriteOnlyUsageDescription - 日历仅写入权限(iOS 17+)
  • NSRemindersUsageDescription - 提醒事项权限
  • NSAppleMusicUsageDescription - Apple Music 权限

生物识别与安全

  • NSFaceIDUsageDescription - Face ID 权限

健康与运动

  • NSMotionUsageDescription - 运动与健身权限
  • NSHealthShareUsageDescription - 健康数据读取权限
  • NSHealthUpdateUsageDescription - 健康数据写入权限

智能家居与语音

  • NSHomeKitUsageDescription - HomeKit 权限
  • NSSiriUsageDescription - Siri 权限
  • NSSpeechRecognitionUsageDescription - 语音识别权限

媒体与订阅

  • NSVideoSubscriberAccountUsageDescription - 视频订阅账户权限

网络与蓝牙

  • NSBluetoothAlwaysUsageDescription - 蓝牙权限(iOS 13+)
  • NSBluetoothPeripheralUsageDescription - 蓝牙外设权限(iOS 12 及以下,已废弃)
  • NSLocalNetworkUsageDescription - 本地网络权限

隐私与追踪

  • NSUserTrackingUsageDescription - 追踪权限(ATT,iOS 14.5+)

注意

  • 所有权限都需要在 Info.plist 中声明对应的 usage description 键值对
  • 部分权限(如通知权限)需要异步检查,cannotCheckByAPI 字段会标识
  • 某些权限(如健康、HomeKit、Siri 等)无法通过 API 准确检查状态,需要通过实际使用来判断

鸿蒙(HarmonyOS)

@ohos.abilityAccessCtrl 的权限名,权限名称必须以 ohos.permission. 开头,如:

基础权限

  • ohos.permission.CAMERA - 相机权限
  • ohos.permission.MICROPHONE - 麦克风权限
  • ohos.permission.LOCATION - 定位权限

通讯录与日历

  • ohos.permission.READ_CALENDAR - 读取日历权限
  • ohos.permission.WRITE_CALENDAR - 写入日历权限

通知权限

  • ohos.permission.ACCESS_NOTIFICATION_POLICY - 通知权限

其他权限

  • 等等... 支持所有鸿蒙系统权限常量

注意

  • 权限名称必须严格以 ohos.permission. 开头,否则会被识别为无效权限(状态 3)
  • 所有权限都需要在 module.json5 中声明
  • 权限状态检查使用 checkAccessToken API,无法区分"从未申请过"和"已拒绝",统一返回未授权(状态 0)
  • 一旦用户拒绝权限,系统会记住选择,无法再次弹出对话框,需要引导到系统设置
  • 更多权限列表请参考:鸿蒙权限管理文档

API 说明

checkPermissions(permissions)

检查权限状态,同步返回(鸿蒙为 Promise,推荐统一使用 await)

import { checkPermissions } from '@/uni_modules/xc-sys-permission'

// Android 示例
const permissionList = [{
  name: 'android.permission.CAMERA',
  title: '相机权限申请说明:',
  content: 'APP申请相机权限用于扫码,允许或拒绝均不会获取任何隐私信息。'
}]

// iOS 示例(直接使用 Info.plist key)
// const permissionList = [{
//   name: 'NSCameraUsageDescription',
//   title: '相机权限申请说明:',
//   content: 'APP申请相机权限用于扫码,允许或拒绝均不会获取任何隐私信息。'
// }]

const res = await checkPermissions(permissionList)
if (!res.allGranted) {
  // TODO: 给出引导
  console.log('未授权权限:', res.permissions.filter(p => p.status !== 1))
}

requestPermissions(permissions)

申请权限并返回 Promise

import { requestPermissions, openSystemPermissionPage } from '@/uni_modules/xc-sys-permission'

// Android 示例
const permissionList = [{
  name: 'android.permission.CAMERA',
  title: '相机权限申请说明:',
  content: 'APP申请相机权限用于扫码,允许或拒绝均不会获取任何隐私信息。'
}]

// iOS 示例(直接使用 Info.plist key)
// const permissionList = [{
//   name: 'NSCameraUsageDescription',
//   title: '相机权限申请说明:',
//   content: 'APP申请相机权限用于扫码,允许或拒绝均不会获取任何隐私信息。'
// }]

const res = await requestPermissions(permissionList)
if (!res.allGranted && res.doNotAskAgain) {
  // 用户勾选"不再询问"或权限被永久拒绝,引导去系统设置
  openSystemPermissionPage(permissionList)
}

openSystemPermissionPage(permissions)

打开系统权限设置页;Android 支持传入需要高亮/引导的权限列表,iOS 无视参数直接跳转 App 设置,鸿蒙返回 Promise 可 await

注意permissions 参数是必需的,但可以传入空数组 [] 表示不需要特定权限。

import { openSystemPermissionPage } from '@/uni_modules/xc-sys-permission'

// 打开系统设置页(不需要特定权限)
await openSystemPermissionPage([])

// 打开系统设置页(传入需要引导的权限列表)
await openSystemPermissionPage(permissionList)

PermissionResult 结构

{
  allGranted: boolean,  // 是否全部授权(所有权限的 status 都为 1)
  doNotAskAgain: boolean,  // 是否存在需要引导到系统设置的权限(存在 status 为 2 的权限)
  permissions: Array<{
    name: string,  // 权限名称(原生常量)
    status: number,  // 权限状态:0=未授权,1=已授权,2=拒绝授权(需引导系统设置),3=无效权限
    title: string,  // 权限标题说明
    content: string,  // 权限详细说明
    cannotCheckByAPI: boolean  // 是否无法通过 API 直接检查状态(true=需要通过实际使用来判断,false=可以通过 API 检查)
  }>  // 按传参顺序返回,保持原始顺序
}

权限状态说明

  • 0 - 未授权:权限尚未授予,可以申请

    • Android:首次请求或用户拒绝但未选择"不再询问"(支持"每次询问"模式)
    • iOS:权限尚未确定(.notDetermined
    • 鸿蒙:权限未授权(GrantStatus.PERMISSION_DENIED),可以申请
  • 1 - 已授权:权限已授予,可以使用

    • Android:权限已授予(PERMISSION_GRANTED
    • iOS:权限已授权(.authorized.limited
    • 鸿蒙:权限已授权(GrantStatus.PERMISSION_GRANTED
  • 2 - 拒绝授权:权限被拒绝且无法再次申请,需要引导用户到系统设置页开启

    • Android:用户选择"不再询问"(永久拒绝),或通知权限(Android 13+)需要跳转到设置
    • iOS:权限被拒绝(.denied.restricted
    • 鸿蒙:权限被拒绝且无法再次弹出对话框(需要引导到系统设置)
  • 3 - 无效权限:权限名称无效或无法识别,该权限无法使用

    • Android:权限常量不存在、未在 AndroidManifest.xml 中声明,或版本不支持(如 POST_NOTIFICATIONS 在 API < 33)
    • iOS:Info.plist key 无法识别或未在 Info.plist 中声明
    • 鸿蒙:权限常量格式不正确(不是以 ohos.permission. 开头)或未在 module.json5 中声明

cannotCheckByAPI 字段说明

  • false - 可以通过 API 直接检查权限状态(Android、鸿蒙的所有权限,iOS 的大部分权限)
  • true - 无法通过 API 直接检查权限状态,需要通过实际使用来判断(仅 iOS 部分权限):
    • NSUserNotificationsUsageDescription - 通知权限(需要异步检查)
    • NSMotionUsageDescription - 运动权限(需要异步查询)
    • NSHealthShareUsageDescription / NSHealthUpdateUsageDescription - 健康数据权限(需要异步检查)
    • NSHomeKitUsageDescription - HomeKit 权限(无法准确判断)
    • NSSiriUsageDescription - Siri 权限(无法准确判断)
    • NSVideoSubscriberAccountUsageDescription - 视频订阅账户权限(无法准确判断)
    • NSTVProviderUsageDescription - TV Provider 权限(无法准确判断)
    • NSLocalNetworkUsageDescription - 本地网络权限(无法准确判断)

注意:当 cannotCheckByAPItrue 时,status 可能不准确,实际权限状态需要通过实际使用相关功能来判断。

使用示例

import { checkPermissions, requestPermissions, openSystemPermissionPage } from '@/uni_modules/xc-sys-permission'

// 根据平台动态构建权限列表
let permissionList = []

// #ifdef APP-PLUS
// uni-app 中需要通过系统 API 判断平台
const systemInfo = uni.getSystemInfoSync()
if (systemInfo.platform === 'android') {
  permissionList = [{
    name: 'android.permission.ACCESS_FINE_LOCATION',
    title: '手机位置权限申请说明:',
    content: 'APP申请定位信息用于查找附近门店使用,允许或拒绝均不会获取任何隐私信息。'
  }, {
    name: 'android.permission.CAMERA',
    title: '相机权限申请说明:',
    content: 'APP申请摄像头权限用于扫码,允许或拒绝均不会获取任何隐私信息。'
  }]
} else if (systemInfo.platform === 'ios') {
  permissionList = [{
    name: 'NSLocationWhenInUseUsageDescription',
    title: '手机位置权限申请说明:',
    content: 'APP申请定位信息用于查找附近门店使用,允许或拒绝均不会获取任何隐私信息。'
  }, {
    name: 'NSCameraUsageDescription',
    title: '相机权限申请说明:',
    content: 'APP申请摄像头权限用于扫码,允许或拒绝均不会获取任何隐私信息。'
  }]
}
// #endif

// #ifdef APP-ANDROID
// uni-app x 中可以直接使用 APP-ANDROID
permissionList = [{
  name: 'android.permission.ACCESS_FINE_LOCATION',
  title: '手机位置权限申请说明:',
  content: 'APP申请定位信息用于查找附近门店使用,允许或拒绝均不会获取任何隐私信息。'
}, {
  name: 'android.permission.CAMERA',
  title: '相机权限申请说明:',
  content: 'APP申请摄像头权限用于扫码,允许或拒绝均不会获取任何隐私信息。'
}]
// #endif

// #ifdef APP-IOS
// uni-app x 中可以直接使用 APP-IOS
permissionList = [{
  name: 'NSLocationWhenInUseUsageDescription',
  title: '手机位置权限申请说明:',
  content: 'APP申请定位信息用于查找附近门店使用,允许或拒绝均不会获取任何隐私信息。'
}, {
  name: 'NSCameraUsageDescription',
  title: '相机权限申请说明:',
  content: 'APP申请摄像头权限用于扫码,允许或拒绝均不会获取任何隐私信息。'
}]
// #endif

// #ifdef APP-HARMONY
permissionList = [{
  name: 'ohos.permission.LOCATION',
  title: '手机位置权限申请说明:',
  content: 'APP申请定位信息用于查找附近门店使用,允许或拒绝均不会获取任何隐私信息。'
}, {
  name: 'ohos.permission.CAMERA',
  title: '相机权限申请说明:',
  content: 'APP申请摄像头权限用于扫码,允许或拒绝均不会获取任何隐私信息。'
}]
// #endif

// 检查权限
async function checkAndRequestPermissions() {
  const checkResult = await checkPermissions(permissionList)

  if (checkResult.allGranted) {
    console.log('所有权限已授权')
    return
  }

  const requestResult = await requestPermissions(permissionList)

  if (!requestResult.allGranted && requestResult.doNotAskAgain) {
    uni.showModal({
      title: '权限申请',
      content: '部分权限被拒绝,请在系统设置中开启',
      success: (res) => {
        if (res.confirm) {
          openSystemPermissionPage(permissionList)
        }
      }
    })
  }
}

注意事项

权限声明

  1. Android:请在 manifest.jsonapp-plus -> distribute -> android -> permissions 中声明需要的权限,或在原生 AndroidManifest.xml 中使用 <uses-permission> 标签声明

    • 权限名称必须与系统权限常量完全一致(如 android.permission.CAMERA
    • 未声明的权限会被识别为无效权限(状态 3)
  2. iOS:请在 manifest.jsonapp-plus -> distribute -> ios -> privacyDescription 中声明权限说明,或在原生 Info.plist 中添加对应的 usage description 键值对

    • 键名必须与系统权限 key 完全一致(如 NSCameraUsageDescription
    • 未声明的权限无法申请,会被识别为无效权限(状态 3)
  3. 鸿蒙:请在 module.json5requestPermissions 数组中声明需要的权限

    • 权限名称必须严格以 ohos.permission. 开头(如 ohos.permission.CAMERA
    • 未声明的权限会被识别为无效权限(状态 3)
    • 更多信息请参考:鸿蒙权限管理文档

权限状态处理

  1. 权限结果数组严格按照传参顺序返回,便于前端按顺序展示

  2. status 为 2 时,表示权限被永久拒绝,需要引导用户到系统设置页开启:

    • Android:用户选择"不再询问",或通知权限(Android 13+)需要跳转到设置
    • iOS:用户拒绝权限,需要跳转到 App 设置
    • 鸿蒙:权限被拒绝且无法再次弹出对话框,需要引导到系统设置
  3. status 为 3 时,表示权限名称无效或无法识别,请检查:

    • Android:权限名称格式是否正确(可以不带 android.permission. 前缀,系统会自动补全),是否在 AndroidManifest.xml 中声明,版本是否支持
    • iOS:Info.plist key 是否正确,是否在 Info.plist 中声明
    • 鸿蒙:权限名称是否以 ohos.permission. 开头,是否在 module.json5 中声明

平台特性

  1. Android 权限特性

    • 支持"每次询问"模式(Android 13+):即使用户之前拒绝过,如果设置了"每次询问",仍然可以弹出对话框
    • 通知权限(POST_NOTIFICATIONS)在 Android 13+ 无法通过运行时对话框申请,必须跳转到系统设置
    • 媒体权限在 Android 13+ 使用 READ_MEDIA_IMAGESREAD_MEDIA_VIDEOREAD_MEDIA_AUDIO,在 Android 12 及以下自动映射为 READ_EXTERNAL_STORAGE
  2. iOS 权限特性

    • 部分权限(如通知、运动、健康等)需要异步检查,cannotCheckByAPI 字段会标识
    • 某些权限(如健康、HomeKit、Siri 等)无法通过 API 准确检查状态,需要通过实际使用来判断
    • 相册权限在 iOS 14+ 支持 .limited 状态(部分授权)
  3. 鸿蒙权限特性

    • 权限状态检查无法区分"从未申请过"和"已拒绝",统一返回未授权(状态 0)
    • 一旦用户拒绝权限,系统会记住选择,无法再次弹出对话框,需要引导到系统设置
    • 权限申请使用 requestPermissionsFromUser,永久拒绝后使用 requestPermissionOnSetting 引导到系统设置

开发文档

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。