You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

331 lines
11 KiB

import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter/material.dart';
import 'dart:io' show Platform;
import 'package:device_info_plus/device_info_plus.dart';
import '../../../core/utils/permission_util.dart';
class PermissionsController extends GetxController with WidgetsBindingObserver {
// 权限状态映射
final RxMap<Permission, PermissionStatus> permissionStatuses =
<Permission, PermissionStatus>{}.obs;
// 是否正在请求权限
final RxBool isRequestingPermission = false.obs;
// Android版本信息(用于权限组显示判断)
final RxInt androidSdkVersion = 0.obs;
final GetStorage _storage = GetStorage();
bool? _isCalendarFullAccess;
@override
void onInit() {
super.onInit();
_isCalendarFullAccess = _storage.read('record_permission_calendar');
_initAndroidVersion();
checkAllPermissions();
// 用户很可能从这个页面点"去设置"跳到系统设置页改权限,再切回来——
// 不监听 resume 的话,页面上显示的状态就停在跳出去那一刻,跟系统里
// 实际的授权状态对不上,得手动下拉刷新才会更新。
WidgetsBinding.instance.addObserver(this);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
checkAllPermissions();
}
}
@override
void onClose() {
WidgetsBinding.instance.removeObserver(this);
super.onClose();
}
/// 初始化Android版本信息
Future<void> _initAndroidVersion() async {
if (Platform.isAndroid) {
try {
final deviceInfo = DeviceInfoPlugin();
final androidInfo = await deviceInfo.androidInfo;
androidSdkVersion.value = androidInfo.version.sdkInt;
} catch (e) {
print('获取Android版本信息失败: $e');
androidSdkVersion.value = 0;
}
}
}
/// 检查是否应该显示蓝牙权限组
bool shouldShowBluetoothPermissions() {
if (Platform.isAndroid) {
// Android 12+ (API 31+) 才显示蓝牙权限组
return androidSdkVersion.value >= 31;
} else if (Platform.isIOS) {
// iOS显示蓝牙权限组
return true;
}
return false;
}
/// 检查是否应该显示存储权限组
bool shouldShowStoragePermissions() {
if (Platform.isAndroid) {
// Android 10及以下版本 (API 29及以下) 才显示存储权限组
return androidSdkVersion.value <= 29 && androidSdkVersion.value > 0;
}
// iOS系统不显示存储权限组
return false;
}
/// 检查所有权限状态
Future<Map<Permission, PermissionStatus>> checkAllPermissions() async {
final Map<Permission, PermissionStatus> statuses = {};
// 根据平台获取需要检查的权限列表
final permissions = await _getPlatformPermissions();
for (final permission in permissions) {
try {
if (Platform.isIOS &&
permission == Permission.calendarFullAccess &&
_isCalendarFullAccess == true) {
PermissionStatus calendarStatus = await permission.status;
if (calendarStatus == PermissionStatus.denied) {
statuses[permission] = PermissionStatus.granted;
} else {
statuses[permission] = await permission.status;
_storage.write('record_permission_calendar', false);
}
} else {
statuses[permission] = await permission.status;
}
print('Permission: $permission, Status: ${statuses[permission]}');
} catch (e) {
// 某些权限在特定平台可能不支持,设置为拒绝状态
statuses[permission] = PermissionStatus.denied;
}
}
permissionStatuses.value = statuses;
return statuses;
}
/// 获取蓝牙权限列表(根据Android版本)
Future<List<Permission>> _getBluetoothPermissions() async {
if (Platform.isAndroid) {
try {
final deviceInfo = DeviceInfoPlugin();
final androidInfo = await deviceInfo.androidInfo;
// Android 12+ (API 31+) 使用新的蓝牙权限
if (androidInfo.version.sdkInt >= 31) {
return [
Permission.bluetoothScan,
Permission.bluetoothConnect,
];
}
// Android 12以下不显示蓝牙权限(因为会自动授予)
return [];
} catch (e) {
print('获取Android版本信息失败: $e');
return [];
}
}
return [];
}
/// 获取平台特定的权限列表
Future<List<Permission>> _getPlatformPermissions() async {
final bluetoothPermissions = await _getBluetoothPermissions();
if (Platform.isIOS) {
final List<Permission> permissions = [
Permission.calendarFullAccess,
Permission.location,
//...bluetoothPermissions,
Permission.notification,
Permission.microphone,
];
// iOS系统不添加存储权限(根据shouldShowStoragePermissions方法)
if (shouldShowStoragePermissions()) {
permissions.add(Permission.storage);
}
return permissions;
} else if (Platform.isAndroid) {
final List<Permission> permissions = [
Permission.calendarFullAccess,
Permission.location,
...bluetoothPermissions,
Permission.notification,
Permission.scheduleExactAlarm,
Permission.microphone,
];
// 只在Android 10及以下版本添加存储权限
if (shouldShowStoragePermissions()) {
permissions.add(Permission.storage);
}
return permissions;
}
return [];
}
/// 请求单个权限
///
/// 这是全 App 唯一允许绕过 48h 拒绝冷却的入口:用户是自己走进「权限管理」页、
/// 自己点的这一条,属于用户主动索要权限,不是 App 骚扰用户,
/// 因此传 userInitiated: true(详见 PermissionUtil 类注释)。
Future<bool> requestPermission(Permission permission) async {
if (isRequestingPermission.value) return false;
isRequestingPermission.value = true;
try {
final permissionName = getPermissionName(permission);
final explanationText = _getDetailedDescription(permission);
final hasPermission = await PermissionUtil.instance.requestPermission(
permissionType: permission,
permissionName: permissionName,
explanationText: explanationText,
permanentDenialText:
'permanentDenialText'.tr.replaceAll('{permission}', permissionName),
settingsButtonText: 'goToSettings'.tr,
cancelButtonText: 'cancel'.tr,
userInitiated: true,
);
if (hasPermission) {
// _showSuccessMessage();
if (Platform.isIOS && permission == Permission.calendarFullAccess) {
if (_isCalendarFullAccess == null) {
_storage.write('record_permission_calendar', true);
_isCalendarFullAccess = true;
}
}
}
// 刷新权限状态
await checkAllPermissions();
return hasPermission;
} catch (e) {
_showErrorMessage();
return false;
} finally {
isRequestingPermission.value = false;
}
}
/// 打开系统设置
void openSettings() {
openAppSettings();
}
/// 获取权限的用户友好名称
String getPermissionName(Permission permission) {
switch (permission) {
case Permission.sms:
return 'sms'.tr;
case Permission.bluetooth:
return 'bluetooth'.tr;
case Permission.bluetoothScan:
return 'bluetoothScan'.tr;
case Permission.bluetoothConnect:
return 'bluetoothConnect'.tr;
case Permission.notification:
return 'notification'.tr;
case Permission.calendarWriteOnly:
return 'calendarWrite'.tr;
case Permission.calendarFullAccess:
return 'calendarFullAccess'.tr;
case Permission.location:
return 'locationInfo'.tr;
case Permission.scheduleExactAlarm:
return 'alarm'.tr;
case Permission.storage:
return 'storagePermission'.tr;
case Permission.microphone:
return 'microphonePermission'.tr;
default:
return permission.toString();
}
}
/// 获取权限说明文本
String _getDetailedDescription(Permission permission) {
switch (permission) {
case Permission.sms:
return 'smsPermissionDetailDesc'.tr;
case Permission.bluetooth:
return 'bluetoothPermissionDetailDesc'.tr;
case Permission.bluetoothScan:
return 'bluetoothScanPermissionDetailDesc'.tr;
case Permission.bluetoothConnect:
return 'bluetoothConnectPermissionDetailDesc'.tr;
case Permission.notification:
return 'notificationPermissionDetailDesc'.tr;
case Permission.calendarWriteOnly:
return 'calendarWritePermissionDetailDesc'.tr;
case Permission.calendarFullAccess:
return 'calendarFullAccessPermissionDetailDesc'.tr;
case Permission.location:
return 'locationPermissionDetailDesc'.tr;
case Permission.scheduleExactAlarm:
return 'alarmPermissionDetailDesc'.tr;
case Permission.storage:
return 'storagePermissionExplanation'.tr;
case Permission.microphone:
return 'microphonePermissionExplanation'.tr;
default:
return 'appNeedsPermissionForFullFunction'.tr;
}
}
/// 获取权限描述
String getPermissionDescription(Permission permission) {
switch (permission) {
case Permission.sms:
return 'smsPermissionDesc'.tr;
case Permission.bluetooth:
return 'bluetoothPermissionDesc'.tr;
case Permission.bluetoothScan:
return 'bluetoothScanPermissionDesc'.tr;
case Permission.bluetoothConnect:
return 'bluetoothConnectPermissionDesc'.tr;
case Permission.notification:
return 'notificationPermissionDesc'.tr;
case Permission.calendarWriteOnly:
return 'calendarWritePermissionDesc'.tr;
case Permission.calendarFullAccess:
return 'calendarFullAccessPermissionDesc'.tr;
case Permission.location:
return 'locationPermissionDesc'.tr;
case Permission.scheduleExactAlarm:
return 'alarmPermissionDesc'.tr;
case Permission.storage:
return 'storagePermissionExplanation'.tr;
case Permission.microphone:
return 'microphonePermissionExplanation'.tr;
default:
return 'appFunctionNeeds'.tr;
}
}
/// 显示错误消息
void _showErrorMessage() {
Get.snackbar(
'error'.tr,
'permissionRequestError'.tr,
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
}
}