Flutter 选择图片文件上传七牛云

688 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情

前言

前段时间刚好遇到一个需求,需要将本地图片上传到服务器(七牛云),以便后续使用到图片文件。需求总体功能流程是:

1、点击添加图片按钮

2、打开相册 || 打开相机

3、确认图片

4、将图片上传七牛云并显示在页面上

涉及到的主要功能是将单张图片上传到七牛云服务器特定的“桶” ("🪣"?什么“🪣”?第一次接触七牛云的我一脸茫然😨,后续了解了一下“七牛云存储桶”,类似于我们在七牛云文件夹)。

现在已经有了七牛云Flutter版本的SDK,提供抽象的接口用于快速使用七牛的对象存储功能,所以很多事情并不需要我们去做,极大的降低了我们的工作量。

涉及依赖

dio: # 网络库

permission_handler: # 权限检测

image_picker: # 系统权限

qiniu_flutter_sdk: # 七牛云

功能涉及到了网络请求相册权限,但是文章不会重点记录到,可以通过pub.flutter-io.cn/diopermission_handler依赖进行进一步了解。

设计思路

1、定义上传图片的selectAndUpLoadImage方法,并定义一个UploadResult类,作为上传结果的返回值;

 class UploadResult {
   final String filePath; // 本地的图片地址,用于UI展示
   final String uploadImagePath; // 上传成功后的图片地址,用于传给后端
 ​
   UploadResult(this.filePath, this.uploadImagePath);
 }
 ​
 /// isGetCamera为可选参数 ture:拍照 false:相册
 Future<UploadResult?> selectAndUpLoadImage({bool isGetCamera = false}) async{ 
 }

2、判断用户选择的传图方式

 /// isGetCamera为可选参数 ture:拍照 false:相册
 final XFile? file = await ImagePicker().pickImage(source: isGetCamera ? ImageSource.camera : ImageSource.gallery);
   if (file == null) {
     return null;
   }

3、选择相应图片后,需要进行以下一系列的操作:

1、调用获取七牛云Token的后端接口,获取Token、fullname和url等字段信息;

2、利用获取到的Token和fullname值,直接调用七牛云依赖提供的方法,上传图片信息;

3、调用后端提供的接口,获取相应图片的URL值。

selectAndUpLoadImage方法代码如下:

 /// 1、调用获取七牛云Token的后端接口,获取Token、fullname和url字段信息;
   // categoryCode为“桶”的名称,filename为文件名可自定义。两者是获取"七牛云"token时接口参数,具体参数根据具体情况进行传值。
   String categoryCode = 'myImgFolder';
   String filename = file.path.toString().substring(file.path.lastIndexOf('/') + 1);
 ​
   // getQNYToken方法调用了后端接口,获取"七牛云"token、fullname等字段。
   String returnData = await getQNYToken(
     categoryCode: categoryCode,
     filename: filename,
   );
 ​
 /// 2、利用获取到的Token和fullname值,直接调用七牛云依赖提供的方法,上传图片信息;
   var split = returnData.split('---');
   String token = split[0];
   String fullname = split[1];
   //调用七牛云依赖方法
   await saveQNYFile(File(file.path), token, fullname);
 ​
 /// 3、调用后端提供的接口,调用方式与"getQNYToken"类似,返回相应图片的URL值。
   var uploadImagePath = await getQNYUrls(categoryCode, [split[2]]);
   return UploadResult(
     file.path,
     uploadImagePath,
   );
 }

getQNYTokensaveQNYFile方法如下:

 ///获取"七牛云"token
 Future<String> getQNYToken({
   required String categoryCode,
   required String filename,
 }) async {
   String myData = '';
   Map<String, dynamic> map = HashMap();
   map['categoryCode'] = categoryCode;
   map['filename'] = filename;
   // 调用接口(网络请求已封装,具体请求方式根据具体项目决定)
   var result = await HttpApi.getUploadToken(map);
   var resultData = result.data['data'];
   // 写法略显潦草,有待改善
   myData = resultData['token'] + '---' +  resultData['fullname'] + '---' + resultData['url'] ;
   return myData;
 }
 ​
 ///保存七牛云图片
 Future<String?> saveQNYFile(File file, String token, String key) async {
   // 创建 storage 对象
   Storage storage = Storage();
   // 创建 putController 对象
   PutController putController = PutController();
   // 添加任务进度监听
   putController.addProgressListener((double percent) {
     print('任务进度变化:已发送:$percent');
   });
   // 添加文件发送进度监听
   putController.addSendProgressListener((double percent) {
     print('已上传进度变化:已发送:$percent');
   });
   // 添加任务状态监听
   putController.addStatusListener((StorageStatus status) {
     print('状态变化: 当前任务状态:$status');
   });
   await storage.putFile(file, token, options: PutOptions(controller: putController, key: key));
   return '';
 }

截屏2022-08-15 14.49.01

注: Storage.putFile接口内部的key值如果不传则后端自动生成;

saveQNYFile方法在创建 Storage 时,一般是不需要自己去实现内部行为的。但是根据需求也可以传入一个 Config 控制内部的一些行为:

 // 创建 storage 对象
   storage = Storage(Config(
     // 通过自己的 hostProvider 来使用自己的 host 进行上传
     hostProvider: HostProvider,
     // 可以通过实现 cacheProvider 来自己实现缓存系统支持分片断点续传
     cacheProvider: CacheProvider,
     // 如果你需要对网络请求进行更基础的一些操作,你可以实现自己的 HttpClientAdapter 处理相关行为
     httpClientAdapter: HttpClientAdapter,
     // 设定网络请求重试次数
     retryLimit: 3,
     ));

总结

其实选择图片文件上传七牛云的功能总体难度并不大,因为许多难点七牛云的flutter SDK已经帮我们解决了。我们主要是明确功能的流程:

1、选择图片后,通过服务器获取七牛云相应的token;
2、调用七牛云提供的API上传图片;
3、通过服务器获取上传图片的URL。