Flutter开发之动态权限

37次阅读

共计 5861 个字符,预计需要花费 15 分钟才能阅读完成。

众所周知,Android 在 6.0 版本后将权限修改成了动态权限,而 iOS 则一直使用的是动态权限,所以在 Flutter 应用开发中如果涉及到一些危险权限,就需要进行动态申请,动态申请权限可以使用 Flutter 的 permission_handler。

基本使用

1,配置权限

首先,打开 Android 工程下的 AndroidManifest.xml 文件,具体路径如下:在 androidappsrcmainAndroidManifest.xml 中配置,然后添加如下所示的权限。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.kill_attendance">
        <!-- 申请 Android 权限 -->
    <!-- 网络访问 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

    <!-- Permissions options for the `contacts` group -->
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />

    <!-- Permissions options for the `storage` group -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <!-- Permissions options for the `camera` group -->
    <uses-permission android:name="android.permission.CAMERA" />

    <!-- Permissions options for the `location` group -->
    <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" />

    <!-- Permissions options for the `microphone` or `speech` group -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
         <!-- app 名称, 图标 -->
    <application
        android:name="io.flutter.app.FlutterApplication"
        android:label="应用名称"
        android:icon="@mipmap/icon">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- This keeps the window background of the activity showing
                 until Flutter renders its first frame. It can be removed if
                 there is no splash screen (such as the default splash screen
                 defined in @style/LaunchTheme). -->
            <meta-data
                android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
                android:value="true" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

动态权限申请

目前,这个插件已经升级了好几版,而不同版本处理方法也不一样,特别是最新的 5.0.0 版本和之前的版本,用法差别比较大。

4.3.0

例如,下面是 4.3.0 版本的用法:

  • 权限列表:PermissionGroup 中的字段
  • 权限状态列表:PermissionStatus 中字段
  • 打开权限设置页面:await PermissionHandler().openAppSettings();
  • 申请权限

示例如下:

await Map<PermissionGroup, PermissionStatus> map= PermissionHandler().requestPermissions([ 权限列表])

然后,是获取申请权限的状态,如下:

PermissionStatus contactsPermStatus = await PermissionHandler().checkPermissionStatus(PermissionGroup.contacts);

下面是一个完整的示例:

  /// 请求权限
  void _requestPermission() async {debugPrint("进入闪屏页面");
    // 申请权限
    // PermissionStatus storageStatus ;
    PermissionStatus cameraStatus;

     await PermissionHandler().requestPermissions([ PermissionGroup.camera]).then((value) {debugPrint("返回:$value");
            // storageStatus=value[PermissionGroup.storage];
            cameraStatus=value[PermissionGroup.camera];
          });
    debugPrint("请求权限, 并获取权限:$cameraStatus");

    // 校验权限
    if (cameraStatus == PermissionStatus.granted) {debugPrint("校验权限: 用户都同意了");
      // 用户都同意了 (用 &&)
      /// 权限都申请成功初始化闪屏
      _initSplash();} else if (cameraStatus == PermissionStatus.denied) {debugPrint("校验权限: 有任何一组权限被用户拒绝");
      // 用户拒绝了 (用 ||)
      /// 有任何一组权限被用户拒绝
      // 拼接提示权限文本
      StringBuffer sb = new StringBuffer();
      sb.write(cameraStatus == PermissionStatus.denied ? "相机," : "");
      String tip = Utils.removePostfix(sb.toString(), ",");

      Utils.showCustomDialog(
          context,
          ConfirmDialog("您拒绝了应用的必要权限:\n[$tip], 是否重新申请?",
            canBackDismiss: false,
            confirmCallback: () => _requestPermission(),
            cancelCallback: () => SystemNavigator.pop(),
          ));
    } else if (cameraStatus == PermissionStatus.neverAskAgain) {debugPrint("校验权限: 有权限永久拒绝");
      // 有权限永久拒绝 (用 ||)
      /// 有任何一组权限选了不再提示
      // 拼接提示权限文本
      StringBuffer sb = new StringBuffer();
      sb.write(cameraStatus == PermissionStatus.neverAskAgain ? "相机," : "");
      String tip = Utils.removePostfix(sb.toString(), ",");

      Utils.showCustomDialog(
          context,
          ConfirmDialog("您禁用了应用的必要权限:\n[$tip], 请到设置里允许?",
            canBackDismiss: false,
            confirmText: "去设置",
            confirmCallback: () async {await PermissionHandler().openAppSettings(); // 打开设置页面
              SystemNavigator.pop();},
            cancelCallback: () => SystemNavigator.pop(),
          ));
    }

  }

效果图如下:

5.0.0

5.0.0 版本和之前的写法大体类似,只是方法和参数字段发生了改变,如下所示。

  • 权限列表:Permission 中的字段
  • 权限状态列表:PermissionStatus 中字段
  • 打开权限设置页面:openAppSettings();
  • 申请权限
await [权限列表].request();   // 可以使用 then, 用权限获取状态 
  • 获取权限状态 await Permission.camera.status
  • 判断权限状态:await Permission.camera.isDenied|isGranted 等

下面是详细的使用示例:

  /// 请求权限
  void _requestPermission() async {debugPrint("进入闪屏页面");
    // 申请权限
    // PermissionStatus cameraStatus;

    await [Permission.camera].request();
    // .then((value){
      // 设置申请后的结果
        // cameraStatus=value[Permission.camera];
      // });
    // 或者直接调用:
    debugPrint("请求权限, 并获取权限");
    if(await Permission.camera.isDenied){ }
    
    // 校验权限
    if (await Permission.camera.isGranted) {debugPrint("校验权限: 用户都同意了");
      // 用户都同意了 (用 &&)
      /// 权限都申请成功初始化闪屏
      _initSplash();} else if (await Permission.camera.isDenied) {debugPrint("校验权限: 有任何一组权限被用户拒绝");
      // 用户拒绝了 (用 ||)
      /// 有任何一组权限被用户拒绝
      // 拼接提示权限文本
      StringBuffer sb = new StringBuffer();
      sb.write(await Permission.camera.isDenied? "相机," : "");
      String tip = Utils.removePostfix(sb.toString(), ",");

      Utils.showCustomDialog(
          context,
          ConfirmDialog("您拒绝了应用的必要权限:\n[$tip], 是否重新申请?",
            canBackDismiss: false,
            confirmCallback: () => _requestPermission(),
            cancelCallback: () => SystemNavigator.pop(),
          ));
    } else if (await Permission.camera.isPermanentlyDenied) {debugPrint("校验权限: 有权限永久拒绝");
      // 有权限永久拒绝 (用 ||)
      /// 有任何一组权限选了不再提示
      // 拼接提示权限文本
      StringBuffer sb = new StringBuffer();
      sb.write(await Permission.camera.isPermanentlyDenied ? "相机," : "");
      String tip = Utils.removePostfix(sb.toString(), ",");

      Utils.showCustomDialog(
          context,
          ConfirmDialog("您禁用了应用的必要权限:\n[$tip], 请到设置里允许?",
            canBackDismiss: false,
            confirmText: "去设置",
            confirmCallback: () async {await openAppSettings(); // 打开设置页面
              SystemNavigator.pop();},
            cancelCallback: () => SystemNavigator.pop(),
          ));
    }

  }

参考:permission_handler

正文完
 0