【问题标题】:How to request and check permissions in Flutter如何在 Flutter 中请求和检查权限
【发布时间】:2021-02-15 03:24:01
【问题描述】:

当用户单击不允许时,我正在使用各种插件来获取用户数据、联系人、照片和相机,应用程序会静默。 当用户选中“不再询问”和“不允许”并再次进入应用程序时,我想向用户显示“询问权限”对话框。

目前,当用户选中“不允许”时,该应用不会再次询问

我知道用户必须授予应用访问个人信息的权限,包括当前位置、相机、日历、联系人、媒体库、麦克风、传感器、语音和照片。尽管人们喜欢使用可以访问这些信息的应用程序的便利性,但他们也希望能够控制他们的私人数据。例如,人们喜欢能够自动用他们的实际位置标记照片或找到附近的朋友,但他们也希望能够选择禁用这些功能。

flutter中如何再次请求用户权限?

【问题讨论】:

    标签: flutter dart permissions android-permissions ios-permissions


    【解决方案1】:

    我对这个问题非常困扰在应用了几个解决方案后,我找到了这个解决方案。所以我想和大家分享一下,所以我问了这个问题,我回答了

    在大多数操作系统上,权限不仅仅在安装时授予应用程序。相反,开发人员必须在应用运行时向用户请求权限。

    处理权限的最佳方式是使用permission_handler 插入。此插件提供跨平台(iOS、Android)API 来请求权限并检查其状态。

    我们还可以打开设备的应用设置,以便用户授予权限。 在 Android 上,我们可以展示请求权限的理由。

    1. 将此添加到您的包的pubspec.yaml 文件中:

      dependencies:
        permission_handler: ^5.0.1+1
      
    2. 现在在你的 Dart 代码中,你可以使用:

      import 'package:permission_handler/permission_handler.dart';
      
    3. 虽然在运行时请求权限,但您仍需要告诉操作系统您的应用可能使用哪些权限。这需要向特定于 Android 和 iOS 的文件添加权限配置。

      iOS

      • 为您的 Info.plist 文件添加权限。 Here 是一个示例 Info.plist,其中包含所有可能权限的完整列表。

      重要提示:当您想提交您的应用程序时,您必须包含所有权限选项。这是因为permission_handler 插件涉及所有不同的 SDK,并且静态代码分析器(由 Apple 在应用程序提交时运行)检测到这一点,如果在 Info.plist 中找不到匹配的权限选项,它将断言。更多相关信息请见here。

    1. 将以下内容添加到您的 Podfile 文件中:

      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)',
      
                     ## dart: PermissionGroup.calendar
                     'PERMISSION_EVENTS=0',
      
                     ## dart: PermissionGroup.reminders
                     'PERMISSION_REMINDERS=0',
      
                     ## dart: PermissionGroup.contacts
                     # 'PERMISSION_CONTACTS=0',
      
                     ## dart: PermissionGroup.camera
                     # 'PERMISSION_CAMERA=0',
      
                     ## dart: PermissionGroup.microphone
                     # 'PERMISSION_MICROPHONE=0',
      
                     ## dart: PermissionGroup.speech
                     'PERMISSION_SPEECH_RECOGNIZER=0',
      
                     ## dart: PermissionGroup.photos
                     # 'PERMISSION_PHOTOS=0',
      
                     ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
                     'PERMISSION_LOCATION=0',
      
                     ## dart: PermissionGroup.notification
                     # 'PERMISSION_NOTIFICATIONS=0',
      
                     ## dart: PermissionGroup.mediaLibrary
                     'PERMISSION_MEDIA_LIBRARY=0',
      
                     ## dart: PermissionGroup.sensors
                     'PERMISSION_SENSORS=0'
                   ]
          end
        end
      end
      
    2. 删除您确实要使用的权限前面的# 字符。例如,如果您确实需要访问日历,请确保代码如下所示:

      ## dart: PermissionGroup.calendar
      'PERMISSION_EVENTS=0',
      

    安卓

    1. 将以下内容添加到您的“gradle.properties”文件中:

      android.useAndroidX=true
      android.enableJetifier=true
      
    2. 确保将“android/app/build.gradle”文件中的compileSdkVersion 设置为28:

       android {
         compileSdkVersion 30
         ...
       }
      
    3. 确保替换所有的 android。对其 AndroidX 对应项的依赖项(完整列表可在此处找到:https://developer.android.com/jetpack/androidx/migrate)

      为您的AndroidManifest.xml 文件添加权限。有debug、main 和profile 版本可供选择,具体取决于您启动应用的方式。通常,仅向main 版本添加权限就足够了。这是一个示例 AndroidManifest.xml ,其中包含所有可能权限的完整列表。

    终于可以这样使用了

    有许多权限。您可以获得Permission 的status,即granted、denied、restricted 或permanentlyDenied。

        var status = await Permission.photos.status;
    
        if (status.isDenied) {
          // We didn't ask for permission yet.
        }
    
        // You can can also directly ask the permission about its status.
        if (await Permission.location.isRestricted) {
           // The OS restricts access, for example because of parental controls.
        }
    
    Call `request()` on a `Permission` to request it. If it has already been granted before, nothing happens.
    

    request() 返回Permission 的新状态。

        if (await Permission.contacts.request().isGranted) {
          // Either the permission was already granted before or the user just granted it.
        }
    
        // You can request multiple permissions at once.
        Map<Permission, PermissionStatus> statuses = await [
          Permission.location,
          Permission.storage,
        ].request();
        print(statuses[Permission.location]);
    
    On Android, you can show a rationale for using permission:
    
        bool isShown = await Permission.contacts.shouldShowRequestRationale;
    

    完整示例

    Container(
      child: Wrap(
        children: <Widget>[
          ListTile(
              leading: Icon(Icons.camera_enhance),
              title: Text(getTranslated(context, "Camera")),
              onTap: () async {
                var status = await Permission.photos.status;
                if (status.isGranted) {
                  final pickedFile =
                      await _picker.getImage(source: ImageSource.camera);
                  final File file = File(pickedFile.path);
                  imageSelected(file);
                } else if (status.isDenied) {
                  final pickedFile =
                      await _picker.getImage(source: ImageSource.camera);
                  final File file = File(pickedFile.path);
                  imageSelected(file);
                } else {
                  showDialog(
                      context: context,
                      builder: (BuildContext context) => CupertinoAlertDialog(
                            title: Text('Camera Permission'),
                            content: Text(
                                'This app needs camera access to take pictures for upload user profile photo'),
                            actions: <Widget>[
                              CupertinoDialogAction(
                                child: Text('Deny'),
                                onPressed: () => Navigator.of(context).pop(),
                              ),
                              CupertinoDialogAction(
                                child: Text('Settings'),
                                onPressed: () => openAppSettings(),
                              ),
                            ],
                          ));
                }
              }),
        ],
      ),
    )
    

    【讨论】:

    • 谢谢你,我真的不知道如何同时获得 ios 和 android 的权限
    • 这个包有很多bug。你还有其他推荐吗?
    • @ykonda 我认为这不是错误,但实施和理解它的工作原理有点困难,但是一旦你很好地实施它,它就会完美地工作。如果您在实施时遗漏任何内容,它将无法完全发挥作用
    • @PareshMangukiya android 相机存在这个非常关键的问题github.com/Baseflow/flutter-permission-handler/issues/336
    • 根据@ykonda 在上面发布的 github 问题,截至今天(2021 年 1 月 28 日),最新版本 (5.0.1+1) 继续出现该问题
    【解决方案2】:

    我建议使用permission_handler 库并编写抽象代码(策略模式)以相同的方式处理所有权限。通常,文档很模糊,并且没有说明如何处理不可恢复/禁用场景。

    代码:

    /// handles .isLimited for iOS 14+ where we can restrict access.
    abstract class GrantPermissionStrategy {
      final Permission permission;
    
      GrantPermissionStrategy(this.permission);
    
      Future<void> request({
        required final OnPermanentlyDenied onPermanentlyDenied,
        required final OnGranted onGranted,
      }) async {
        PermissionStatus status = await permission.status;
        print("GrantPermissionStrategy status: $status");
    
        if (!status.isLimited && !status.isGranted) {
          final PermissionStatus result = await permission.request();
          if (result.isPermanentlyDenied) {
            onPermanentlyDenied.call();
            return;
          }
          if (!result.isGranted) {
            return;
          }
        }
        onGranted.call();
      }
    }
    
    typedef OnPermanentlyDenied = void Function();
    
    typedef OnGranted = void Function();
    
    
    

    而且,你可以做出具体的实现,比如:

    class GrantPermissionCameraStrategy extends GrantPermissionStrategy {
      GrantPermissionCameraStrategy() : super(Permission.camera);
    }
    
    class GrantPermissionPhotosStrategy extends GrantPermissionStrategy {
      GrantPermissionPhotosStrategy() : super(Platform.isAndroid ? Permission.storage : Permission.photos);
    }
    
    

    最后,调用它!:

        await GrantPermissionPhotosStrategy().request(onPermatentlyDenied: () {
          // launch dialog, make user go to app settings
        }, onGranted: () async {
          // we have passed! Launch the feature.
        });
      }
    

    【讨论】:

    • 检查 status.isPermanentlyDenied 不可靠来自 permission_handler: &gt;6.0.0。正如文档所述:WARNING: This can only be determined AFTER requesting this permission. Therefore make a request call first. 在此处阅读更多信息:github.com/Baseflow/flutter-permission-handler/issues/…
    • @DarkMikey 感谢您发现这一点。更新了代码。
    【解决方案3】:

    为简单起见,我使用了位置权限。要请求另一个权限,只需将 location 替换为该权限。这是list of all permissions。

    1。安卓设置:

    1. 将这些添加到android/grade.properties 文件中:

      android.useAndroidX=true
      android.enableJetifier=true
      
    2. 在android/app/build.gradle 文件中:

      android {
        compileSdkVersion 30 // Set this to at least 30
        ...
      }
      
    3. 给android/app/src/main/AndroidManifest.xml文件添加权限

      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 
        ...
       </manifest>
      

    2。 iOS 设置:

    1. 将此添加到info.plist 文件:

      <key>NSLocationWhenInUseUsageDescription</key>
      <string>App needs location permission to work</string>
      
    2. 将PERMISSION_LOCATION=1 添加到Podfile:

      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)',
      
              ## Add the following line.
               'PERMISSION_LOCATION=1'
            ]
      
          end
        end
      end
      

    3。颤振设置:

    将此添加到pubspec.yaml 文件中:

    permission_handler: ^8.0.0+2
    

    主要工作:

    • 检查权限:

      检查位置 aka GPS 是否开启。

      final serviceStatus = await Permission.locationWhenInUse.serviceStatus;
      bool isGpsOn = serviceStatus == ServiceStatus.enabled;
      
    • 请求许可:

      final status = await Permission.locationWhenInUse.request();
      if (status == PermissionStatus.granted) {
        print('Permission granted');
      } else if (status == PermissionStatus.denied) {
        print('Denied. Show a dialog with a reason and again ask for the permission.');
      } else if (status == PermissionStatus.permanentlyDenied) {
        print('Take the user to the settings page.');
      }
      

    完整代码:

    class HomePage extends StatelessWidget {
      Future<void> _checkPermission() async {
        final serviceStatus = await Permission.locationWhenInUse.serviceStatus;
        final isGpsOn = serviceStatus == ServiceStatus.enabled;
        if (!isGpsOn) {
          print('Turn on location services before requesting permission.');
          return;
        }
    
        final status = await Permission.locationWhenInUse.request();
        if (status == PermissionStatus.granted) {
          print('Permission granted');
        } else if (status == PermissionStatus.denied) {
          print('Permission denied. Show a dialog and again ask for the permission');
        } else if (status == PermissionStatus.permanentlyDenied) {
          print('Take the user to the settings page.');
          await openAppSettings();
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: ElevatedButton(
              onPressed: _checkPermission,
              child: Text('Check Permission'),
            ),
          ),
        );
      }
    }
    

    【讨论】:

    • 这不适用于 Android 10,您可能还需要更新 MainActivity.kt 或 MainActivity.java
    • @AnthonyO 它适用于所有 Android 版本。我自己在 Android 10 上对其进行了测试。您无需向任何文件的MainActivity 添加任何内容。
    • @CopsOnRoad 你是个聪明人,你的一些回答对我帮助很大。谢谢你帮助别人。你的答案是正确的答案。当我们使用 [var status = await Permission.photos.status ] 出现错误时,我们必须使用 [var status = await Permission.photos.request();]
    猜你喜欢
    • 1970-01-01
    • 2017-09-26
    • 2018-05-31
    • 2021-11-01
    • 2020-07-20
    • 2020-06-04
    • 1970-01-01
    • 2019-09-03
    • 2020-07-31
    相关资源
    最近更新 更多