Commit a6505868 by tanghuan

权限设置引导,以及一些优化

1 parent 67ce5110
...@@ -2,6 +2,7 @@ import 'dart:async'; ...@@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:app_settings/app_settings.dart';
import 'package:appframe/config/constant.dart'; import 'package:appframe/config/constant.dart';
import 'package:appframe/config/locator.dart'; import 'package:appframe/config/locator.dart';
import 'package:appframe/config/routes.dart'; import 'package:appframe/config/routes.dart';
...@@ -12,12 +13,14 @@ import 'package:appframe/services/local_server_service.dart'; ...@@ -12,12 +13,14 @@ import 'package:appframe/services/local_server_service.dart';
import 'package:appframe/services/player_service.dart'; import 'package:appframe/services/player_service.dart';
import 'package:appframe/services/recorder_service.dart'; import 'package:appframe/services/recorder_service.dart';
import 'package:appframe/utils/zip_util.dart'; import 'package:appframe/utils/zip_util.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:fluwx/fluwx.dart'; import 'package:fluwx/fluwx.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'package:webview_flutter/webview_flutter.dart'; import 'package:webview_flutter/webview_flutter.dart';
...@@ -59,7 +62,9 @@ class WebState extends Equatable { ...@@ -59,7 +62,9 @@ class WebState extends Equatable {
final bool chooseVideoCmdFlag; final bool chooseVideoCmdFlag;
final String chooseVideoCmdMessage; final String chooseVideoCmdMessage;
const WebState({ final String h5Version;
WebState({
this.selectedIndex = 0, this.selectedIndex = 0,
this.loaded = false, this.loaded = false,
this.isUpgrading = false, this.isUpgrading = false,
...@@ -82,7 +87,8 @@ class WebState extends Equatable { ...@@ -82,7 +87,8 @@ class WebState extends Equatable {
this.chooseImageCmdMessage = '', this.chooseImageCmdMessage = '',
this.chooseVideoCmdFlag = false, this.chooseVideoCmdFlag = false,
this.chooseVideoCmdMessage = '', this.chooseVideoCmdMessage = '',
}); String? h5Version,
}) : this.h5Version = h5Version ?? getIt.get<SharedPreferences>().getString("h5_version") ?? Constant.h5Version;
WebState copyWith({ WebState copyWith({
int? selectedIndex, int? selectedIndex,
...@@ -108,6 +114,7 @@ class WebState extends Equatable { ...@@ -108,6 +114,7 @@ class WebState extends Equatable {
String? chooseImageCmdMessage, String? chooseImageCmdMessage,
bool? chooseVideoCmdFlag, bool? chooseVideoCmdFlag,
String? chooseVideoCmdMessage, String? chooseVideoCmdMessage,
String? h5Version,
}) { }) {
return WebState( return WebState(
selectedIndex: selectedIndex ?? this.selectedIndex, selectedIndex: selectedIndex ?? this.selectedIndex,
...@@ -132,6 +139,7 @@ class WebState extends Equatable { ...@@ -132,6 +139,7 @@ class WebState extends Equatable {
chooseImageCmdMessage: chooseImageCmdMessage ?? this.chooseImageCmdMessage, chooseImageCmdMessage: chooseImageCmdMessage ?? this.chooseImageCmdMessage,
chooseVideoCmdFlag: chooseVideoCmdFlag ?? this.chooseVideoCmdFlag, chooseVideoCmdFlag: chooseVideoCmdFlag ?? this.chooseVideoCmdFlag,
chooseVideoCmdMessage: chooseVideoCmdMessage ?? this.chooseVideoCmdMessage, chooseVideoCmdMessage: chooseVideoCmdMessage ?? this.chooseVideoCmdMessage,
h5Version: h5Version ?? this.h5Version,
); );
} }
...@@ -159,6 +167,7 @@ class WebState extends Equatable { ...@@ -159,6 +167,7 @@ class WebState extends Equatable {
chooseImageCmdMessage, chooseImageCmdMessage,
chooseVideoCmdFlag, chooseVideoCmdFlag,
chooseVideoCmdMessage, chooseVideoCmdMessage,
h5Version,
]; ];
} }
...@@ -475,9 +484,9 @@ class WebCubit extends Cubit<WebState> { ...@@ -475,9 +484,9 @@ class WebCubit extends Cubit<WebState> {
Future<void> clearStorage() async { Future<void> clearStorage() async {
// 1 清理非 h5_version 的缓存 // 1 清理非 h5_version 的缓存
var sharedPreferences = getIt.get<SharedPreferences>(); var sharedPreferences = getIt.get<SharedPreferences>();
sharedPreferences.getKeys().forEach((key) { sharedPreferences.getKeys().forEach((key) async {
if (!key.startsWith('h5_version')) { if (!key.startsWith('h5_version')) {
sharedPreferences.remove(key); await sharedPreferences.remove(key);
} }
}); });
...@@ -619,16 +628,29 @@ class WebCubit extends Cubit<WebState> { ...@@ -619,16 +628,29 @@ class WebCubit extends Cubit<WebState> {
} }
void _chooseImageFromAlbum(BuildContext context, int count, String unique, String cmd) async { void _chooseImageFromAlbum(BuildContext context, int count, String unique, String cmd) async {
final List<AssetEntity>? result = await AssetPicker.pickAssets( final List<AssetEntity>? result;
context, try {
pickerConfig: AssetPickerConfig( result = await AssetPicker.pickAssets(
maxAssets: count, context,
requestType: RequestType.image, pickerConfig: AssetPickerConfig(
gridThumbnailSize: const ThumbnailSize.square(80), maxAssets: count,
previewThumbnailSize: const ThumbnailSize.square(150), requestType: RequestType.image,
dragToSelect: false, gridThumbnailSize: const ThumbnailSize.square(120),
), previewThumbnailSize: const ThumbnailSize.square(150),
); dragToSelect: false,
),
);
} catch (e) {
var resp = {'unique': unique, 'cmd': cmd, 'data': null, 'errMsg': 'no auth'};
_sendResponse(resp);
// 权限异常之后,检查是否已被永久拒绝,此时需要对用户进行引导
if (await _checkGalleryPermanentlyDenied()) {
_permissionLead(context, '相册权限');
}
return;
}
if (result == null || result.isEmpty) { if (result == null || result.isEmpty) {
var resp = {'unique': unique, 'cmd': cmd, 'data': null, 'errMsg': 'cancel'}; var resp = {'unique': unique, 'cmd': cmd, 'data': null, 'errMsg': 'cancel'};
...@@ -653,7 +675,19 @@ class WebCubit extends Cubit<WebState> { ...@@ -653,7 +675,19 @@ class WebCubit extends Cubit<WebState> {
} }
void _chooseImageFromCamera(BuildContext context, String unique, String cmd) async { void _chooseImageFromCamera(BuildContext context, String unique, String cmd) async {
AssetEntity? asset = await CameraPicker.pickFromCamera(context, pickerConfig: const CameraPickerConfig()); AssetEntity? asset;
try {
asset = await CameraPicker.pickFromCamera(context, pickerConfig: const CameraPickerConfig());
} catch (e) {
var resp = {'unique': unique, 'cmd': cmd, 'data': null, 'errMsg': 'no auth'};
_sendResponse(resp);
if (await _checkCameraPermanentlyDenied()) {
_permissionLead(context, '相机权限');
}
return;
}
if (asset == null) { if (asset == null) {
var resp = {'unique': unique, 'cmd': cmd, 'data': null, 'errMsg': 'cancel'}; var resp = {'unique': unique, 'cmd': cmd, 'data': null, 'errMsg': 'cancel'};
...@@ -693,6 +727,64 @@ class WebCubit extends Cubit<WebState> { ...@@ -693,6 +727,64 @@ class WebCubit extends Cubit<WebState> {
}; };
} }
///
/// 引导打开权限设置
///
Future<void> _permissionLead(BuildContext context, String permission) async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('权限设置'),
content: Text('$permission已被拒绝,请到设置中手动开启权限'),
actions: <Widget>[
TextButton(
child: Text('取消'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text('去设置'),
onPressed: () {
Navigator.of(context).pop();
AppSettings.openAppSettings(asAnotherTask: true); // 引导用户到应用设置页面
},
),
],
);
},
);
}
///
/// 检测相册权限是否被永久拒绝
///
Future<bool> _checkGalleryPermanentlyDenied() async {
PermissionStatus status;
if (Platform.isAndroid) {
final androidInfo = await DeviceInfoPlugin().androidInfo;
if (androidInfo.version.sdkInt <= 32) {
status = await Permission.storage.status;
} else {
status = await Permission.photos.status;
}
} else if (Platform.isIOS) {
status = await Permission.photos.status;
} else {
return false;
}
return PermissionStatus.permanentlyDenied == status;
}
///
/// 检测摄像头权限是否被永久拒绝
///
Future<bool> _checkCameraPermanentlyDenied() async {
PermissionStatus status = await Permission.camera.status;
return PermissionStatus.permanentlyDenied == status;
}
void setChooseVideoCmdFlag(bool chooseVideoCmdFlag, String chooseVideoCmdMessage) { void setChooseVideoCmdFlag(bool chooseVideoCmdFlag, String chooseVideoCmdMessage) {
emit(state.copyWith(chooseVideoCmdFlag: chooseVideoCmdFlag, chooseVideoCmdMessage: chooseVideoCmdMessage)); emit(state.copyWith(chooseVideoCmdFlag: chooseVideoCmdFlag, chooseVideoCmdMessage: chooseVideoCmdMessage));
} }
...@@ -739,14 +831,28 @@ class WebCubit extends Cubit<WebState> { ...@@ -739,14 +831,28 @@ class WebCubit extends Cubit<WebState> {
} }
void _chooseVideoFromAlbum(BuildContext context, int count, String unique, String cmd) async { void _chooseVideoFromAlbum(BuildContext context, int count, String unique, String cmd) async {
final List<AssetEntity>? result = await AssetPicker.pickAssets( List<AssetEntity>? result;
context,
pickerConfig: AssetPickerConfig( try {
maxAssets: count, result = await AssetPicker.pickAssets(
requestType: RequestType.video, context,
dragToSelect: false, pickerConfig: AssetPickerConfig(
), maxAssets: count,
); requestType: RequestType.video,
dragToSelect: false,
),
);
} catch (e) {
var resp = {'unique': unique, 'cmd': cmd, 'data': null, 'errMsg': 'no auth'};
_sendResponse(resp);
// 权限异常之后,检查是否已被永久拒绝,此时需要对用户进行引导
if (await _checkGalleryPermanentlyDenied()) {
_permissionLead(context, '相册权限');
}
return;
}
if (result == null || result.isEmpty) { if (result == null || result.isEmpty) {
var resp = {'unique': unique, 'cmd': cmd, 'data': null, 'errMsg': 'cancel'}; var resp = {'unique': unique, 'cmd': cmd, 'data': null, 'errMsg': 'cancel'};
...@@ -771,15 +877,27 @@ class WebCubit extends Cubit<WebState> { ...@@ -771,15 +877,27 @@ class WebCubit extends Cubit<WebState> {
} }
void _chooseVideoFromCamera(BuildContext context, int maxDuration, String unique, String cmd) async { void _chooseVideoFromCamera(BuildContext context, int maxDuration, String unique, String cmd) async {
AssetEntity? asset = await CameraPicker.pickFromCamera( AssetEntity? asset;
context, try {
pickerConfig: CameraPickerConfig( asset = await CameraPicker.pickFromCamera(
enableRecording: true, context,
onlyEnableRecording: true, pickerConfig: CameraPickerConfig(
// enableTapRecording: true, enableRecording: true,
maximumRecordingDuration: Duration(seconds: maxDuration), onlyEnableRecording: true,
), // enableTapRecording: true,
); maximumRecordingDuration: Duration(seconds: maxDuration),
),
);
} catch (e) {
var resp = {'unique': unique, 'cmd': cmd, 'data': null, 'errMsg': 'no auth'};
_sendResponse(resp);
if (await _checkCameraPermanentlyDenied()) {
_permissionLead(context, '相机权限');
}
return;
}
if (asset == null) { if (asset == null) {
var resp = {'unique': unique, 'cmd': cmd, 'data': null, 'errMsg': 'cancel'}; var resp = {'unique': unique, 'cmd': cmd, 'data': null, 'errMsg': 'cancel'};
......
...@@ -57,6 +57,13 @@ class RemoveStorageHandler extends MessageHandler { ...@@ -57,6 +57,13 @@ class RemoveStorageHandler extends MessageHandler {
class ClearStorageHandler extends MessageHandler { class ClearStorageHandler extends MessageHandler {
@override @override
Future<dynamic> handleMessage(dynamic params) async { Future<dynamic> handleMessage(dynamic params) async {
return await getIt.get<SharedPreferences>().clear(); var sharedPreferences = getIt.get<SharedPreferences>();
sharedPreferences.getKeys().forEach((key) async {
if (!key.startsWith('h5_version')) {
await sharedPreferences.remove(key);
}
});
return true;
} }
} }
...@@ -151,12 +151,13 @@ class WebPage extends StatelessWidget { ...@@ -151,12 +151,13 @@ class WebPage extends StatelessWidget {
child: Column( child: Column(
children: [ children: [
Text( Text(
'Version ${Constant.appVersion}', 'Version ${Constant.appVersion}-${state.h5Version}',
style: TextStyle( style: TextStyle(
color: Colors.grey, color: Colors.grey,
fontSize: 12, fontSize: 12,
), ),
), ),
SizedBox(height: 8),
Text( Text(
'Copyright © 中山班小二科技有限公司', 'Copyright © 中山班小二科技有限公司',
), ),
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!