Flutter中的权限处理

权限在构建移动应用程序时至关重要,这些应用程序需要访问设备功能,如位置、相机、联系人等。在Flutter中,有效处理这些权限确保应用程序提供无缝的用户体验,同时遵守隐私和安全要求。在Flutter中管理权限的一个流行包是permission_handler

本文将指导您如何在Flutter中使用permission_handler请求、检查和处理不同权限,其中包括基于permission_handler的实际示例。

首先,将permission_handlerfluttertoast包添加到您的pubspec.yaml文件中:

dependencies:
  permission_handler: ^11.3.1 
  fluttertoast: ^8.2.4

然后运行:

flutter pub get

permission_handler包提供了一种简单的方式来请求权限并检查其状态。以下是处理不同权限(如电话呼叫、联系人、位置、短信以及相机/麦克风)的完整细分。

权限处理程序可以处理以下所有类型的权限:日历、相机、联系人、位置、媒体库、麦克风、电话、照片、提醒事项、传感器、短信、语音识别、存储、忽略电池优化、通知、访问媒体位置、活动识别、蓝牙权限、管理外部存储、系统警报窗口、请求安装包、应用跟踪透明度、关键警报、访问通知策略、附近的 Wi-Fi 设备、音频、精确闹钟计划、始终传感器、只读日历和完全访问日历,但本文将涵盖其中一部分。

以下是关于如何请求每种类型权限、处理拒绝或永久拒绝等情况以及每种权限授予访问权限的详细指南。


  • 权限: calendar, calendarReadOnly, calendarFullAccess

  • 用例: 访问用户的日历以读取或写入事件。

Future<void> requestCalendarPermission() async {
  var status = await Permission.calendar.request();

  if (status.isGranted) {
    // Permission granted, proceed with calendar access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Calendar permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Calendar permission denied',
    );
  }
}

  • 权限: camera

  • 用例: 访问设备的相机以拍摄照片或视频。

Future<void> requestCameraPermission() async {
  var status = await Permission.camera.request();

  if (status.isGranted) {
    // Permission granted, proceed with camera access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Camera permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Camera permission denied',
    );
  }
}

  • 权限: contacts

  • 使用案例: 访问用户的联系人列表以读取或修改联系人。

Future<void> requestContactsPermission() async {
  var status = await Permission.contacts.request();

  if (status.isGranted) {
    // Permission granted, proceed with contacts access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Contacts permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Contacts permission denied',
    );
  }
}

  • 权限: location, locationAlways, locationWhenInUse, accessMediaLocation

  • 使用案例: 访问用户的位置以进行导航、地理围栏或附近服务。

Future<void> requestLocationPermission() async {
  var status = await Permission.location.request();

  if (status.isGranted) {
    // Permission granted, proceed with location access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Location permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Location permission denied',
    );
  }
}

  • 权限: mediaLibrary

  • 使用案例: 访问用户的媒体库(仅限iOS)。
Future<void> requestMediaLibraryPermission() async {
  var status = await Permission.mediaLibrary.request();

  if (status.isGranted) {
    // Permission granted, proceed with media library access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Media Library permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Media Library permission denied',
    );
  }
}

  • 权限: microphone

  • 使用案例:访问设备的麦克风以录制音频。

Future<void> requestMicrophonePermission() async {
  var status = await Permission.microphone.request();

  if (status.isGranted) {
    // Permission granted, proceed with microphone access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Microphone permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Microphone permission denied',
    );
  }
}

  • 权限phone

  • 使用案例:拨打电话、读取电话状态或访问通话记录。

Future<void> requestPhonePermission() async {
  var status = await Permission.phone.request();

  if (status.isGranted) {
    // Permission granted, proceed with phone access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Phone permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Phone permission denied',
    );
  }
}

  • 权限photos, photosAddOnly

  • 使用案例:访问用户的照片库以读取或添加照片。

Future<void> requestPhotosPermission() async {
  var status = await Permission.photos.request();

  if (status.isGranted) {
    // Permission granted, proceed with photos access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Photos permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Photos permission denied',
    );
  }
}

  • 权限reminders

  • 使用案例:访问并管理用户设备上的提醒事项。

Future<void> requestRemindersPermission() async {
  var status = await Permission.reminders.request();

  if (status.isGranted) {
    // Permission granted, proceed with reminders access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Reminders permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Reminders permission denied',
    );
  }
}

  • 权限sensors, sensorsAlways

  • 使用案例: 访问设备的传感器,如加速度计和陀螺仪。

Future<void> requestSensorsPermission() async {
  var status = await Permission.sensors.request();

  if (status.isGranted) {
    // Permission granted, proceed with sensors access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Sensors permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Sensors permission denied',
    );
  }
}

  • 权限: sms

  • 使用案例: 访问短信功能,包括读取或发送短信。

Future<void> requestSmsPermission() async {
  var status = await Permission.sms.request();

  if (status.isGranted) {
    // Permission granted, proceed with SMS access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'SMS permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'SMS permission denied',
    );
  }
}

  • 权限: speech

  • 使用案例: 访问语音转文本功能。

Future<void> requestSpeechPermission() async {
  var status = await Permission.speech.request();

  if (status.isGranted) {
    // Permission granted, proceed with speech recognition
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Speech recognition permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Speech recognition permission denied',
    );
  }
}

  • 权限: storage, manageExternalStorage

  • 使用案例: 访问用户的内部或外部存储以读取或写入文件。

Future<void> requestStoragePermission() async {
  var status = await Permission.storage.request();

  if (status.isGranted) {
    // Permission granted, proceed with storage access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Storage permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Storage permission denied',
    );
  }
}

  • 权限: ignoreBatteryOptimizations

  • 使用情况: 请求系统将应用排除在电池优化措施之外。

Future<void> requestIgnoreBatteryOptimizationsPermission() async {
  var status = await Permission.ignoreBatteryOptimizations.request();

  if (status.isGranted) {
    // Permission granted, proceed with ignoring battery optimizations
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Battery optimization permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Battery optimization permission denied',
    );
  }
}

  • 权限: notification

  • 使用情况: 允许您的应用发送通知。

Future<void> requestNotificationPermission() async {
  var status = await Permission.notification.request();

  if (status.isGranted) {
    // Permission granted, proceed with notifications access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Notification permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Notification permission denied',
    );
  }
}

  • 权限: bluetooth, bluetoothScan, bluetoothAdvertise, bluetoothConnect

  • 使用情况: 访问蓝牙功能以连接或管理蓝牙设备。

Future<void> requestBluetoothPermission() async {
  var status = await Permission.bluetooth.request();

  if (status.isGranted) {
    // Permission granted, proceed with Bluetooth access
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'Bluetooth permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'Bluetooth permission denied',
    );
  }
}

  • 权限: appTrackingTransparency

  • 使用情况: 请求用户允许跟踪,这是 iOS 中应用跟踪的要求。

Future<void> requestAppTrackingTransparencyPermission() async {
  var status = await Permission.appTrackingTransparency.request();

  if (status.isGranted) {
    // Permission granted, proceed with app tracking
  } else if (status.isPermanentlyDenied) {
    ShowToast.showErrorText(
      text: 'App tracking permission permanently denied. Please enable it in the app settings.',
    );
    openAppSettings();
  } else {
    ShowToast.showErrorText(
      text: 'App tracking permission denied',
    );
  }
}

权限在提供用户无缝体验的同时尊重其隐私方面起着至关重要的作用。优雅处理这些权限并向用户解释您的应用为何需要它们至关重要。

通过使用 permission_handler 包,您可以在 Android 和 iOS 平台上请求、检查和管理所有必要的权限,适用于您的 Flutter 应用程序。始终向用户提供有意义的反馈,并考虑在权限被拒绝或撤销时添加替代流程。

Android 和 iOS 配置

包括必要的 Android 和 iOS 配置是非常重要的。对于 Android,这意味着更新 AndroidManifest.xml 文件以正确声明权限。对于 iOS,必须将权限使用说明添加到 Info.plist 文件中,以便告知用户为何请求某些权限。

对于 17 个示例中的每个权限,您需要在 AndroidManifest.xml 中添加相应的 <uses-permission> 标签。以下是这些权限与 permission_handler 包的对应关系:

  1. 相机权限

     <uses-permission android:name="android.permission.CAMERA" />
    
  2. 通讯录权限

     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    
  3. 位置权限

     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    
  4. 媒体库/存储权限

     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage"/>
     <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
     <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
     <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
    
  5. 麦克风权限

     <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  6. 电话权限

     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    
  7. 照片权限

     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
  8. 提醒权限(无明确的Android权限)

  9. 传感器权限

     <uses-permission android:name="android.permission.BODY_SENSORS" />
    
  10. 短信权限

    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    
  11. 语音识别权限

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  12. 忽略电池优化

    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
    
  13. 通知权限(在 Android 13+ 中原生处理)

  14. 访问媒体位置权限

    <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
    
  15. 活动识别权限

    <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
    
  16. 蓝牙权限

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    
  17. 应用追踪透明度权限(仅限iOS)


对于iOS,您必须在Info.plist文件中提供描述性键,以告知用户您的应用为何需要特定权限。以下是每个权限示例的配置:

  1. 相机权限

     <key>NSCameraUsageDescription</key>
     <string>我们需要访问您的相机以拍照。</string>
    
  2. 通讯录权限

     <key>NSContactsUsageDescription</key>
     <string>我们需要访问您的通讯录以实现更好的沟通。</string>
    
  3. 位置权限

     <key>NSLocationWhenInUseUsageDescription</key>
     <string>我们需要访问您的位置以提供基于位置的服务。</string>
     <key>NSLocationAlwaysUsageDescription</key>
     <string>我们需要访问您的位置以在应用未激活时跟踪您的移动。</string>
    
  4. 媒体库/存储权限

     <key>NSPhotoLibraryUsageDescription</key>
     <string>我们需要访问您的照片以便分享或上传媒体。</string>
    
  5. 麦克风权限

     <key>NSMicrophoneUsageDescription</key>
     <string>我们需要访问您的麦克风以进行语音录制。</string>
    
  6. 电话权限

     <key>NSPhoneUsageDescription</key>
     <string>我们需要访问电话服务以启用拨打电话。</string>
    
  7. 照片权限

     <key>NSPhotoLibraryAddUsageDescription</key>
     <string>我们需要权限将照片添加到您的库中。</string>
    
  8. 提醒权限

     <key>NSRemindersUsageDescription</key>
     <string>我们需要访问您的提醒事项以进行任务管理。</string>
    
  9. 传感器权限

     <key>NSSensorsUsageDescription</key>
     <string>我们需要访问您的传感器以进行健康追踪。</string>
    
  10. 短信权限(如果请求短信服务,iOS会自动处理)

  11. 语音识别权限

<key>NSSpeechRecognitionUsageDescription</key>
<string>We need access to speech recognition for voice commands.</string>
  1. 忽略电池优化(不适用于iOS)

  2. 通知权限

<key>NSUserNotificationUsageDescription</key>
<string>We need permission to send notifications.</string>
  1. 访问媒体位置权限(在iOS上自动处理)

  2. 活动识别权限

<key>NSMotionUsageDescription</key>
<string>We need access to motion data for fitness tracking.</string>
  1. 蓝牙权限
<key>NSBluetoothPeripheralUsageDescription</key>
<string>We need access to Bluetooth for device connectivity.</string>
  1. 应用追踪透明度
<key>NSUserTrackingUsageDescription</key>
<string>We need permission to track your activity across apps and websites for personalized ads.</string>

为了使您的应用程序完全功能正常并符合最新的隐私法规,适当管理权限至关重要。通过更新 AndroidManifest.xmlInfo.plist,以及在您的 Flutter 应用中实施正确的权限处理逻辑,您可以在请求访问敏感功能时为用户提供无缝且透明的体验。

始终确保在两个平台上测试权限,并向用户提供有关为何需要这些权限的有意义解释,以避免在应用商店审核期间被拒绝。

如需更深入的研究,可以查看官方的 权限处理文档 以探索其他权限类型。确保更新您的平台特定文件(如 AndroidManifest.xmlInfo.plist),并为每种权限类型提供必要的声明。

Source:
https://atuoha.hashnode.dev/permission-handling-in-flutter