device_info: 2.0.3
permission_handler: 11.3.1
permission_handler 权限使用说明文档
📖 概述
permission_handler
是 Flutter 中最常用的权限请求插件。它提供了一个统一的 API 用于检查和请求 iOS 和 Android 平台的运行时权限。
本文档基于 permission_handler_platform_interface
中的 Permission
类源码,详细说明了每个权限的定义、平台差异、行为和使用注意事项。
🧾 权限列表(按功能分类)
1. 日历权限
权限 | 平台 | 说明 | 备注 |
---|---|---|---|
calendar | Android, iOS | 访问设备日历。 | 已弃用。请使用 calendarWriteOnly 和 calendarFullAccess 。 |
calendarWriteOnly | Android, iOS | 仅写入设备日历的权限。 | 在 iOS 16 及更低版本上,此权限与 calendarFullAccess 相同。 |
calendarFullAccess | Android, iOS | 读取和写入设备日历的权限。 |
2. 相机与媒体权限
权限 | 平台 | 说明 | 备注 |
---|---|---|---|
camera | Android, iOS | 访问设备的摄像头。 | iOS 上对应 Photos (相机胶卷和相机)。 |
mediaLibrary | 主要 iOS | 访问设备的媒体库(iOS 9.3+)。 | 在 iOS 上,用于访问 Apple Music 等媒体内容,不是照片。 |
photos | Android, iOS | 访问设备的照片。 | 平台差异大: - iOS: Photos (iOS 14+ 读写访问级别)。 - Android: - API 32 (Android 12) 及以下:使用 Permission.storage 。 - API 33 (Android 13) 及以上:应使用 Permission.photos 。 |
photosAddOnly | 仅 iOS | 仅添加照片到设备照片库的权限。 | iOS: Photos (14+ 仅添加访问级别)。如果想读取,需使用 photos 。 |
videos | Android 13+ | 访问设备外部存储中的视频文件。 | Android API 33+。 |
audio | Android 13+ | 访问设备外部存储中的音频文件。 | Android API 33+。 |
accessMediaLocation | Android 10+ | 访问用户共享集合中任何媒体文件包含的地理位置信息。 | Android API 29+。 |
3. 联系人、传感器与手机功能
权限 | 平台 | 说明 | 备注 |
---|---|---|---|
contacts | Android, iOS | 访问设备的联系人。 | Android: Contacts iOS: AddressBook |
microphone | Android, iOS | 访问设备的麦克风。 | |
sensors | Android, iOS | 访问设备的传感器。 | Android: Body Sensors iOS: CoreMotion |
sensorsAlways | Android 13+ | 在后台访问设备的传感器。 | Android API 33+。 |
phone | 仅 Android | 访问设备手机状态(如电话号码、蜂窝网络信息)。 | PermissionWithService ,可查询服务状态。 |
sms | 仅 Android | 发送和读取短信。 | |
bluetooth | Android, iOS | 访问设备的蓝牙适配器状态。 | PermissionWithService 。 iOS 13+: 需要授权。 iOS 13.0 注意: .status 可能不准确,请使用 .request() 并处理弹窗。 |
bluetoothScan | Android 12+ | 扫描蓝牙设备。 | Android API 31+。 |
bluetoothAdvertise | Android 12+ | 广播蓝牙设备(使本设备可被其他设备发现)。 | Android API 31+。 |
bluetoothConnect | Android 12+ | 连接已配对的蓝牙设备。 | Android API 31+。 |
speech | Android, iOS | 访问语音识别功能。 | 平台行为不同: - Android: 请求麦克风权限(同 microphone )。 - iOS: 请求语音访问权限(与 microphone 不同)。 |
4. 位置权限
权限 | 值 | 平台 | 说明 | 备注 |
---|---|---|---|---|
location | 3 | Android, iOS | 访问设备的粗略和精确定位。 | PermissionWithService 。 Android: Fine and Coarse Location iOS: CoreLocation (Always and WhenInUse) |
locationWhenInUse | 5 | Android, iOS | 仅在应用前台运行时访问设备位置。 | PermissionWithService 。 Android: Fine and Coarse Location iOS: CoreLocation - WhenInUse |
locationAlways | 4 | Android, iOS | 在应用后台运行时也访问设备位置。 | PermissionWithService 。 注意: 在 Android 10+ 上,需要先获得前台定位权限,然后此权限会显示额外对话框或打开设置页。 iOS: CoreLocation - Always |
activityRecognition | 19 | Android 10+ | 访问活动识别(如检测用户步行、驾车等)。 | Android API 29+。 |
5. 存储权限
权限 | 值 | 平台 | 说明 | 备注 |
---|---|---|---|---|
storage | 15 | 主要 Android | 访问外部存储。 | 平台差异大: - Android: - API 33+: 此权限已弃用,总是返回 denied 。请使用 photos , videos , audio 或 manageExternalStorage 。 - API 33-: 请求 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 。 - iOS: 访问 Documents 或 Downloads 等文件夹。隐式授予。 |
manageExternalStorage | 22 | Android 11+ | 管理外部存储(范围存储下的广泛文件访问权限)。 | Android API 30+。 慎用: 应优先使用更隐私友好的 API(如 Storage Access Framework)。使用此权限可能需要向 Google Play 提交声明表。 |
6. 其他系统权限
权限 | 值 | 平台 | 说明 | 备注 |
---|---|---|---|---|
reminders | 11 | 仅 iOS | 访问设备的提醒事项。 | |
notification | 17 | Android, iOS | 推送通知。 | |
ignoreBatteryOptimizations | 16 | 仅 Android | 忽略电池优化(请求应用不被休眠)。 | |
systemAlertWindow | 23 | 仅 Android | 绘制系统警报窗口(悬浮窗)。 | |
requestInstallPackages | 24 | Android 6.0+ | 请求安装软件包。 | Android API 23+。 |
appTrackingTransparency | 25 | 仅 iOS | 应用跟踪透明度(ATT)权限。 | 用于请求跟踪用户 across apps 和网站的权限。 |
criticalAlerts | 26 | 仅 iOS | 发送关键警报(绕过静音模式的通知)。 | |
accessNotificationPolicy | 27 | Android 6.0+ | 访问通知策略(如开关勿扰模式)。 | Android API 23+。 |
nearbyWifiDevices | 31 | Android 13+ | 通过 Wi-Fi 连接附近设备。 | Android API 33+。 |
scheduleExactAlarm | 34 | Android 12+ | 安排精确警报。 | Android API 31+。 |
assistant | 38 | Android, iOS | 助手权限。 | Android: 无 iOS: SiriKit |
backgroundRefresh | 39 | 仅 iOS | 读取当前后台应用刷新状态。 |
7. 特殊权限
权限 | 值 | 说明 |
---|---|---|
unknown | 20 | 未知权限,仅用作返回类型,从不主动请求。 |
🛠️ 核心类说明
Permission
类
- 作用: 定义所有可以检查和请求的权限。
- 核心属性:
value
(整数值,用于区分不同权限)。 - 核心方法:
Permission.byValue(int value)
: 工厂构造函数,通过整数值创建 Permission 实例。static const List<Permission> values
: 所有可能的权限值列表。
PermissionWithService
类
- 继承自:
Permission
。 - 作用: 一种特殊的权限,用于访问系统服务(如定位服务、蓝牙服务、电话服务)。除了拥有普通权限的检查和请求功能外,还可以查询相关服务的状态(例如,定位服务是否开启)。
- 包含的权限:
location
,locationAlways
,locationWhenInUse
,phone
,bluetooth
。
⚠️ 重要平台差异与使用指南
-
Android 存储权限演变 (API 33 / Android 13+)
- 问题:
Permission.storage
在 Android 13+ 上已废弃并总是返回denied
。 - 解决方案:
- 如果只需要访问媒体文件(图片、视频、音频),使用新的细分权限:
Permission.photos
(图片)Permission.videos
(视频)Permission.audio
(音频)
- 如果需要广泛的文件管理(访问所有文件),考虑使用
Permission.manageExternalStorage
(但需注意商店审核政策)。
- 如果只需要访问媒体文件(图片、视频、音频),使用新的细分权限:
- 代码适配示例:
Future<Permission> getStoragePermission() async { if (Platform.isAndroid) { final androidInfo = await DeviceInfoPlugin().androidInfo; if (androidInfo.version.sdkInt <= 32) { // Android 12 (API 32) 及以下,使用 storage return Permission.storage; } else { // Android 13 (API 33) 及以上,使用 photos(假设你需要图片) return Permission.photos; } } else { // iOS 平台,使用 photos return Permission.photos; } } // 使用 void checkPermission() async { Permission neededPermission = await getStoragePermission(); var status = await neededPermission.status; if (status.isDenied) { status = await neededPermission.request(); } // ... 处理状态 }
- 问题:
-
iOS 权限描述 (
Info.plist
)- 要求: 在请求任何敏感权限之前,必须在
ios/Runner/Info.plist
文件中添加相应的用途描述键和描述文字,否则可能导致请求失败或应用被拒绝。 - 示例:
- 相机:
NSCameraUsageDescription
- 相册:
NSPhotoLibraryUsageDescription
- 位置(始终):
NSLocationAlwaysUsageDescription
- 位置(使用时):
NSLocationWhenInUseUsageDescription
- 麦克风:
NSMicrophoneUsageDescription
- 语音识别:
NSSpeechRecognitionUsageDescription
- 追踪:
NSUserTrackingUsageDescription
(用于appTrackingTransparency
)
- 相机:
- 要求: 在请求任何敏感权限之前,必须在
-
Android 权限声明 (
AndroidManifest.xml
)- 要求: 同样需要在
android/app/src/main/AndroidManifest.xml
文件中声明你需要的权限。 - 示例:
<uses-permission android:name="android.permission.CAMERA" />
- 要求: 同样需要在
-
服务相关权限 (
PermissionWithService
)- 对于
location
,bluetooth
等权限,除了检查permission.status
,还应检查serviceEnabled
(通过PermissionWithService
的能力或其它专用API,如location.serviceEnabled
),因为用户可能关闭了设备的定位服务或蓝牙服务,即使权限已被授予。
- 对于
💡 最佳实践与常见问题
- 按需请求: 在用户即将使用相关功能时才请求权限,而不是在应用启动时一次性请求所有权限。
- 解释原因: 在系统弹窗之前,自定义一个界面解释为什么需要这个权限,可以提高用户授权率。
- 处理“不再询问”: 如果
status.isPermanentlyDenied
为true
,应引导用户前往系统设置手动开启权限(使用openAppSettings()
方法)。 - 真机测试: 务必在真实设备上测试权限流程,模拟器的行为可能与真机不一致。
- iOS 配置: 确保
Podfile
中已为permission_handler
配置了所需的预处理器宏,以确保 iOS 权限检测正常工作。例如:post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) # ... 权限处理器配置 target.build_configurations.each do |config| config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ '$(inherited)', 'PERMISSION_CAMERA=1', 'PERMISSION_PHOTOS=1', # ... 其他需要的权限 ] end end end
- 版本检查: 对于 Android,使用
device_info_plus
等插件来获取系统版本号,以适配不同 API 级别的权限逻辑。
通过遵循本文档的说明,您可以更准确、更安全地在您的 Flutter 应用中处理各种运行时权限。