From 20345cbf74920d49af04cc9fa806c09538267ad8 Mon Sep 17 00:00:00 2001 From: wuqifeng <540416539@qq.com> Date: Mon, 10 Jul 2023 01:35:34 +0800 Subject: [PATCH] feat:修改头像权限android端优化(权限申请流程还有待优化) --- android/app/src/main/AndroidManifest.xml | 4 ++++ lib/common/permission/PermissionUtil.dart | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/common/permission/permissionRequestPage.dart | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/reading/bloc/reading_bloc.dart | 2 +- lib/pages/reading/permissionRequestPage.dart | 189 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- lib/pages/user/modify/user_avatar_bloc/user_avatar_bloc.dart | 15 ++++++++++++++- 6 files changed, 331 insertions(+), 191 deletions(-) create mode 100644 lib/common/permission/PermissionUtil.dart create mode 100644 lib/common/permission/permissionRequestPage.dart delete mode 100644 lib/pages/reading/permissionRequestPage.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4e58ed2..c2ff064 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -36,6 +36,10 @@ + + + diff --git a/lib/common/permission/PermissionUtil.dart b/lib/common/permission/PermissionUtil.dart new file mode 100644 index 0000000..c27fbd3 --- /dev/null +++ b/lib/common/permission/PermissionUtil.dart @@ -0,0 +1,124 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:permission_handler/permission_handler.dart'; + +///权限检测工具 +class PermissionUtil { + static defaultCall(name) { + EasyLoading.showToast(name); + } + + /// 检测石是否有权限 + /// [permissionList] 权限申请列表 + /// [errMsg] 错误信息 + /// [onSuccess] 全部成功 + /// [onFailed] 有一个失败 + /// [goSetting] 前往设置 + static checkPermission( + {required List permissionList, + String? errMsg, + VoidCallback? onSuccess, + VoidCallback? onFailed, + VoidCallback? goSetting}) async { + ///一个新待申请权限列表 + List newPermissionList = []; + + ///遍历当前权限申请列表 + for (Permission permission in permissionList) { + PermissionStatus status = await permission.status; + + ///如果不是允许状态就添加到新的申请列表中 + if (!status.isGranted) { + newPermissionList.add(permission); + } + } + + ///如果需要重新申请的列表不是空的 + if (newPermissionList.isNotEmpty) { + PermissionStatus permissionStatus = + await requestPermission(newPermissionList); + + switch (permissionStatus) { + + ///拒绝状态 + case PermissionStatus.denied: + onFailed != null ? onFailed() : defaultCall("权限申请失败"); + break; + + ///允许状态 + case PermissionStatus.granted: + onSuccess != null ? onSuccess() : defaultCall("权限申请成功"); + break; + + /// 永久拒绝 活动限制 + case PermissionStatus.restricted: + case PermissionStatus.limited: + case PermissionStatus.permanentlyDenied: + case PermissionStatus.provisional: + goSetting != null + ? goSetting( ) + :await openAppSettings(); + break; + } + } else { + onSuccess != null ? onSuccess() : defaultCall("权限申请成功"); + } + } + + /// 获取新列表中的权限 如果有一项不合格就返回false + static requestPermission(List permissionList) async { + Map statuses = await permissionList.request(); + PermissionStatus currentPermissionStatus = PermissionStatus.granted; + statuses.forEach((key, value) { + if (!value.isGranted) { + currentPermissionStatus = value; + return; + } + }); + return currentPermissionStatus; + } + + static checkLocationAlways( + {VoidCallback? onSuccess, + VoidCallback? onFailed, + VoidCallback? goSetting}) async { + ///获取前置状态 + /// Android没有这一步 ios会先访问这个再访问其他的 + PermissionStatus status = PermissionStatus.granted; + status = await _checkSinglePermission(Permission.locationWhenInUse); + + ///获取第二个状态 + PermissionStatus status2 = PermissionStatus.denied; + + ///如果前置状态为成功才能执行获取第二个状态 + if (status.isGranted) { + status2 = await _checkSinglePermission(Permission.locationAlways); + } + + ///如果两个都成功那么就返回成功 + if (status.isGranted && status2.isGranted) { + onSuccess != null ? onSuccess() : defaultCall("权限申请成功"); + + ///如果有一个拒绝那么就失败了 + } else if (status.isDenied || status2.isDenied) { + onFailed != null ? onFailed() : defaultCall("权限申请失败"); + } else { + goSetting != null ? goSetting() : await openAppSettings(); + } + } + + static _checkSinglePermission(Permission permission) async { + ///获取当前状态 + PermissionStatus status = await permission.status; + PermissionStatus currentPermissionStatus = PermissionStatus.granted; + + ///如果它状态不是允许那么就去获取 + if (!status.isGranted) { + currentPermissionStatus = await requestPermission([permission]); + } + + ///返回最终状态 + return currentPermissionStatus; + } +} diff --git a/lib/common/permission/permissionRequestPage.dart b/lib/common/permission/permissionRequestPage.dart new file mode 100644 index 0000000..c99702a --- /dev/null +++ b/lib/common/permission/permissionRequestPage.dart @@ -0,0 +1,188 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:permission_handler/permission_handler.dart'; + +import '../../utils/log_util.dart'; + +/// 权限检查及请求 +/// 外部可通过此方法来进行权限的检查和请求,将自动跳转到`PermissionRequestPage`页面。 +/// 传入 `Permission` 以及对应的权限名称 `permissionTypeStr`,如果有权限则返回 `Future true` +/// `isRequiredPermission` 如果为 `true`,则 "取消" 按钮将执行 "退出app" 的操作 +Future permissionCheckAndRequest( + BuildContext context, + Permission permission, + String permissionTypeStr, + {bool isRequiredPermission = false}) async { + if (!await permission.status.isGranted) { + await Navigator.of(context).push(PageRouteBuilder( + opaque: false, + pageBuilder: ((context, animation, secondaryAnimation) { + return PermissionRequestPage(permission, permissionTypeStr, + isRequiredPermission: isRequiredPermission); + }))); + } else { + return true; + } + return false; +} + +class PermissionRequestPage extends StatefulWidget { + const PermissionRequestPage(this.permission, this.permissionTypeStr, + {super.key, this.isRequiredPermission = false}); + + final Permission permission; + final String permissionTypeStr; + 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); + msgList = [ + "${widget.permissionTypeStr}功能需要获取您设备的${widget.permissionTypeStr}权限,否则可能无法正常工作。\n是否申请${widget.permissionTypeStr}权限?", + "${widget.permissionTypeStr}权限不全,是否重新申请权限?", + "没有${widget.permissionTypeStr}权限,您可以手动开启权限", + widget.isRequiredPermission ? "退出应用" : "取消" + ]; + _checkPermission(widget.permission); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + super.didChangeAppLifecycleState(state); + Log.d("didChangeAppLifecycleState state=$state _isGoSetting=$_isGoSetting"); + // 监听 app 从后台切回前台 + if (state == AppLifecycleState.resumed && _isGoSetting) { + _checkPermission(widget.permission); + } + } + + /// 校验权限 + void _checkPermission(Permission permission) async { + final PermissionStatus status = await permission.status; + _handlePermissionStatus(permission, status); + } + + void _handlePermissionStatus(Permission permission, PermissionStatus status) { + Log.d('_handlePermissionStatus=$status permission=$permission'); + if (status.isGranted) { + _popPage(); + return; + } + + // 还未申请权限或之前拒绝了权限(在 iOS 上为首次申请权限,拒绝后将变为 `永久拒绝权限`) + if (status.isDenied) { + showAlert( + permission, msgList[0], msgList[3], _isGoSetting ? "前往系统设置" : "确定"); + } + // 权限已被永久拒绝 + if (status.isPermanentlyDenied) { + _isGoSetting = true; + showAlert( + permission, msgList[2], msgList[3], _isGoSetting ? "前往系统设置" : "确定"); + } + // 拥有部分权限 + 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); + }), + TextButton( + child: Text(confirmMsg), + onPressed: () { + if (_isGoSetting) { + openAppSettings(); + } else { + _requestPermisson(permission); + } + _popDialog(context); + }) + ], + ); + }).then((value) => { + _isDialogShowing = false, + }); + } + + /// 申请权限 + void _requestPermisson(Permission permission) async { + // 申请权限 + PermissionStatus status = await permission.request(); + Log.d('requestPermisson权限检测=$status _isGoSetting=$_isGoSetting'); + // 再次校验 + _handlePermissionStatus(permission, status); + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container(); + } + + /// 退出应用程序 + void _quitApp() { + SystemChannels.platform.invokeMethod("SystemNavigator.pop"); + } + + /// 关闭整个权限申请页面 + void _popDialogAndPage(BuildContext dialogContext) { + _popDialog(dialogContext); + _popPage(); + } + + /// 关闭弹窗 + void _popDialog(BuildContext dialogContext) { + Navigator.of(dialogContext).pop(); + } + + /// 关闭透明页面 + void _popPage() { + Navigator.of(context).pop(); + } +} diff --git a/lib/pages/reading/bloc/reading_bloc.dart b/lib/pages/reading/bloc/reading_bloc.dart index e4f933f..071c33c 100644 --- a/lib/pages/reading/bloc/reading_bloc.dart +++ b/lib/pages/reading/bloc/reading_bloc.dart @@ -14,7 +14,7 @@ import '../../../models/course_process_entity.dart'; import '../../../utils/loading.dart'; import '../../../utils/log_util.dart'; -import '../permissionRequestPage.dart'; +import '../../../common/permission/permissionRequestPage.dart'; part 'reading_event.dart'; part 'reading_state.dart'; diff --git a/lib/pages/reading/permissionRequestPage.dart b/lib/pages/reading/permissionRequestPage.dart deleted file mode 100644 index cffeb24..0000000 --- a/lib/pages/reading/permissionRequestPage.dart +++ /dev/null @@ -1,189 +0,0 @@ -import 'dart:io'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:permission_handler/permission_handler.dart'; - -import '../../utils/log_util.dart'; - -/// 权限检查及请求 -/// 外部可通过此方法来进行权限的检查和请求,将自动跳转到`PermissionRequestPage`页面。 -/// 传入 `Permission` 以及对应的权限名称 `permissionTypeStr`,如果有权限则返回 `Future true` -/// `isRequiredPermission` 如果为 `true`,则 "取消" 按钮将执行 "退出app" 的操作 -Future permissionCheckAndRequest( - BuildContext context, - Permission permission, - String permissionTypeStr, - {bool isRequiredPermission = false}) async { - if (!await permission.status.isGranted) { - await Navigator.of(context).push(PageRouteBuilder( - opaque: true, - barrierColor: const Color.fromRGBO(255, 0, 0, 0.7), - pageBuilder: ((context, animation, secondaryAnimation) { - return PermissionRequestPage(permission, permissionTypeStr, - isRequiredPermission: isRequiredPermission); - }))); - } else { - return true; - } - return false; -} - -class PermissionRequestPage extends StatefulWidget { - const PermissionRequestPage(this.permission, this.permissionTypeStr, - {super.key, this.isRequiredPermission = false}); - - final Permission permission; - final String permissionTypeStr; - 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); - msgList = [ - "${widget.permissionTypeStr}功能需要获取您设备的${widget.permissionTypeStr}权限,否则可能无法正常工作。\n是否申请${widget.permissionTypeStr}权限?", - "${widget.permissionTypeStr}权限不全,是否重新申请权限?", - "没有${widget.permissionTypeStr}权限,您可以手动开启权限", - widget.isRequiredPermission ? "退出应用" : "取消" - ]; - _checkPermission(widget.permission); - } - - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - super.didChangeAppLifecycleState(state); - Log.d("didChangeAppLifecycleState state=$state _isGoSetting=$_isGoSetting"); - // 监听 app 从后台切回前台 - if (state == AppLifecycleState.resumed && _isGoSetting) { - _checkPermission(widget.permission); - } - } - - /// 校验权限 - void _checkPermission(Permission permission) async { - final PermissionStatus status = await permission.status; - _handlePermissionStatus(permission, status); - } - - void _handlePermissionStatus(Permission permission, PermissionStatus status) { - Log.d('_handlePermissionStatus=$status permission=$permission'); - if (status.isGranted) { - _popPage(); - return; - } - - // 还未申请权限或之前拒绝了权限(在 iOS 上为首次申请权限,拒绝后将变为 `永久拒绝权限`) - if (status.isDenied) { - showAlert( - permission, msgList[0], msgList[3], _isGoSetting ? "前往系统设置" : "确定"); - } - // 权限已被永久拒绝 - if (status.isPermanentlyDenied) { - _isGoSetting = true; - showAlert( - permission, msgList[2], msgList[3], _isGoSetting ? "前往系统设置" : "确定"); - } - // 拥有部分权限 - 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); - }), - TextButton( - child: Text(confirmMsg), - onPressed: () { - if (_isGoSetting) { - openAppSettings(); - } else { - _requestPermisson(permission); - } - _popDialog(context); - }) - ], - ); - }).then((value) => { - _isDialogShowing = false, - }); - } - - /// 申请权限 - void _requestPermisson(Permission permission) async { - // 申请权限 - PermissionStatus status = await permission.request(); - Log.d('requestPermisson权限检测=$status _isGoSetting=$_isGoSetting'); - // 再次校验 - _handlePermissionStatus(permission, status); - } - - @override - void dispose() { - WidgetsBinding.instance.removeObserver(this); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Container(); - } - - /// 退出应用程序 - void _quitApp() { - SystemChannels.platform.invokeMethod("SystemNavigator.pop"); - } - - /// 关闭整个权限申请页面 - void _popDialogAndPage(BuildContext dialogContext) { - _popDialog(dialogContext); - _popPage(); - } - - /// 关闭弹窗 - void _popDialog(BuildContext dialogContext) { - Navigator.of(dialogContext).pop(); - } - - /// 关闭透明页面 - void _popPage() { - Navigator.of(context).pop(); - } -} diff --git a/lib/pages/user/modify/user_avatar_bloc/user_avatar_bloc.dart b/lib/pages/user/modify/user_avatar_bloc/user_avatar_bloc.dart index 9347a7e..5a4f6ce 100644 --- a/lib/pages/user/modify/user_avatar_bloc/user_avatar_bloc.dart +++ b/lib/pages/user/modify/user_avatar_bloc/user_avatar_bloc.dart @@ -1,3 +1,6 @@ +import 'dart:io'; + +import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; @@ -99,7 +102,17 @@ class UserAvatarBloc extends Bloc { ///获取相册权限 Future getPhotoPermissionStatus() async { - Permission permission = Permission.photos; + Permission permission; + if (Platform.isAndroid) { + final androidInfo = await DeviceInfoPlugin().androidInfo; + if (androidInfo.version.sdkInt <= 32) { + permission = Permission.storage; + } else { + permission = Permission.photos; + } + } else { + permission = Permission.photos; + } PermissionStatus status = await permission.status; if (status.isGranted) { return true; -- libgit2 0.22.2