Browse Source

feat(permission): (针对部分华为手机)添加权限拒绝次数统计和熔断机制

添加智能拒绝次数统计功能,当拒绝次数达到阈值时直接引导用户去设置
引入 GetStorage 持久化存储拒绝次数
新增重置拒绝次数和获取当前拒绝次数的方法
优化权限请求流程,在授权时自动清零拒绝记录
newdev_shunjiawei
lxm 1 year ago
parent
commit
6afbd5d622
  1. 120
      lib/core/utils/permission_util.dart

120
lib/core/utils/permission_util.dart

@ -3,6 +3,7 @@ import 'package:permission_handler/permission_handler.dart';
import 'package:app_settings/app_settings.dart'; import 'package:app_settings/app_settings.dart';
import 'logger.dart'; import 'logger.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
/// 权限请求工具类 /// 权限请求工具类
/// ///
@ -11,6 +12,7 @@ import 'package:get/get.dart';
/// 2. 权限解释横幅显示(悬浮在UI顶部的解释性UI) /// 2. 权限解释横幅显示(悬浮在UI顶部的解释性UI)
/// 3. 权限请求执行 /// 3. 权限请求执行
/// 4. 永久拒绝后的设置引导 /// 4. 永久拒绝后的设置引导
/// 5. 智能拒绝次数统计和熔断机制
/// ///
/// 使用单例模式:`PermissionUtil.instance` /// 使用单例模式:`PermissionUtil.instance`
@ -24,6 +26,30 @@ class PermissionUtil {
/// 权限解释横幅的叠加层入口 /// 权限解释横幅的叠加层入口
//OverlayEntry? _explanationOverlayEntry; //OverlayEntry? _explanationOverlayEntry;
/// 引入 get_storage 用于持久化权限拒绝次数
final _storage = GetStorage();
/// 权限拒绝次数阈值(达到此次数后视为永久拒绝)
static const int _denialThreshold = 2;
/// 获取权限拒绝次数的存储键
String _getDenialCountKey(Permission permission) {
return 'permission_denial_count_${permission.toString()}';
}
/// 重置指定权限的拒绝次数
///
/// 在某些场景下可能需要手动重置拒绝次数,比如用户主动要求重新请求权限
Future<void> resetDenialCount(Permission permissionType) async {
await _storage.remove(_getDenialCountKey(permissionType));
Logger.d('PermissionUtil', '已重置 ${permissionType.toString()} 的拒绝次数');
}
/// 获取指定权限的拒绝次数
int getDenialCount(Permission permissionType) {
return _storage.read<int>(_getDenialCountKey(permissionType)) ?? 0;
}
/// 请求指定权限 /// 请求指定权限
/// ///
/// 参数: /// 参数:
@ -59,34 +85,75 @@ class PermissionUtil {
if (status == PermissionStatus.granted || if (status == PermissionStatus.granted ||
status == PermissionStatus.provisional) { status == PermissionStatus.provisional) {
Logger.i('PermissionUtil', '$permissionName 权限已授予或临时授权'); Logger.i('PermissionUtil', '$permissionName 权限已授予或临时授权');
// 如果已经授权,清零之前的拒绝记录,以防用户在设置中开启后又关闭
await _storage.remove(_getDenialCountKey(permissionType));
return true; return true;
} }
// 显示权限解释横幅(覆盖所有状态的处理) // 2. 读取历史拒绝次数
_showExplanationOverlay( final denialCountKey = _getDenialCountKey(permissionType);
//context: context, int denialCount = _storage.read<int>(denialCountKey) ?? 0;
permissionName: permissionName, Logger.d('PermissionUtil', '$permissionName 当前拒绝次数: $denialCount');
explanationText: explanationText,
);
// 处理永久拒绝状态(先显示说明横幅,再引导用户去设置) // 3. 熔断机制:如果拒绝次数达到阈值或系统返回了 permanentlyDenied,直接视为永久拒绝
if (status == PermissionStatus.permanentlyDenied) { if (denialCount >= _denialThreshold ||
Logger.w('PermissionUtil', '$permissionName 权限被永久拒绝,显示引导对话框'); status == PermissionStatus.permanentlyDenied) {
Logger.w('PermissionUtil',
'$permissionName 已被拒绝 $denialCount 次或被系统永久拒绝,触发设置引导');
// 显示永久拒绝对话框(在解释横幅下方显示) // 显示权限解释横幅
_showExplanationOverlay(
permissionName: permissionName,
explanationText: explanationText,
);
// 显示引导去设置的对话框
final result = await _showPermanentDenialDialog( final result = await _showPermanentDenialDialog(
// context: context,
permissionName: permissionName, permissionName: permissionName,
permanentDenialText: permanentDenialText, permanentDenialText: permanentDenialText,
settingsButtonText: finalSettingsButtonText, settingsButtonText: finalSettingsButtonText,
cancelButtonText: finalCancelButtonText, cancelButtonText: finalCancelButtonText,
); );
// 移除解释横幅 // 移除解释横幅
_hideExplanationOverlay(); _hideExplanationOverlay();
return result; return result;
} }
// 处理初始拒绝/未决定状态 // 显示权限解释横幅(覆盖所有状态的处理)
_showExplanationOverlay(
//context: context,
permissionName: permissionName,
explanationText: explanationText,
);
// 处理永久拒绝状态(先显示说明横幅,再引导用户去设置)
// if (status == PermissionStatus.permanentlyDenied) {
// Logger.w('PermissionUtil', '$permissionName 权限被永久拒绝,显示引导对话框');
// // 显示永久拒绝对话框(在解释横幅下方显示)
// final result = await _showPermanentDenialDialog(
// // context: context,
// permissionName: permissionName,
// permanentDenialText: permanentDenialText,
// settingsButtonText: finalSettingsButtonText,
// cancelButtonText: finalCancelButtonText,
// );
// // 移除解释横幅
// _hideExplanationOverlay();
// return result;
// }
// 处理受限状态
if (status == PermissionStatus.restricted ||
status == PermissionStatus.limited) {
Logger.w('PermissionUtil', '$permissionName 权限受限或受限访问: $status');
await _showRestrictedPermissionDialog(permissionName);
_hideExplanationOverlay();
return false;
}
// 处理初始拒绝/未决定状态(真正的权限请求)
if (status == PermissionStatus.denied) { if (status == PermissionStatus.denied) {
Logger.d('PermissionUtil', '$permissionName 权限被拒绝或未决定,显示说明横幅并请求'); Logger.d('PermissionUtil', '$permissionName 权限被拒绝或未决定,显示说明横幅并请求');
// _showExplanationOverlay( // _showExplanationOverlay(
@ -94,19 +161,22 @@ class PermissionUtil {
// permissionName: permissionName, // permissionName: permissionName,
// explanationText: explanationText, // explanationText: explanationText,
// ); // );
//请求权限 //请求权限
final PermissionStatus newStatus = await permissionType.request(); final PermissionStatus newStatus = await permissionType.request();
Logger.d('PermissionUtil', '请求后 $permissionName 的新权限状态: $newStatus'); Logger.d('PermissionUtil', '请求后 $permissionName 的新权限状态: $newStatus');
//_hideExplanationOverlay(); //_hideExplanationOverlay();
// 处理请求后的状态 // 5. 根据结果更新状态和拒绝次数
if (newStatus == PermissionStatus.granted || if (newStatus == PermissionStatus.granted ||
newStatus == PermissionStatus.provisional) { newStatus == PermissionStatus.provisional) {
Logger.i('PermissionUtil', '$permissionName 权限在请求后被授予'); Logger.i('PermissionUtil', '$permissionName 权限在请求后被授予');
// 授权成功,清零拒绝次数
await _storage.remove(denialCountKey);
_hideExplanationOverlay(); _hideExplanationOverlay();
return true; return true;
} }
// 处理请求后变为永久拒绝 // 处理请求后变为永久拒绝
else if (newStatus == PermissionStatus.permanentlyDenied) { else if (newStatus == PermissionStatus.permanentlyDenied) {
Logger.w('PermissionUtil', '$permissionName 权限在请求后被永久拒绝'); Logger.w('PermissionUtil', '$permissionName 权限在请求后被永久拒绝');
@ -120,18 +190,16 @@ class PermissionUtil {
_hideExplanationOverlay(); _hideExplanationOverlay();
return result; return result;
} }
// 其他拒绝状态 // 如果执行到这里,说明权限被拒绝了 (denied)
_hideExplanationOverlay(); else {
return false; Logger.w('PermissionUtil', '$permissionName 权限被拒绝');
} // 拒绝次数 +1
await _storage.write(denialCountKey, denialCount + 1);
// 处理受限状态 Logger.d(
if (status == PermissionStatus.restricted || 'PermissionUtil', '$permissionName 拒绝次数更新为: ${denialCount + 1}');
status == PermissionStatus.limited) { _hideExplanationOverlay();
Logger.w('PermissionUtil', '$permissionName 权限受限或受限访问: $status'); return false;
await _showRestrictedPermissionDialog(permissionName); }
_hideExplanationOverlay();
return false;
} }
// 其他未知状态处理 // 其他未知状态处理

Loading…
Cancel
Save