Files
flutter_common/lib/upload_image/upload_images_tool.dart
wuxinglong 0aea393ed0 fix(upload_image): 修复压缩图片后临时文件未删除问题
- 优化图片压缩流程后立即删除临时文件
- 避免临时文件堆积占用存储空间
- 保持压缩图片的质量和尺寸设置不变
- 确保选中的文件列表正确添加压缩文件实例
2026-02-06 14:06:47 +08:00

376 lines
13 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:io';
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter_common/upload_image/ossUtil.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
// import 'package:images_picker/images_picker.dart';
// import 'package:images_picker/images_picker.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
class UploadImagesTool {
static uploadImagesTool({
String? oSSAccessKeyId,
String? policy,
String? callback,
String? signature,
String? ossDirectory,
String? ossHost,
required BuildContext context,
Function? chooseImagesTap,
int? max,
bool? isVideo,
Widget? isAddOtherWidget,
bool? isShowLoading,
}) async {
await chooseCamera(
context: context,
max: max,
oSSAccessKeyId: oSSAccessKeyId ?? '',
ossHost: ossHost ?? '',
ossDirectory: ossDirectory ?? '',
policy: policy ?? '',
callback: callback ?? '',
signature: signature ?? '',
isVideo: isVideo,
isAddOtherWidget: isAddOtherWidget,
isShowLoading: isShowLoading,
chooseImages: (list) => chooseImagesTap?.call(list),
);
}
/// 动态申请权限需要区分android和ios很多时候它两配置权限时各自的名称不同
/// 此处以保存图片需要的配置为例
static Future<bool> requestPermission(context) async {
late PermissionStatus status;
// 1、读取系统权限的弹框
if (Platform.isIOS) {
status = await Permission.photosAddOnly.request();
} else {
status = await Permission.camera.request();
}
// 2、假如你点not allow后下次点击不会在出现系统权限的弹框系统权限的弹框只会出现一次
// 这时候需要你自己写一个弹框然后去打开app权限的页面
if (status != PermissionStatus.granted) {
showCupertinoDialog(
context: context,
builder: (BuildContext ctx) {
return CupertinoAlertDialog(
title: const Text('您需要去打开权限'),
content: const Text('请打开您的相机或者相册权限'),
actions: <Widget>[
CupertinoDialogAction(
child: const Text('取消'),
onPressed: () {
Navigator.pop(ctx);
},
),
CupertinoDialogAction(
child: const Text('确定'),
onPressed: () {
openAppSettings();
Navigator.pop(ctx);
// 打开手机上该app权限的页面
},
),
],
);
});
} else {
return true;
}
return false;
}
///
static Future<void> chooseCamera({
required BuildContext context,
int? max,
String? oSSAccessKeyId,
String? policy,
String? callback,
String? signature,
String? ossDirectory,
String? ossHost,
Function? chooseImages,
bool? isVideo,
Widget? isAddOtherWidget,
bool? isShowLoading,
}) async {
//
showCupertinoModalPopup(
context: context,
builder: (BuildContext ctx) {
return isVideo == true
? CupertinoActionSheet(
title: const Text('上传视频'),
message: Text('请选择视频'),
actions: <Widget>[
CupertinoActionSheetAction(
child: const Text('视频库'),
onPressed: () {
openGallery(
max: max,
isVideo: isVideo,
oSSAccessKeyId: oSSAccessKeyId ?? '',
ossHost: ossHost ?? '',
ossDirectory: ossDirectory ?? '',
policy: policy ?? '',
callback: callback ?? '',
signature: signature ?? '',
chooseImages: (list) => chooseImages?.call(list),
);
Get.back();
},
),
],
cancelButton: CupertinoActionSheetAction(
isDefaultAction: true,
child: const Text('取消'),
onPressed: () {
Get.back();
},
),
)
: CupertinoActionSheet(
title: const Text('上传图片'),
message: (max == null || max == 0) ? null : Text('请选择上传方式\n相册最多${max ?? 9}'),
actions: isAddOtherWidget != null
? <Widget>[
isAddOtherWidget,
CupertinoActionSheetAction(
child: const Text('拍照上传'),
onPressed: () {
openCamera(
oSSAccessKeyId: oSSAccessKeyId ?? '',
ossHost: ossHost ?? '',
ossDirectory: ossDirectory ?? '',
policy: policy ?? '',
callback: callback ?? '',
signature: signature ?? '',
chooseImages: (list) => chooseImages?.call(list),
);
Get.back();
},
),
CupertinoActionSheetAction(
child: const Text('相册'),
onPressed: () {
openGallery(
max: max,
oSSAccessKeyId: oSSAccessKeyId ?? '',
ossHost: ossHost ?? '',
ossDirectory: ossDirectory ?? '',
policy: policy ?? '',
callback: callback ?? '',
signature: signature ?? '',
chooseImages: (list) => chooseImages?.call(list),
);
Get.back();
},
),
]
: <Widget>[
CupertinoActionSheetAction(
child: const Text('拍照上传'),
onPressed: () {
openCamera(
oSSAccessKeyId: oSSAccessKeyId ?? '',
ossHost: ossHost ?? '',
ossDirectory: ossDirectory ?? '',
policy: policy ?? '',
callback: callback ?? '',
signature: signature ?? '',
chooseImages: (list) => chooseImages?.call(list),
);
Get.back();
},
),
CupertinoActionSheetAction(
child: const Text('相册'),
onPressed: () {
openGallery(
max: max,
oSSAccessKeyId: oSSAccessKeyId ?? '',
ossHost: ossHost ?? '',
ossDirectory: ossDirectory ?? '',
policy: policy ?? '',
callback: callback ?? '',
signature: signature ?? '',
isShowLoading: isShowLoading,
chooseImages: (list) => chooseImages?.call(list),
);
Get.back();
},
),
],
cancelButton: CupertinoActionSheetAction(
isDefaultAction: true,
child: const Text('取消'),
onPressed: () {
Get.back();
},
),
);
});
}
//
static openCamera({
Function? chooseImages,
String? oSSAccessKeyId,
String? policy,
String? callback,
String? signature,
String? ossDirectory,
String? ossHost,
}) async {
XFile? file = await ImagePicker().pickImage(
source: ImageSource.camera,
);
if (file == null) {
Get.back();
} else {
String imgPath = await saveNetworkImg(
file,
oSSAccessKeyId: oSSAccessKeyId ?? '',
ossHost: ossHost ?? '',
ossDirectory: ossDirectory ?? '',
policy: policy ?? '',
callback: callback ?? '',
signature: signature ?? '',
);
chooseImages?.call([imgPath]);
}
}
static openGallery({
Function? chooseImages,
String? oSSAccessKeyId,
String? policy,
String? callback,
String? signature,
String? ossDirectory,
String? ossHost,
int? max,
bool? isVideo,
bool? isShowLoading,
}) async {
if (isVideo == true) {
final List<AssetEntity>? result = await AssetPicker.pickAssets(
Get.context!,
pickerConfig: AssetPickerConfig(maxAssets: 1, requestType: RequestType.video),
);
final File? video = await result?.first.file;
String path = await saveNetworkImgGallery(
video?.path ?? '',
fileType: 'mp4',
oSSAccessKeyId: oSSAccessKeyId ?? '',
ossHost: ossHost ?? '',
ossDirectory: ossDirectory ?? '',
policy: policy ?? '',
callback: callback ?? '',
signature: signature ?? '',
);
chooseImages?.call([path]);
} else {
final List<AssetEntity>? result = await AssetPicker.pickAssets(
Get.context!,
pickerConfig: AssetPickerConfig(maxAssets: max ?? 50),
);
/// 临时存储选中的图片
final List<XFile> selectedFiles = [];
if (result != null && result.isNotEmpty) {
for (int i = 0; i < result.length; i++) {
final File? file = await result[i].file;
if (file != null) {
/// 获取文件扩展名
final String extension = file.absolute.path.split('.').last;
/// 压缩并保存到临时文件
final XFile? compressedFile = await FlutterImageCompress.compressAndGetFile(
file.absolute.path, '${file.parent.path}/${DateTime.now().millisecondsSinceEpoch}_compressed.$extension',
quality: 80, minWidth: 1920, minHeight: 1080);
if (compressedFile != null) {
selectedFiles.add(compressedFile);
/// 删除临时文件
File(compressedFile.path).deleteSync();
}
}
}
}
/// 上传选中的图片
List<String> list = [];
for (var element in selectedFiles) {
String path = await saveNetworkImgGallery(
element.path,
oSSAccessKeyId: oSSAccessKeyId ?? '',
ossHost: ossHost ?? '',
ossDirectory: ossDirectory ?? '',
policy: policy ?? '',
callback: callback ?? '',
signature: signature ?? '',
isShowLoading: isShowLoading,
);
list.add(path);
}
chooseImages?.call(list);
}
}
// 保存网络图片
static Future<String> saveNetworkImg(
XFile file, {
String? oSSAccessKeyId,
String? policy,
String? callback,
String? signature,
String? ossDirectory,
String? ossHost,
}) async {
// print("file.path ===== ${file.path}");
String string = await UploadOss.upload(
file.path,
fileType: "jpg",
oSSAccessKeyId: oSSAccessKeyId ?? '',
ossHost: ossHost ?? '',
ossDirectory: ossDirectory ?? '',
policy: policy ?? '',
callback: callback ?? '',
signature: signature ?? '',
);
// print("Gallery ===string== $string");
return string;
}
// 保存网络图片
static Future<String> saveNetworkImgGallery(
String path, {
String? fileType,
String? oSSAccessKeyId,
String? policy,
String? callback,
String? signature,
String? ossDirectory,
String? ossHost,
bool? isShowLoading,
}) async {
String string = await UploadOss.upload(
path,
fileType: fileType ?? "jpg",
oSSAccessKeyId: oSSAccessKeyId ?? '',
ossHost: ossHost ?? '',
ossDirectory: ossDirectory ?? '',
policy: policy ?? '',
callback: callback ?? '',
signature: signature ?? '',
isShowLoading: isShowLoading,
);
return string;
}
}