import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:loopin/IM/im_service.dart'; import 'package:loopin/components/my_confirm.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:photo_manager/photo_manager.dart'; class Permissions { /// 判断是否为华为设备 static Future isHuaweiDevice() async { if (Platform.isAndroid) { final deviceInfoPlugin = DeviceInfoPlugin(); final androidInfo = await deviceInfoPlugin.androidInfo; // 判断品牌是否为华为 return androidInfo.brand.toLowerCase().contains('huawei') || androidInfo.manufacturer.toLowerCase().contains('huawei'); } return false; } // 请求视频访问权限 static Future requestVideoPermission({String? title, String? content}) async { if (Platform.isAndroid) { SnackbarController? ctl; final isHw = await isHuaweiDevice(); if (isHw) { ctl = Get.snackbar( title ?? '相册权限使用说明:', content ?? '我们需要读取您的手机相册,以便您从相册中选择文件', duration: Duration(days: 1), backgroundColor: Colors.red.withAlpha(230), colorText: Colors.white, icon: const Icon(Icons.error_outline, color: Colors.white), ); } final deviceInfoPlugin = DeviceInfoPlugin(); final androidInfo = await deviceInfoPlugin.androidInfo; final sdkInt = androidInfo.version.sdkInt; if (sdkInt >= 33) { // Android 13 及以上 final status = await Permission.videos.request(); if (ctl != null) { ctl.close(); } return status.isGranted; } else { // Android 12 及以下 final status = await Permission.storage.request(); if (ctl != null) { ctl.close(); } return status.isGranted; } } else if (Platform.isIOS) { final status = await Permission.photos.request(); // return status.isGranted || status.isLimited; return handleStatus(status, isAndroid: false); } else { return false; } } // 请求相册权限 static Future requestPhotoPermission({String? title, String? content}) async { if (Platform.isAndroid) { final isHw = await isHuaweiDevice(); SnackbarController? ctl; if (isHw) { ctl = Get.snackbar( title ?? '相册权限使用说明:', content ?? '我们需要读取您的手机相册,以便您从相册中选择文件', duration: Duration(days: 1), backgroundColor: Colors.red.withAlpha(230), colorText: Colors.white, icon: const Icon(Icons.error_outline, color: Colors.white), ); } final deviceInfoPlugin = DeviceInfoPlugin(); final androidInfo = await deviceInfoPlugin.androidInfo; final sdkInt = androidInfo.version.sdkInt; logger.w(sdkInt); if (sdkInt >= 33) { // Android 13 及以上 final status = await Permission.photos.request(); if (ctl != null) { ctl.close(); } // return status.isGranted; return handleStatus(status, isAndroid: true); } else { // Android 12 及以下 final status = await Permission.storage.request(); if (ctl != null) { ctl.close(); } // return status.isGranted; return handleStatus(status, isAndroid: true); } } else if (Platform.isIOS) { final status = await Permission.photos.request(); logger.w('iOS photos = $status'); // return status.isGranted || status.isLimited; return handleStatus(status, isAndroid: false); } else { return false; } } // 请求相机 static Future requestCameraPermission({String? title, String? content}) async { return await _checkAndRequest(Permission.camera, title: title, content: content); } // 请求麦克风权限 static Future requestMicrophonePermission({String? title, String? content}) async { return await _checkAndRequest(Permission.microphone, title: title, content: content); } // 请求本地存储权限 static Future requestStoragePermission({String? title, String? content}) async { return await _checkAndRequest(Permission.storage, title: title, content: content); } // 封装公共权限处理逻辑 static Future _checkAndRequest(Permission permission, {String? title, String? content}) async { if (Platform.isAndroid) { final isHw = await isHuaweiDevice(); SnackbarController? ctl; if (isHw) { ctl = Get.snackbar( title ?? '麦克风权限使用说明:', content ?? '用于发送语音消息', duration: Duration(days: 1), backgroundColor: Colors.red.withAlpha(230), colorText: Colors.white, icon: const Icon(Icons.error_outline, color: Colors.white), ); } final result = await permission.request(); if (ctl != null) { ctl.close(); } return handleStatus(result, isAndroid: true); } else { final result = await permission.request(); return handleStatus(result, isAndroid: false); } // final status = await permission.status; // if (status.isGranted) { // // 有权限直接关闭 // if (ctl != null) { // ctl.close(); // } // return true; // } // final result = await permission.request(); // if (result.isGranted) { // if (ctl != null) { // ctl.close(); // } // return true; // } // if (result.isPermanentlyDenied) { // // 永久拒绝 只能去设置 // if (ctl != null) { // ctl.close(); // } // return false; // } else { // if (ctl != null) { // ctl.close(); // } // // 临时拒绝 提示 // Get.snackbar('权限请求失败', '无法访问,请授权对应权限后重试'); // } // return false; } /// 处理权限状态 static Future handleStatus(PermissionStatus status, {required bool isAndroid, SnackbarController? ctl}) async { logger.w("当前权限状态 = $status"); logger.e(status.isPermanentlyDenied); if (status.isGranted) { return true; } if (!isAndroid) { // iOS 独有的情况 if (status.isLimited) { logger.w("iOS 相册权限 = 仅限部分照片 (Limited)"); return true; // Limited 状态下也能用,但受限制 } if (status.isPermanentlyDenied) { // ios 二次检测 // permission_handler在ios下只能检测出limited和granted;其余被拒或手动修改均为permanentlyDenied的问题 final result = await PhotoManager.requestPermissionExtend(); logger.e(result); switch (result) { case PermissionState.authorized: return true; // 完全授权 case PermissionState.limited: return true; // 部分授权,也可用 case PermissionState.denied: return false; case PermissionState.restricted: return false; default: return false; // 用户拒绝,跳转设置页 } } } if (status.isDenied) { logger.w("相册权限被拒绝(可再次请求)"); return false; } if (status.isPermanentlyDenied || status.isRestricted) { logger.w("相册权限被永久拒绝,需要跳转到设置页"); return false; } return false; } // 跳转设置的提示弹窗 static void showPermissionDialog(String name) async { final confirmed = await ConfirmDialog.show( title: '需要$name权限', content: '请前往系统设置中手动开启权限', confirmText: '去设置', ); if (confirmed == true) { await openAppSettings(); } } }