import 'dart:convert'; import 'dart:io'; import 'dart:math'; import 'dart:typed_data'; import 'dart:ui' as ui; import 'dart:ui'; import 'package:crypto/crypto.dart'; import "package:dio/dio.dart"; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_common/utils/toast_utils.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:image_gallery_saver_plus/image_gallery_saver_plus.dart'; // import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; class UploadOss { /* * @params file 要上传的文件对象 * @params rootDir 阿里云oss设置的根目录文件夹名字 * @param fileType 文件类型例如jpg,mp4等 * @param callback 回调函数我这里用于传cancelToken,方便后期关闭请求 * @param onSendProgress 上传的进度事件 */ static Future upload( String path, { String rootDir = "moment", required String fileType, required String oSSAccessKeyId, required String policy, required String callback, required String signature, required String ossDirectory, required String ossHost, bool? isShowLoading, }) async { // 生成oss的路径和文件名我这里目前设置的是moment/20201229/test.mp4 String pathName = "$rootDir/${getDate()}/app-${getRandom(12)}.$fileType"; // 请求参数的form对象 FormData formdata = FormData.fromMap({ 'OSSAccessKeyId': oSSAccessKeyId, 'policy': policy, 'callback': callback, 'signature': signature, 'key': '$ossDirectory$pathName', //上传后的文件名 'success_action_status': '200', 'file': MultipartFile.fromFileSync( path, contentType: fileType == 'mp4' ? null : DioMediaType("image", "jpg"), filename: "${getRandom(12)}.$fileType", ), }); if (isShowLoading == true) { await EasyLoading.show( // status: 'loading...', maskType: EasyLoadingMaskType.black, ); } Dio dio = Dio(); dio.options.responseType = ResponseType.plain; // dio.options.method = 'put'; // dio.options.contentType = "multipart/form-data;image/jpg"; try { // 发送请求 Response response = await dio.post( ossHost, data: formdata, options: Options( contentType: "multipart/form-data;image/jpg", headers: {'Content-Type': 'multipart/form-data;image/jpg'}, ), ); print("response ===== $response"); EasyLoading.dismiss(); // 成功后返回文件访问路径 return "$ossHost/$ossDirectory$pathName"; } on DioError catch (e) { EasyLoading.dismiss(); print("e.message ===== ${e.message}"); print("e.data ===== ${e.response?.data}"); // print("e.headers ===== ${e.response?.headers}"); // print("e.extra ===== ${e.response?.extra}"); return ''; } } /* * 生成固定长度的随机字符串 * */ static String getRandom(int num) { String alphabet = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"; String left = ""; for (var i = 0; i < num; i++) { // right = right + (min + (Random().nextInt(max - min))).toString(); left = left + alphabet[Random().nextInt(alphabet.length)]; } return left; } /// 获取日期 static String getDate() { DateTime now = DateTime.now(); return "${now.year}${now.month}${now.day}"; } } class UploadWidgetOss { static Future uploadWidgetImage( GlobalKey globalKey, { required String oSSAccessKeyId, required String policy, required String callback, required String signature, required String ossDirectory, required String ossHost, }) async { ///通过globalkey将Widget保存为ui.Image ui.Image _image = await getImageFromWidget(globalKey); ///异步将这张图片保存在手机内部存储目录下 String? localImagePath = await saveImageByUIImage(_image, isEncode: false); ///保存完毕后关闭当前页面并将保存的图片路径返回到上一个页面 String? url = await UploadOss.upload( localImagePath, fileType: "png", oSSAccessKeyId: oSSAccessKeyId, policy: policy, callback: callback, signature: signature, ossDirectory: ossDirectory, ossHost: ossHost, ); return url; } // 将一个Widget转为image.Image对象 static Future getImageFromWidget(GlobalKey globalKey) async { // globalKey为需要图像化的widget的key RenderRepaintBoundary? boundary = globalKey.currentContext?.findRenderObject() as RenderRepaintBoundary?; // 转换为图像 ui.Image img = await boundary!.toImage(pixelRatio: 2); return img; } ///将指定的文件保存到目录空间中。 ///[image] 这里是使用的ui包下的Image ///[picName] 保存到本地的文件(图片)文件名,如test_image ///[endFormat]保存到本地的文件(图片)文件格式,如png, ///[isReplace]当本地存在同名的文件(图片)时,true就是替换 ///[isEncode]对保存的文件(图片)进行编码 /// 最终保存到本地的文件 (图片)的名称为 picName.endFormat static Future saveImageByUIImage(ui.Image image, {String? picName, String endFormat = "png", bool isReplace = true, bool isEncode = true}) async { ///获取本地磁盘路径 /* * 在Android平台中获取的是/data/user/0/com.studyyoun.flutterbookcode/app_flutter * 此方法在在iOS平台获取的是Documents路径 */ Directory appDocDir = await getApplicationDocumentsDirectory(); String appDocPath = appDocDir.path; ///拼接目录 if (picName == null || picName.trim().isEmpty) { ///当用户没有指定picName时,取当前的时间命名 picName = "${DateTime.now().millisecond.toString()}.$endFormat"; } else { picName = "$picName.$endFormat"; } if (isEncode) { ///对保存的图片名字加密 picName = md5.convert(utf8.encode(picName)).toString(); } appDocPath = "$appDocPath/$picName"; ///校验图片是否存在 var file = File(appDocPath); bool exist = await file.exists(); if (exist) { if (isReplace) { ///如果图片存在就进行删除替换 ///如果新的图片加载失败,那么旧的图片也被删除了 await file.delete(); } else { ///如果图片存在就不进行下载 return ""; } } ByteData? byteData = await image.toByteData(format: ImageByteFormat.png); Uint8List pngBytes = byteData!.buffer.asUint8List(); ///将Uint8List的数据格式保存 await File(appDocPath).writeAsBytes(pngBytes); return appDocPath; } //申请存本地相册权限 static Future getPormiation() async { if (Platform.isIOS) { var status = await Permission.photos.status; if (status.isDenied) { Map statuses = await [ Permission.photos, ].request(); // saveImage(globalKey); } return status.isGranted; } else { var status = await Permission.storage.status; if (status.isDenied) { Map statuses = await [ Permission.storage, ].request(); } return status.isGranted; } } ///保存到相册 static void savePhoto(GlobalKey globalKey) async { RenderRepaintBoundary? boundary = globalKey.currentContext!.findRenderObject() as RenderRepaintBoundary?; double dpr = ui.window.devicePixelRatio; // 获取当前设备的像素比 var image = await boundary!.toImage(pixelRatio: dpr); // 将image转化成byte ByteData? byteData = await image.toByteData(format: ImageByteFormat.png); //获取保存相册权限,如果没有,则申请改权限 bool permition = await getPormiation(); var status = await Permission.photos.status; if (permition) { if (Platform.isIOS) { if (status.isGranted) { Uint8List images = byteData!.buffer.asUint8List(); final result = await ImageGallerySaverPlus.saveImage(images, quality: 60, name: "hello"); // EasyLoading.showToast("保存成功"); ToastUtils.showToast(msg: "保存成功"); } if (status.isDenied) { print("IOS拒绝"); } } else { //安卓 if (status.isGranted) { print("Android已授权"); Uint8List images = byteData!.buffer.asUint8List(); final result = await ImageGallerySaverPlus.saveImage(images, quality: 60); if (result != null) { // EasyLoading.showToast("保存成功"); ToastUtils.showToast(msg: "保存成功"); } else { print('error'); // toast("保存失败"); } } } } else { //重新请求--第一次请求权限时,保存方法不会走,需要重新调一次 savePhoto(globalKey); } } }