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 permissionCheckAndRequests( BuildContext context, List permissions, List permissionTypeStrs, {bool isRequiredPermission = false}) async { // List 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 permissionCheckAndRequest( BuildContext context, Permission permission, String permissionTypeStr, {bool isRequiredPermission = false}) async { return permissionCheckAndRequests(context, [permission], [permissionTypeStr], isRequiredPermission: isRequiredPermission); } ///判断权限数组是否都授予 Future isPermissionsGranted(List permissions) async { // 使用 every 直接检查权限状态 return await Future.wait(permissions.map((permission) async { return await permission.status.isGranted; })).then((statuses) => statuses.every((status) => status)); } ///请求权限 Future?> requestPermissions(List permissionList) async { Map 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 permissions; final List permissionTypeStrs; ///是否需要强制授予 final bool isRequiredPermission; @override State createState() => _PermissionRequestPageState(); } class _PermissionRequestPageState extends State with WidgetsBindingObserver { bool _isGoSetting = false; late final List 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 permissions) async { ///一个新待申请权限列表 List 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 _requestPermission(List permissions) async { Log.d('_requestPermission permissions=$permissions'); if (await isPermissionsGranted(permissions)) { _popPage(true); return; } MapEntry? 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); } }