permissionRequestPage.dart 8.26 KB
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:wow_english/common/core/app_config_helper.dart';

import '../../utils/log_util.dart';

/// 带隐私合规功能的权限检查及请求
/// 外部可通过此方法来进行权限的检查和请求,将自动跳转到`PermissionRequestPage`页面。
/// 传入 `Permission` 以及对应的权限名称 `permissionTypeStr`,如果有权限则返回 `Future true`
/// `isRequiredPermission` 如果为 `true`,则 "取消" 按钮将执行 "退出app" 的操作
Future<bool> permissionCheckAndRequests(
    BuildContext context,
    List<Permission> permissions,
    List<String> permissionTypeStrs,
    {bool isRequiredPermission = false}) async {

  // List<PermissionStatus> statuses = await Future.wait(
  //   permissions.map((permission) => permission.status),
  // );
  // bool allGranted = statuses.every((status) => status.isGranted);

  bool allGranted = await isPermissionsGranted(permissions);
    if (allGranted) {
      return true;
    } else {
      return await Navigator.of(context).push(PageRouteBuilder(
          opaque: false,
          pageBuilder: ((context, animation, secondaryAnimation) {
            return PermissionRequestPage(permissions, permissionTypeStrs,
                isRequiredPermission: isRequiredPermission);
          })));
    }
}

Future<bool> permissionCheckAndRequest(
    BuildContext context,
    Permission permission,
    String permissionTypeStr,
    {bool isRequiredPermission = false}) async {
  return permissionCheckAndRequests(context, [permission], [permissionTypeStr],
      isRequiredPermission: isRequiredPermission);
    }

///判断权限数组是否都授予
Future<bool> isPermissionsGranted(List<Permission> permissions) async {
  // 使用 every 直接检查权限状态
  return await Future.wait(permissions.map((permission) async {
    return await permission.status.isGranted;
  })).then((statuses) => statuses.every((status) => status));
}

///请求权限
Future<MapEntry<Permission, PermissionStatus>?> requestPermissions(List<Permission> permissionList) async {
  Map<Permission, PermissionStatus> statusesMap = await permissionList.request();
  for (var entry in statusesMap.entries) {
    if (!entry.value.isGranted) {
      return entry;
    }
  }
  return null;
}

class PermissionRequestPage extends StatefulWidget {
  const PermissionRequestPage(this.permissions, this.permissionTypeStrs,
      {super.key, this.isRequiredPermission = false});

  final List<Permission> permissions;
  final List<String> permissionTypeStrs;
  ///是否需要强制授予
  final bool isRequiredPermission;

  @override
  State<PermissionRequestPage> createState() => _PermissionRequestPageState();
}

class _PermissionRequestPageState extends State<PermissionRequestPage>
    with WidgetsBindingObserver {
  bool _isGoSetting = false;
  late final List<String> msgList;
  bool _isDialogShowing = false;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    String permissionTypeStrs = widget.permissionTypeStrs.join('、');
    msgList = [
      "Wow English需要获取您设备的$permissionTypeStrs权限,否则可能无法正常工作。\n是否同意授予?",
      "$permissionTypeStrs权限不全,是否重新申请权限?",
      "没有$permissionTypeStrs权限,您可以手动开启权限",
      widget.isRequiredPermission ? "退出应用" : "取消"
    ];
    _handlePermission(widget.permissions);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    Log.d("didChangeAppLifecycleState state=$state _isGoSetting=$_isGoSetting");
    // 监听 app 从后台切回前台
    if (state == AppLifecycleState.resumed && _isGoSetting) {
      _handlePermission(widget.permissions);
    }
  }

  /// 校验权限
  void _handlePermission(List<Permission> permissions) async {
    ///一个新待申请权限列表
    List<Permission> intentPermissionList = [];

    ///遍历当前权限申请列表
    for (Permission permission in permissions) {
      PermissionStatus status = await permission.status;

      ///如果不是允许状态就添加到新的申请列表中
      if (!status.isGranted) {
        intentPermissionList.add(permission);
      }
    }

    if (intentPermissionList.isEmpty) {
      _popPage(true);
    } else {
      _requestPermission(intentPermissionList);
    }
  }

  ///实际触发请求权限
  Future<void> _requestPermission(List<Permission> permissions) async {
    Log.d('_requestPermission permissions=$permissions');
    if (await isPermissionsGranted(permissions)) {
      _popPage(true);
      return;
    }

    MapEntry<Permission, PermissionStatus>? statusEntry = await requestPermissions(permissions);
    if (statusEntry == null) {
      ///都手动同意授予了
      _popPage(true);
      return;
    }

    Permission permission = statusEntry.key;
    PermissionStatus status = statusEntry.value;
    // 还未申请权限或之前拒绝了权限(在 iOS 上为首次申请权限,拒绝后将变为 `永久拒绝权限`)
    if (status.isDenied) {
      showAlert(
          permission, msgList[0], msgList[3], _isGoSetting ? "前往系统设置" : "确定");
    }
    // 权限已被永久拒绝
    /// 在 Android 上:Android 11+ (API 30+):用户是否第二次拒绝权限。低于 Android 11 (API 30):用户是否拒绝访问请求的功能,并选择不再显示请求。
    /// 在 iOS 上:如果用户拒绝访问所请求的功能。
    if (status.isPermanentlyDenied) {
      _isGoSetting = true;
      showAlert(
          permission, msgList[2], msgList[3], _isGoSetting ? "前往系统设置" : "确定");
    }
    // 拥有部分权限(受限,仅在 iOS (iOS14+) 上受支持)
    if (status.isLimited) {
      if (Platform.isIOS || Platform.isMacOS) _isGoSetting = true;
      showAlert(
          permission, msgList[1], msgList[3], _isGoSetting ? "前往系统设置" : "确定");
    }
    // 拥有部分权限,活动限制(例如,设置了家长///控件,仅在iOS以上受支持。(仅限 iOS)
    if (status.isRestricted) {
      if (Platform.isIOS || Platform.isMacOS) _isGoSetting = true;
      showAlert(
          permission, msgList[1], msgList[3], _isGoSetting ? "前往系统设置" : "确定");
    }
  }

  void showAlert(Permission permission, String message, String cancelMsg,
      String confirmMsg) {
    if (_isDialogShowing) {
      // 对话框已经在显示中,不重复弹出
      Log.d("对话框已经在显示中,不重复弹出");
      return;
    }
    _isDialogShowing = true;
    showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: const Text("温馨提示"),
            content: Text(message),
            actions: [
              TextButton(
                  child: Text(cancelMsg),
                  onPressed: () {
                    widget.isRequiredPermission
                        ? _quitApp()
                        : _popDialogAndPage(context, false);
                  }),
              TextButton(
                  child: Text(confirmMsg),
                  onPressed: () {
                    if (_isGoSetting) {
                      openAppSettings();
                    } else {
                      _handlePermission(widget.permissions);
                    }
                    _popDialog(context);
                  })
            ],
          );
        }).then((value) => {
          _isDialogShowing = false,
    });
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }

  /// 退出应用程序
  void _quitApp() {
    AppConfigHelper.exitApp();
  }

  /// 关闭整个权限申请页面
  void _popDialogAndPage(BuildContext dialogContext, bool isAllGranted) {
    _popDialog(dialogContext);
    _popPage(isAllGranted);
  }

  /// 关闭弹窗
  void _popDialog(BuildContext dialogContext) {
    Navigator.of(dialogContext).pop();
  }

  /// 关闭透明页面
  void _popPage(bool isAllGranted) {
    Navigator.of(context).pop(isAllGranted);
  }
}