From 1daca20d5640a9c1ca1059dd67d2d5f74e44808a Mon Sep 17 00:00:00 2001 From: wuqifeng <540416539@qq.com> Date: Sat, 29 Jun 2024 00:58:59 +0800 Subject: [PATCH] pref:权限申请页面优化 --- lib/common/permission/permissionRequestPage.dart | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------ lib/pages/user/modify/modify_user_avatar_page.dart | 2 +- lib/pages/user/modify/user_avatar_bloc/user_avatar_bloc.dart | 31 ++++++++++++++++++++++++------- 3 files changed, 124 insertions(+), 50 deletions(-) diff --git a/lib/common/permission/permissionRequestPage.dart b/lib/common/permission/permissionRequestPage.dart index 8a23fc2..7b41db9 100644 --- a/lib/common/permission/permissionRequestPage.dart +++ b/lib/common/permission/permissionRequestPage.dart @@ -1,38 +1,75 @@ +import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:package_info_plus/package_info_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:wow_english/common/core/app_config_helper.dart'; import '../../utils/log_util.dart'; -/// 权限检查及请求 +/// 带隐私合规功能的权限检查及请求 /// 外部可通过此方法来进行权限的检查和请求,将自动跳转到`PermissionRequestPage`页面。 /// 传入 `Permission` 以及对应的权限名称 `permissionTypeStr`,如果有权限则返回 `Future true` /// `isRequiredPermission` 如果为 `true`,则 "取消" 按钮将执行 "退出app" 的操作 +Future permissionCheckAndRequests( + BuildContext context, + List permissions, + List permissionTypeStrs, + {bool isRequiredPermission = false}) async { + + // List statuses = await Future.wait( + // permissions.map((permission) => permission.status), + // ); + // bool allGranted = statuses.every((status) => status.isGranted); + + bool allGranted = await isPermissionsGranted(permissions); + if (allGranted) { + return true; + } else { + return await Navigator.of(context).push(PageRouteBuilder( + opaque: false, + pageBuilder: ((context, animation, secondaryAnimation) { + return PermissionRequestPage(permissions, permissionTypeStrs, + isRequiredPermission: isRequiredPermission); + }))); + } +} + 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 permissionCheckAndRequests(context, [permission], [permissionTypeStr], + isRequiredPermission: isRequiredPermission); + } + +///判断权限数组是否都授予 +Future isPermissionsGranted(List permissions) async { + // 使用 every 直接检查权限状态 + return await Future.wait(permissions.map((permission) async { + return await permission.status.isGranted; + })).then((statuses) => statuses.every((status) => status)); +} + +///请求权限 +Future?> requestPermissions(List permissionList) async { + Map statusesMap = await permissionList.request(); + for (var entry in statusesMap.entries) { + if (!entry.value.isGranted) { + return entry; + } } - return false; + return null; } class PermissionRequestPage extends StatefulWidget { - const PermissionRequestPage(this.permission, this.permissionTypeStr, + const PermissionRequestPage(this.permissions, this.permissionTypeStrs, {super.key, this.isRequiredPermission = false}); - final Permission permission; - final String permissionTypeStr; + final List permissions; + final List permissionTypeStrs; + ///是否需要强制授予 final bool isRequiredPermission; @override @@ -49,13 +86,14 @@ class _PermissionRequestPageState extends State void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); + String permissionTypeStrs = widget.permissionTypeStrs.join('、'); msgList = [ - "${widget.permissionTypeStr}功能需要获取您设备的${widget.permissionTypeStr}权限,否则可能无法正常工作。\n是否申请${widget.permissionTypeStr}权限?", - "${widget.permissionTypeStr}权限不全,是否重新申请权限?", - "没有${widget.permissionTypeStr}权限,您可以手动开启权限", + "Wow English需要获取您设备的$permissionTypeStrs权限,否则可能无法正常工作。\n是否同意授予?", + "$permissionTypeStrs权限不全,是否重新申请权限?", + "没有$permissionTypeStrs权限,您可以手动开启权限", widget.isRequiredPermission ? "退出应用" : "取消" ]; - _checkPermission(widget.permission); + _handlePermission(widget.permissions); } @override @@ -64,35 +102,63 @@ class _PermissionRequestPageState extends State Log.d("didChangeAppLifecycleState state=$state _isGoSetting=$_isGoSetting"); // 监听 app 从后台切回前台 if (state == AppLifecycleState.resumed && _isGoSetting) { - _checkPermission(widget.permission); + _handlePermission(widget.permissions); } } /// 校验权限 - void _checkPermission(Permission permission) async { - final PermissionStatus status = await permission.status; - _handlePermissionStatus(permission, status); + void _handlePermission(List permissions) async { + ///一个新待申请权限列表 + List intentPermissionList = []; + + ///遍历当前权限申请列表 + for (Permission permission in permissions) { + PermissionStatus status = await permission.status; + + ///如果不是允许状态就添加到新的申请列表中 + if (!status.isGranted) { + intentPermissionList.add(permission); + } + } + + if (intentPermissionList.isEmpty) { + _popPage(true); + } else { + _requestPermission(intentPermissionList); + } } - void _handlePermissionStatus(Permission permission, PermissionStatus status) { - Log.d('_handlePermissionStatus=$status permission=$permission'); - if (status.isGranted) { - _popPage(); + ///实际触发请求权限 + Future _requestPermission(List permissions) async { + Log.d('_requestPermission permissions=$permissions'); + if (await isPermissionsGranted(permissions)) { + _popPage(true); return; } + MapEntry? statusEntry = await requestPermissions(permissions); + if (statusEntry == null) { + ///都手动同意授予了 + _popPage(true); + return; + } + + Permission permission = statusEntry.key; + PermissionStatus status = statusEntry.value; // 还未申请权限或之前拒绝了权限(在 iOS 上为首次申请权限,拒绝后将变为 `永久拒绝权限`) if (status.isDenied) { showAlert( permission, msgList[0], msgList[3], _isGoSetting ? "前往系统设置" : "确定"); } // 权限已被永久拒绝 + /// 在 Android 上:Android 11+ (API 30+):用户是否第二次拒绝权限。低于 Android 11 (API 30):用户是否拒绝访问请求的功能,并选择不再显示请求。 + /// 在 iOS 上:如果用户拒绝访问所请求的功能。 if (status.isPermanentlyDenied) { _isGoSetting = true; showAlert( permission, msgList[2], msgList[3], _isGoSetting ? "前往系统设置" : "确定"); } - // 拥有部分权限 + // 拥有部分权限(受限,仅在 iOS (iOS14+) 上受支持) if (status.isLimited) { if (Platform.isIOS || Platform.isMacOS) _isGoSetting = true; showAlert( @@ -126,7 +192,7 @@ class _PermissionRequestPageState extends State onPressed: () { widget.isRequiredPermission ? _quitApp() - : _popDialogAndPage(context); + : _popDialogAndPage(context, false); }), TextButton( child: Text(confirmMsg), @@ -134,7 +200,7 @@ class _PermissionRequestPageState extends State if (_isGoSetting) { openAppSettings(); } else { - _requestPermisson(permission); + _handlePermission(widget.permissions); } _popDialog(context); }) @@ -145,15 +211,6 @@ class _PermissionRequestPageState extends State }); } - /// 申请权限 - 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); @@ -171,9 +228,9 @@ class _PermissionRequestPageState extends State } /// 关闭整个权限申请页面 - void _popDialogAndPage(BuildContext dialogContext) { + void _popDialogAndPage(BuildContext dialogContext, bool isAllGranted) { _popDialog(dialogContext); - _popPage(); + _popPage(isAllGranted); } /// 关闭弹窗 @@ -182,7 +239,7 @@ class _PermissionRequestPageState extends State } /// 关闭透明页面 - void _popPage() { - Navigator.of(context).pop(); + void _popPage(bool isAllGranted) { + Navigator.of(context).pop(isAllGranted); } } diff --git a/lib/pages/user/modify/modify_user_avatar_page.dart b/lib/pages/user/modify/modify_user_avatar_page.dart index b697a12..31b7ffb 100644 --- a/lib/pages/user/modify/modify_user_avatar_page.dart +++ b/lib/pages/user/modify/modify_user_avatar_page.dart @@ -22,7 +22,7 @@ class ModifyUserAvatarPage extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => UserAvatarBloc(), + create: (context) => UserAvatarBloc(context), child: _ModifyUserAvatarPage(pageType: pageType), ); } 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 7cc3100..cf61c3e 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 @@ -14,6 +14,8 @@ import 'package:wow_english/utils/aliyun_oss_util.dart'; import 'package:wow_english/utils/log_util.dart'; import 'package:wow_english/utils/toast_util.dart'; +import '../../../../common/permission/permissionRequestPage.dart'; + part 'user_avatar_event.dart'; part 'user_avatar_state.dart'; @@ -32,7 +34,9 @@ class UserAvatarBloc extends Bloc { final ImagePicker picker = ImagePicker(); - UserAvatarBloc() : super(UserAvatarInitial()) { + final BuildContext context; + + UserAvatarBloc(this.context) : super(UserAvatarInitial()) { on(_getImageFromPhoto); on(_getImageFromCamera); on(_changeUserEnterAppState); @@ -75,11 +79,8 @@ class UserAvatarBloc extends Bloc { } void _getImageFromCamera(GetImageFromCameraEvent event, Emitter emitter) async { - await getPermissionStatus(Permission.camera).then((value) async { - if (!value) { - debugPrint('失败$value'); - return; - } + bool result = await permissionCheckAndRequest(context, Permission.camera, "拍照"); + if (result) { _file = await picker.pickImage(source: ImageSource.camera); EasyLoading.show(); try { @@ -90,7 +91,23 @@ class UserAvatarBloc extends Bloc { showToast('上传头像失败: $e'); } EasyLoading.dismiss(); - }); + } + // await getPermissionStatus(Permission.camera).then((value) async { + // if (!value) { + // debugPrint('失败$value'); + // return; + // } + // _file = await picker.pickImage(source: ImageSource.camera); + // EasyLoading.show(); + // try { + // final urlStr = await _uploadAvatar(_file!.path); + // emitter(ChangeImageState(urlStr)); + // } catch (e) { + // Log.e('上传头像失败:$e'); + // showToast('上传头像失败: $e'); + // } + // EasyLoading.dismiss(); + // }); } void _changeUserEnterAppState(ChangeUserEnterAppStateEvent event, Emitter emitter) async { -- libgit2 0.22.2