Browse Source

refactor(permission): 优化权限请求逻辑并移除冗余代码

- 重构权限请求流程,简化状态处理逻辑
- 移除未使用的注释代码和冗余方法
- 改进权限横幅显示和隐藏的可靠性
- 使用更清晰的权限状态检查方法
weicu
lxm 1 year ago
parent
commit
8532c4efad
  1. 263
      lib/core/utils/permission_util.dart

263
lib/core/utils/permission_util.dart

@ -23,9 +23,6 @@ class PermissionUtil {
/// 私有构造函数 /// 私有构造函数
PermissionUtil._(); PermissionUtil._();
/// 权限解释横幅的叠加层入口
//OverlayEntry? _explanationOverlayEntry;
/// 引入 get_storage 用于持久化权限拒绝次数 /// 引入 get_storage 用于持久化权限拒绝次数
final _storage = GetStorage(); final _storage = GetStorage();
@ -63,7 +60,6 @@ class PermissionUtil {
/// ///
/// 返回值:`Future<bool>` 权限是否最终授予 /// 返回值:`Future<bool>` 权限是否最终授予
Future<bool> requestPermission({ Future<bool> requestPermission({
// required BuildContext context,
required Permission permissionType, required Permission permissionType,
required String permissionName, required String permissionName,
required String explanationText, required String explanationText,
@ -75,145 +71,82 @@ class PermissionUtil {
final String finalSettingsButtonText = final String finalSettingsButtonText =
settingsButtonText ?? 'goToSettings'.tr; settingsButtonText ?? 'goToSettings'.tr;
final String finalCancelButtonText = cancelButtonText ?? 'cancel'.tr; final String finalCancelButtonText = cancelButtonText ?? 'cancel'.tr;
bool isOverlayShown = false;
try { try {
// 检查初始权限状态 // 检查初始权限状态
final PermissionStatus status = await permissionType.status; PermissionStatus status = await permissionType.status;
Logger.d('PermissionUtil', '初始权限状态 [$permissionName]: $status'); Logger.d('PermissionUtil', '初始权限状态 [$permissionName]: $status');
// 处理已授权状态(包括授予状态和临时通知权限) // 1. <--- 已授权处理 --->(包括授予状态和临时通知权限)
if (status == PermissionStatus.granted || if (status.isGranted) {
status == PermissionStatus.provisional) { Logger.i('PermissionUtil', '$permissionName 权限已授予或临时授予');
Logger.i('PermissionUtil', '$permissionName 权限已授予或临时授权');
// 如果已经授权,清零之前的拒绝记录,以防用户在设置中开启后又关闭 // 如果已经授权,清零之前的拒绝记录,以防用户在设置中开启后又关闭
await _storage.remove(_getDenialCountKey(permissionType)); await resetDenialCount(permissionType); // 清零拒绝记录
return true; return true;
} }
// 2. 读取历史拒绝次数 // 2. <--- 熔断机制:检查我们自己的拒绝次数 --->
final denialCountKey = _getDenialCountKey(permissionType); final denialCount = getDenialCount(permissionType);
int denialCount = _storage.read<int>(denialCountKey) ?? 0;
Logger.d('PermissionUtil', '$permissionName 当前拒绝次数: $denialCount'); Logger.d('PermissionUtil', '$permissionName 当前拒绝次数: $denialCount');
// 如果拒绝次数达到阈值或系统返回了 permanentlyDenied,直接视为永久拒绝
// 3. 熔断机制:如果拒绝次数达到阈值或系统返回了 permanentlyDenied,直接视为永久拒绝 if (status.isPermanentlyDenied || denialCount >= _denialThreshold) {
if (denialCount >= _denialThreshold || Logger.w('PermissionUtil', '$permissionName 已被系统永久拒绝或自定义计数达到阈值($denialCount),触发设置引导');
status == PermissionStatus.permanentlyDenied) { await _showPermanentDenialDialog(
Logger.w('PermissionUtil',
'$permissionName 已被拒绝 $denialCount 次或被系统永久拒绝,触发设置引导');
// 显示权限解释横幅
_showExplanationOverlay(
permissionName: permissionName,
explanationText: explanationText,
);
// 显示引导去设置的对话框
final result = await _showPermanentDenialDialog(
permissionName: permissionName, permissionName: permissionName,
permanentDenialText: permanentDenialText, permanentDenialText: permanentDenialText,
settingsButtonText: finalSettingsButtonText, settingsButtonText: finalSettingsButtonText,
cancelButtonText: finalCancelButtonText, cancelButtonText: finalCancelButtonText,
); );
// 引导用户后,返回false,因为权限当前未被授予
// 移除解释横幅 return false;
_hideExplanationOverlay();
return result;
} }
// 显示权限解释横幅(覆盖所有状态的处理) // 3. <--- 发起正常的权限请求 (此时 status 必然是 denied 或受限) --->
_showExplanationOverlay( _showExplanationOverlay(
//context: context,
permissionName: permissionName, permissionName: permissionName,
explanationText: explanationText, explanationText: explanationText,
); );
isOverlayShown = true;
// 处理永久拒绝状态(先显示说明横幅,再引导用户去设置)
// 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;
// }
// 处理受限状态 final PermissionStatus newStatus = await permissionType.request();
if (status == PermissionStatus.restricted || Logger.d('PermissionUtil', '请求后 $permissionName 的新权限状态: $newStatus');
status == PermissionStatus.limited) {
Logger.w('PermissionUtil', '$permissionName 权限受限或受限访问: $status');
await _showRestrictedPermissionDialog(permissionName);
_hideExplanationOverlay();
return false;
}
// 处理初始拒绝/未决定状态(真正的权限请求) _hideExplanationOverlay();
if (status == PermissionStatus.denied) { isOverlayShown = false;
Logger.d('PermissionUtil', '$permissionName 权限被拒绝或未决定,显示说明横幅并请求');
// _showExplanationOverlay(
// context: context,
// permissionName: permissionName,
// explanationText: explanationText,
// );
//请求权限
final PermissionStatus newStatus = await permissionType.request();
Logger.d('PermissionUtil', '请求后 $permissionName 的新权限状态: $newStatus');
//_hideExplanationOverlay(); // 4. <--- 处理请求后的结果 --->
if (newStatus.isGranted) {
Logger.i('PermissionUtil', '$permissionName 权限在请求后被授予');
await resetDenialCount(permissionType); // 授权成功,清零
return true;
}
// 5. 根据结果更新状态和拒绝次数 if (newStatus.isPermanentlyDenied) {
if (newStatus == PermissionStatus.granted || Logger.w('PermissionUtil', '$permissionName 权限在请求后被系统永久拒绝');
newStatus == PermissionStatus.provisional) { await _showPermanentDenialDialog(
Logger.i('PermissionUtil', '$permissionName 权限在请求后被授予'); permissionName: permissionName,
// 授权成功,清零拒绝次数 permanentDenialText: permanentDenialText,
await _storage.remove(denialCountKey); settingsButtonText: finalSettingsButtonText,
_hideExplanationOverlay(); cancelButtonText: finalCancelButtonText,
return true; );
} return false;
}
// 处理请求后变为永久拒绝 if (newStatus.isDenied) {
else if (newStatus == PermissionStatus.permanentlyDenied) { Logger.w('PermissionUtil', '$permissionName 权限被拒绝,增加拒绝计数');
Logger.w('PermissionUtil', '$permissionName 权限在请求后被永久拒绝'); await _storage.write(_getDenialCountKey(permissionType), denialCount + 1);
final result = await _showPermanentDenialDialog(
// context: context,
permissionName: permissionName,
permanentDenialText: permanentDenialText,
settingsButtonText: finalSettingsButtonText,
cancelButtonText: finalCancelButtonText,
);
_hideExplanationOverlay();
return result;
}
// 如果执行到这里,说明权限被拒绝了 (denied)
else {
Logger.w('PermissionUtil', '$permissionName 权限被拒绝');
// 拒绝次数 +1
await _storage.write(denialCountKey, denialCount + 1);
Logger.d(
'PermissionUtil', '$permissionName 拒绝次数更新为: ${denialCount + 1}');
_hideExplanationOverlay();
return false;
}
} }
// 其他未知状态处理 // 所有未授权的情况最终都返回 false
Logger.e('PermissionUtil', '$permissionName 处于未知状态: $status');
_hideExplanationOverlay();
return false; return false;
} catch (e, stackTrace) { } catch (e, stackTrace) {
Logger.e( Logger.e('PermissionUtil', '请求 $permissionName 权限失败: $e', e, stackTrace);
'PermissionUtil', if (isOverlayShown) {
'请求 $permissionName 权限失败: $e', _hideExplanationOverlay();
e, }
stackTrace,
);
_hideExplanationOverlay();
return false; return false;
} }
} }
@ -236,7 +169,7 @@ class PermissionUtil {
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
elevation: 8, elevation: 8,
color: Colors.grey[300], color: Colors.grey[300],
shadowColor: Colors.black.withOpacity(0.3), shadowColor: Colors.black.withValues(alpha: 0.3),
child: Padding( child: Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Column( child: Column(
@ -264,64 +197,23 @@ class PermissionUtil {
), ),
], ],
), ),
// 防止用户通过点击背景关闭解释横幅
barrierDismissible: false,
); );
// _hideExplanationOverlay(); // 确保移除旧叠加层
// _explanationOverlayEntry = OverlayEntry(
// builder: (context) => Positioned(
// top: MediaQuery.of(context).padding.top + 10,
// left: 16,
// right: 16,
// child: Material(
// borderRadius: BorderRadius.circular(12),
// elevation: 8,
// color: Theme.of(context).colorScheme.background,
// shadowColor: Colors.black.withOpacity(0.3),
// child: Padding(
// padding: const EdgeInsets.all(16),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// '需要$permissionName权限',
// style: const TextStyle(
// fontWeight: FontWeight.bold,
// fontSize: 16,
// ),
// ),
// const SizedBox(height: 8),
// Text(
// explanationText,
// style: const TextStyle(fontSize: 14),
// ),
// ],
// ),
// ),
// ),
// ),
// );
// Future.delayed(Duration.zero, () {
// if (_explanationOverlayEntry != null) {
// Overlay.of(context).insert(_explanationOverlayEntry!);
// Logger.i('PermissionUtil', '权限说明叠加层已显示 ($permissionName)');
// }
// });
} }
/// 隐藏权限解释横幅 /// 隐藏权限解释横幅
void _hideExplanationOverlay() { void _hideExplanationOverlay() {
Get.back(); if (Get.isDialogOpen ?? false) {
//_explanationOverlayEntry!.remove(); Get.back();
Logger.d('PermissionUtil', '权限说明叠加层已移除'); Logger.d('PermissionUtil', '权限说明叠加层已移除');
}
} }
/// 显示永久拒绝后的设置引导对话框 /// 显示永久拒绝后的设置引导对话框
/// ///
/// 在权限被永久拒绝时调用,提示用户前往设置手动开启权限 /// 在权限被永久拒绝时调用,提示用户前往设置手动开启权限
Future<bool> _showPermanentDenialDialog({ Future<void> _showPermanentDenialDialog({
//required BuildContext context,
required String permissionName, required String permissionName,
required String permanentDenialText, required String permanentDenialText,
required String settingsButtonText, required String settingsButtonText,
@ -355,59 +247,10 @@ class PermissionUtil {
barrierDismissible: false, barrierDismissible: false,
); );
// bool? userChoice = await showDialog<bool>(
// context: context,
// barrierDismissible: false,
// builder: (context) =>
// );
// 用户选择前往设置
if (userChoice == true) { if (userChoice == true) {
AppSettings.openAppSettings(); AppSettings.openAppSettings();
return false; // 不能立即获取权限,需要用户手动设置
} }
// 用户取消
return false;
} }
/// 显示受限权限对话框 // 移除了多余的_showRestrictedPermissionDialog,因为永久拒绝流程已能覆盖
///
/// 在权限受限状态(如iOS上的受限照片访问)时调用
Future<void> _showRestrictedPermissionDialog(String permissionName) async {
Logger.w('PermissionUtil', '显示受限权限对话框 ($permissionName)');
Get.dialog(
AlertDialog(
title: Text(permissionName + 'permissionUtilRestricted'.tr),
content: Text('permissionUtilRestrictedMessage'.tr),
actions: [
TextButton(
onPressed: () {
Logger.d('PermissionUtil', '用户确认受限权限 ($permissionName)');
// Navigator.pop(context);
Get.back();
},
child: Text('permissionUtilConfirm'.tr),
),
],
),
);
// await showDialog(
// context: context,
// builder: (context) => AlertDialog(
// title: Text('$permissionName权限受限'),
// content: const Text('此功能在当前设备上不可用或受限,请检查设备设置或系统限制'),
// actions: [
// TextButton(
// onPressed: () {
// Logger.d('PermissionUtil', '用户确认受限权限 ($permissionName)');
// Navigator.pop(context);
// },
// child: const Text('确定'),
// ),
// ],
// ),
// );
}
} }

Loading…
Cancel
Save