Blame view

lib/common/permission/permissionRequestPage.dart 8.64 KB
1daca20d   吴启风   pref:权限申请页面优化
1
  import 'dart:async';
6051f850   吴启风   feat:带隐私合规权限申请描述的...
2
3
  import 'dart:io';
  import 'package:flutter/material.dart';
e811f164   吴启风   feat:权限申请页面增加隐私合规...
4
  import 'package:flutter_screenutil/flutter_screenutil.dart';
6051f850   吴启风   feat:带隐私合规权限申请描述的...
5
  import 'package:permission_handler/permission_handler.dart';
258578de   吴启风   feat:修复ios上退出应用失效问题
6
  import 'package:wow_english/common/core/app_config_helper.dart';
e811f164   吴启风   feat:权限申请页面增加隐私合规...
7
  import 'package:wow_english/common/permission/permissionRequester.dart';
6051f850   吴启风   feat:带隐私合规权限申请描述的...
8
9
10
  
  import '../../utils/log_util.dart';
  
ba96a4bc   吴启风   feat:方法注释优化
11
  ///带有隐私合规弹窗的透明权限申请页面,主要应对android各大应用市场对隐私权限申请需同步告知索取权限目的
6051f850   吴启风   feat:带隐私合规权限申请描述的...
12
  class PermissionRequestPage extends StatefulWidget {
e811f164   吴启风   feat:权限申请页面增加隐私合规...
13
14
    const PermissionRequestPage(this.permissions,
        this.permissionNames, this.permissionDesc,
6051f850   吴启风   feat:带隐私合规权限申请描述的...
15
16
        {super.key, this.isRequiredPermission = false});
  
1daca20d   吴启风   pref:权限申请页面优化
17
    final List<Permission> permissions;
e811f164   吴启风   feat:权限申请页面增加隐私合规...
18
19
20
    final List<String> permissionNames;
    final String permissionDesc;
  
1daca20d   吴启风   pref:权限申请页面优化
21
    ///是否需要强制授予
6051f850   吴启风   feat:带隐私合规权限申请描述的...
22
23
24
25
26
27
28
29
30
31
32
    final bool isRequiredPermission;
  
    @override
    State<PermissionRequestPage> createState() => _PermissionRequestPageState();
  }
  
  class _PermissionRequestPageState extends State<PermissionRequestPage>
      with WidgetsBindingObserver {
    bool _isGoSetting = false;
    late final List<String> msgList;
    bool _isDialogShowing = false;
c272c662   吴启风   fix: 崩溃修复
33
    bool _isRequestingPermission = false;
6051f850   吴启风   feat:带隐私合规权限申请描述的...
34
35
36
37
38
  
    @override
    void initState() {
      super.initState();
      WidgetsBinding.instance.addObserver(this);
e811f164   吴启风   feat:权限申请页面增加隐私合规...
39
40
      String permissionDesc = widget.permissionDesc;
      String permissionStr = widget.permissionNames.join('、');
6051f850   吴启风   feat:带隐私合规权限申请描述的...
41
      msgList = [
e811f164   吴启风   feat:权限申请页面增加隐私合规...
42
43
44
45
        "$permissionDesc,需要获取您设备的$permissionStr权限",
        "你还没有开启$permissionStr权限,开启后即可$permissionDesc",
        "未开启$permissionStr权限导致功能受限,您可以手动开启权限",
        widget.isRequiredPermission ? "退出应用" : "以后再说"
6051f850   吴启风   feat:带隐私合规权限申请描述的...
46
      ];
1daca20d   吴启风   pref:权限申请页面优化
47
      _handlePermission(widget.permissions);
6051f850   吴启风   feat:带隐私合规权限申请描述的...
48
49
50
    }
  
    @override
e811f164   吴启风   feat:权限申请页面增加隐私合规...
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
    Widget build(BuildContext context) {
      double screenWidth = MediaQuery.of(context).size.width;
      // PackageInfo packageInfo = await PackageInfo.fromPlatform();
      // String packageName = packageInfo.packageName;
      return Scaffold(
          backgroundColor: Colors.transparent,
          body: Align(
              alignment: Alignment.topCenter,
              child: Container(
                  width: screenWidth / 2,
                  padding: const EdgeInsets.all(16.0),
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(10.0), // 圆角半径
                    boxShadow: const [
                      BoxShadow(
                        color: Colors.black26,
                        blurRadius: 4.0,
                        offset: Offset(2, 2),
                      ),
                    ],
                  ),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Center(
                        child: Text(
                          '${widget.permissionNames.join('、')}权限使用说明',
                          style: TextStyle(
                              color: Colors.black,
                              fontSize: 15.sp,
                              fontWeight: FontWeight.w500,
                              fontFamily: 'PingFangSC-Regular'),
                          textAlign: TextAlign.left,
                        ),
                      ),
                      16.verticalSpace,
                      Text(
                        widget.permissionDesc,
                        style: const TextStyle(color: Colors.black54,
                            fontFamily: 'PingFangSC-Regular'),
                        textAlign: TextAlign.left,
                      ),
                    ],
                  ))));
    }
  
    @override
6051f850   吴启风   feat:带隐私合规权限申请描述的...
100
101
102
103
    void didChangeAppLifecycleState(AppLifecycleState state) {
      super.didChangeAppLifecycleState(state);
      Log.d("didChangeAppLifecycleState state=$state _isGoSetting=$_isGoSetting");
      // 监听 app 从后台切回前台
e811f164   吴启风   feat:权限申请页面增加隐私合规...
104
      if (state == AppLifecycleState.resumed && _isGoSetting && !_isDialogShowing) {
1daca20d   吴启风   pref:权限申请页面优化
105
        _handlePermission(widget.permissions);
6051f850   吴启风   feat:带隐私合规权限申请描述的...
106
107
108
109
      }
    }
  
    /// 校验权限
1daca20d   吴启风   pref:权限申请页面优化
110
    void _handlePermission(List<Permission> permissions) async {
c272c662   吴启风   fix: 崩溃修复
111
112
113
114
115
      if (_isRequestingPermission) {
        Log.d('_handlePermission already in progress, skipping');
        return;
      }
      
1daca20d   吴启风   pref:权限申请页面优化
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
      ///一个新待申请权限列表
      List<Permission> 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);
      }
6051f850   吴启风   feat:带隐私合规权限申请描述的...
134
135
    }
  
1daca20d   吴启风   pref:权限申请页面优化
136
137
    ///实际触发请求权限
    Future<void> _requestPermission(List<Permission> permissions) async {
c272c662   吴启风   fix: 崩溃修复
138
139
      if (_isRequestingPermission) {
        Log.d('_requestPermission already in progress, skipping');
1daca20d   吴启风   pref:权限申请页面优化
140
141
        return;
      }
c272c662   吴启风   fix: 崩溃修复
142
143
144
145
146
147
148
149
150
151
152
153
      
      _isRequestingPermission = true;
      Log.d('_requestPermission permissions=$permissions');
      
      try {
        MapEntry<Permission, PermissionStatus>? statusEntry =
            await requestPermissionsInner(permissions);
        if (statusEntry == null) {
          ///都手动同意授予了
          _popPage(true);
          return;
        }
1daca20d   吴启风   pref:权限申请页面优化
154
  
c272c662   吴启风   fix: 崩溃修复
155
156
        Permission permission = statusEntry.key;
        PermissionStatus status = statusEntry.value;
e811f164   吴启风   feat:权限申请页面增加隐私合规...
157
  
c272c662   吴启风   fix: 崩溃修复
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
        // 还未申请权限或之前拒绝了权限(在 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 ? "前往系统设置" : "继续");
        }
        // isLimited:拥有部分权限(受限,仅在 iOS (iOS14+) 上受支持)
        // isRestricted:拥有部分权限,活动限制(例如,设置了家长///控件,仅在iOS以上受支持。(仅限 iOS)
        if (status.isLimited || status.isRestricted) {
          if (Platform.isIOS || Platform.isMacOS) _isGoSetting = true;
          showAlert(
              permission, msgList[1], msgList[3], _isGoSetting ? "前往系统设置" : "继续");
        }
      } catch (e) {
        Log.d('_requestPermission error: $e');
        _popPage(false);
      } finally {
        _isRequestingPermission = false;
6051f850   吴启风   feat:带隐私合规权限申请描述的...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
      }
    }
  
    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()
e811f164   吴启风   feat:权限申请页面增加隐私合规...
206
                          : _popDialog(context, false);
6051f850   吴启风   feat:带隐私合规权限申请描述的...
207
208
209
210
211
212
213
                    }),
                TextButton(
                    child: Text(confirmMsg),
                    onPressed: () {
                      if (_isGoSetting) {
                        openAppSettings();
                      } else {
1daca20d   吴启风   pref:权限申请页面优化
214
                        _handlePermission(widget.permissions);
6051f850   吴启风   feat:带隐私合规权限申请描述的...
215
                      }
e811f164   吴启风   feat:权限申请页面增加隐私合规...
216
                      _popDialog(context, null);
6051f850   吴启风   feat:带隐私合规权限申请描述的...
217
218
219
220
221
                    })
              ],
            );
          }).then((value) => {
            _isDialogShowing = false,
e811f164   吴启风   feat:权限申请页面增加隐私合规...
222
223
            _popPage(value)
          });
6051f850   吴启风   feat:带隐私合规权限申请描述的...
224
225
    }
  
6051f850   吴启风   feat:带隐私合规权限申请描述的...
226
227
228
229
230
231
    @override
    void dispose() {
      WidgetsBinding.instance.removeObserver(this);
      super.dispose();
    }
  
6051f850   吴启风   feat:带隐私合规权限申请描述的...
232
233
    /// 退出应用程序
    void _quitApp() {
258578de   吴启风   feat:修复ios上退出应用失效问题
234
      AppConfigHelper.exitApp();
6051f850   吴启风   feat:带隐私合规权限申请描述的...
235
236
    }
  
6051f850   吴启风   feat:带隐私合规权限申请描述的...
237
    /// 关闭弹窗
e811f164   吴启风   feat:权限申请页面增加隐私合规...
238
239
    /// isAllGranted为null的话跳到系统设置页
    void _popDialog(BuildContext dialogContext, bool? isAllGranted) {
6051f850   吴启风   feat:带隐私合规权限申请描述的...
240
      Navigator.of(dialogContext).pop();
e811f164   吴启风   feat:权限申请页面增加隐私合规...
241
      _popPage(isAllGranted);
6051f850   吴启风   feat:带隐私合规权限申请描述的...
242
243
    }
  
e811f164   吴启风   feat:权限申请页面增加隐私合规...
244
245
246
247
248
249
    /// 关闭权限申请透明页面
    /// isAllGranted 所有权限都授予,为空不关闭
    void _popPage(bool? isAllGranted) {
      if (isAllGranted != null) {
        Navigator.of(context).pop(isAllGranted);
      }
6051f850   吴启风   feat:带隐私合规权限申请描述的...
250
251
    }
  }