专栏首页万物皆可Serverless【玩转腾讯云】万物皆可Serverless之在Flutter中写一个Dart原生腾讯云对象存储插件
原创

【玩转腾讯云】万物皆可Serverless之在Flutter中写一个Dart原生腾讯云对象存储插件

万物皆可Serverless系列文章

  1. 万物皆可Serverless之免费搭建自己的不限速大容量云盘(5TB)
  2. 万物皆可Serverless之使用云函数Timer触发器实现每天自动定时打卡
  3. 万物皆可Serverless之使用SCF+COS快速开发全栈应用
  4. 万物皆可Serverless之使用SCF+COS免费运营微信公众号
  5. 万物皆可Serverless之使用SCF快速部署验证码识别接口
  6. 万物皆可Serverless之Kaggle+SCF端到端验证码识别从训练到部署
  7. 万物皆可Serverless之借助微信公众号简单管理用户激活码
  8. 万物皆可Serverless之使用SCF+COS给未来写封信
  9. 万物皆可Serverless之在Flutter中快速接入腾讯云开发
  10. 万物皆可Serverless之在Flutter中写一个Dart原生腾讯云对象存储插件
  11. 万物皆可Serverless之我的Serverless之路

一、本文介绍

在上一篇文章中,我们尝试在Flutter中接入了腾讯云开发SDK

不过在有些应用场景下我们只需要用到腾讯云对象存储的能力,

比如将用户头像上传存储到自己的对象存储桶中,然后返回文件下载链接保存到本地数据库中,

这时候用云开发的话就有点高射炮打蚊子-->大材小用的感觉了。

所以这里我就带大家直接上手从头写一个Dart原生的腾讯云对象存储插件

废话少说,上图

直接在dart vm里调试

注意,

这里我是直接在windows本地的dart vm里运行的示例代码哈,

并不需要连接手机或者设备虚拟机去调试运行

因为这是Dart原生应用,放到哪里都可以运行的奥~

二、开始教程

第一步:创建Package

我们根据Flutter官方文档 https://flutter.dev/docs/development/packages-and-plugins/developing-packages

先创建一个名为 tencent_cloud_cos 的package

flutter create --template=package tencent_cloud_cos

创建成功

创建完之后,你的package目录应该是和上图一样的,下面我们就来编写插件

第二步:导入依赖

打开项目根目录下的pubspec.yaml配置文件,添加必要依赖

dependencies:
  flutter:
    sdk: flutter

  dio: ^3.0.9
  crypto: ^2.1.3

这里我们仅添加了dio和crypto两个dart原生依赖库,分别用来进行http请求和请求的加密签名工作

flutter pub get

当然,配置好依赖之后不要忘记下载安装一下依赖

第三步:编写插件

Life is short, show me the code.

打开lib/tencent_cloud_cos.dart文件,修改代码如下

// @author = WJG.
// @email = idootop@163.com
// @date = 2020-04-19

// @dart = 2.7

library tencent_cloud_cos;


import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:crypto/crypto.dart';

/// 腾讯云对象存储工具类
/// 使用腾讯云secret_id,secret_key和存储桶地址来初始化
///
///   ```dart
///    String secret_id='xxxxxxx';
///    String secret_key='xxxxxxx';
///    String bucket_host='https://xxxxxx.cos.xxxxx.myqcloud.com';
///    Cos cos = Cos(secret_id, secret_key, bucket_host);
///   ```
/// 上传/更新文件
///   ```dart
///    String imgUrl = await cos.upload('/example.jpg', File('example.jpg').readAsBytesSync());
///   ```
/// 下载文件
///   ```dart
///    bool success = await cos.download(imgUrl, 'download/example.jpg');
///   ```
/// 删除文件
///   ```dart
///    bool success = await cos.delete('/example.jpg');
///   ```
class Cos {
  Dio dio = Dio();
  String id;
  String key;
  String host;

  Cos(this.id, this.key, this.host);

  /// 上传文件成功后返回文件下载链接
  ///
  /// `path` : 存储桶文件存放路径
  ///
  /// `bytes` : 待上传文件二进制数组
  ///
  /// `params` : 请求参数
  ///
  /// `headers` : 请求头部
  ///
  /// `progress` : 上传进度回调函数,示例
  ///   ```dart
  ///   progress(int count, int total) {
  ///     double progress = (count / total) * 100;
  ///     if (progress % 5 == 0) print('上传进度---> ${progress.round()}%');
  ///   }
  ///  ```
  Future<String> upload(String path, List<int> bytes,
      {Map<String, String> params,
      Map<String, String> headers,
      Function(int, int) progress}) async {
    String url = host + path;
    params = params ?? Map<String, String>();
    Options options = Options();
    options.headers = headers ?? Map<String, String>();
    options.headers['content-length'] =
        bytes.length.toString(); // 设置content-length,否则无法监听文件上传进度
    //对put上传请求签名
    options.headers['Authorization'] =
        sign('put', path, headers: options.headers, params: params);
    try {
      Response response = await dio.put(url,
          data: Stream.fromIterable(bytes.map((e) => [e])), //bytes转为Stream
          onSendProgress: progress ??
              (int count, int total) {
                double progress = (count / total) * 100;
                if (progress % 5 == 0) print('上传进度---> ${progress.round()}%');
              },
          queryParameters: params,
          options: options);
      return response.statusCode == 200 ? url : '';
    } on DioError catch (e) {
      print('Error:' + e.message);
      return '';
    }
  }

  /// 删除在线文件
  ///
  /// `path` : 存储桶文件存放路径
  ///
  /// `params` : 请求参数
  ///
  /// `headers` : 请求头部
  ///
  Future<bool> delete(String path,
      {Map<String, String> params, Map<String, String> headers}) async {
    String url = host + path;
    params = params ?? Map<String, String>();
    Options options = Options();
    options.headers = headers ?? Map<String, String>();
    //对请求签名
    options.headers['Authorization'] =
        sign('DELETE', path, headers: options.headers, params: params);
    try {
      Response response =
          await dio.delete(url, queryParameters: params, options: options);
      return response.statusCode == 204 ? true : false;
    } on DioError catch (e) {
      print('Error:' + e.message);
      return false;
    }
  }

  /// 下载文件
  ///
  /// `urlPath` : 存储桶文件存放路径
  ///
  /// `savePath` : 文件保存路径
  ///
  /// `progress` : 下载进度回调函数,示例
  ///   ```dart
  ///   progress(int count, int total) {
  ///     double progress = (count / total) * 100;
  ///     if (progress % 5 == 0) print('下载进度---> ${progress.round()}%');
  ///   }
  ///  ```
  Future<bool> download(String urlPath, String savePath,
      {Function(int, int) progress}) async {
    try {
      await dio.download(urlPath, savePath,
          options: Options(receiveTimeout: 0),
          onReceiveProgress: progress ??
              (int count, int total) {
                double progress = (count / total) * 100;
                if (progress % 5 == 0) print('下载进度---> ${progress.round()}%');
              });
      return true;
    } on DioError catch (e) {
      print('Error:' + e.message);
      return false;
    }
  }

  /// 对http请求进行签名,返回Authorization签名字符串
  ///
  /// `httpMethod` : 请求方法
  ///
  /// `httpUrl` : 请求地址
  ///
  /// `params` : 请求参数
  ///
  /// `headers` : 请求头部
  ///
  String sign(String httpMethod, String httpUrl,
      {Map<String, String> headers,
      Map<String, String> params,
      int expire = 10}) {
    headers = headers ?? Map();
    params = params ?? Map();
    headers = headers.map((key, value) => MapEntry(key.toLowerCase(), value));
    params = params.map((key, value) => MapEntry(key.toLowerCase(), value));
    List<String> headerKeys = headers.keys.toList();
    headerKeys.sort();
    String headerList = headerKeys.join(';');
    String httpHeaders = headerKeys
        .map((item) => '$item=${Uri.encodeFull(headers[item])}')
        .join('&');
    List<String> paramKeys = params.keys.toList();
    paramKeys.sort();
    String urlParamList = paramKeys.join(';');
    String httpParameters = paramKeys
        .map((item) => '$item=${Uri.encodeFull(params[item])}')
        .join('&');
    String httpString =
        '${httpMethod.toLowerCase()}\n$httpUrl\n$httpParameters\n$httpHeaders\n';
    String httpStringData = sha1.convert(utf8.encode(httpString)).toString();
    int timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;
    String keyTime = '$timestamp;${timestamp + expire}';
    String signKey =
        Hmac(sha1, utf8.encode(key)).convert(utf8.encode(keyTime)).toString();
    String stringToSign = 'sha1\n$keyTime\n$httpStringData\n';
    String signature = Hmac(sha1, utf8.encode(signKey))
        .convert(utf8.encode(stringToSign))
        .toString();
    return 'q-sign-algorithm=sha1&q-ak=$id&q-sign-time=$keyTime&q-key-time=$keyTime&q-header-list=$headerList&q-url-param-list=$urlParamList&q-signature=$signature';
  }
}

这里我就不再详细解释了,代码里都写得很清楚

请求签名

请求签名过程可参考腾讯云官方文档,地址 https://cloud.tencent.com/document/product/436/7778

第四步:代码示例

在项目根目录创建一个bin目录,然后在里面新建一个main.dart

示例程序

填上以下测试代码

import 'dart:io';
import '../lib/tencent_cloud_cos.dart';

main() async {
  String secret_id = 'xxxxxxxxxx'; //你的腾讯云secret_id
  String secret_key = 'xxxxxxxxxxxxxxxxx'; //你的腾讯云secret_key
  String bucket_host = 'https://xxxxxx-6666666.cos.ap-chongqing.myqcloud.com'; //你的对象存储桶访问域名
  Cos cos = Cos(secret_id, secret_key, bucket_host);
  String imgUrl = await cos.upload('/example.jpg', File('example.jpg').readAsBytesSync());
  await cos.download(imgUrl, 'example2.jpg');
  await cos.delete('/example.jpg');
}

然后按F5调试运行一下吧,没啥意外你就可以看到文章一开始那张图了

测试成功

三、文章最后

哈?这也算Serverless?

你可能会疑问,这不是介绍腾讯云对象存储吗,和serverless有啥关系~

哈哈,我只能说cos也是serverless的一种表现形式,

只要是不需要自己购买服务器运行的服务,大体都可以称之为serverless(无服务器)

以上,逃~

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【玩转腾讯云】征文活动获奖名单公布

    由云+社区联合腾讯云免费体验馆及各产品团队举办【玩转腾讯云】征文活动,吸引入驻作者积极参加,非常感谢各位作者的参与。经过评委老师从产品创新性、实用性、可借鉴性、...

    云加社区
  • 【玩转腾讯云】万物皆可Serverless之我的Serverless之路

    我最早接触Serverless大概是在18年6月,那时候我在阿里云的学生机刚好到期,

    乂乂又又
  • 万物皆可 Serverless 之我的 Serverless 之路

    我最早接触 Serverless 大概是在 18 年 6 月,那时候我在阿里云的学生机刚好到期,那台机子上我有装宝塔面板,然后在上面只放了一个 Typecho ...

    腾讯云serverless团队
  • 【玩转腾讯云】万物皆可Serverless之在Flutter中快速接入腾讯云开发

    本文将带领大家按照云开发的官方文档在Flutter中快速接入一下腾讯云开发SDK,

    乂乂又又
  • 三分钟给女票写个“彩虹屁”bot | 🏆 技术专题第七期征文

    前几天 ~女票~ -> 女同学甩给我上面那张图,说她也想每天都能收到甜甜的彩虹屁。好家伙,我一寻思这不就是个彩虹屁bot嘛,自欺欺人地说?但既然她开口了,那咱必...

    乂乂又又
  • 【玩转腾讯云】万物皆可Serverless之使用SCF+COS快速开发全栈应用

    直到后来我接触到腾讯云无服务器云函数,让前端可以快速获得后端的能力同时,一并解决了前端数据请求跨域的问题。

    乂乂又又
  • 【玩转腾讯云】万物皆可Serverless之使用SCF+COS给未来写封信

    你也可以访问 http://letter.idoo.top/letter 来亲自体验一下(仅供测试之用,不保证服务一直可用)

    乂乂又又
  • 【玩转腾讯云】万物皆可Serverless之免费搭建自己的不限速大容量云盘(5TB)

    当我们在网络上好不容易找到资源准备下载时,却发现下载速度最快不过200、300KB/S,

    乂乂又又
  • 【玩转腾讯云】万物皆可Serverless之借助微信公众号简单管理用户激活码

    就可以添加并回复一个指定有效期的会员激活码,实现了在微信公众号简单管理用户激活码的需求

    乂乂又又
  • 【玩转腾讯云】万物皆可Serverless之关于云函数冷热启动那些事儿

    然后我们再来看一下腾讯云云函数文档里的简介 https://cloud.tencent.com/document/product/583/9199

    乂乂又又
  • 【玩转腾讯云】万物皆可Serverless之使用云函数Timer触发器实现每天自动定时打卡

    模板函数的描述里写着“本示例代码的功能是定时拨测 URL 列表中的地址,并通过邮件发送告警”

    乂乂又又
  • 【玩转腾讯云】万物皆可Serverless之使用SCF+COS免费运营微信公众号

    在上一篇《万物皆可Serverless之使用SCF+COS快速开发全栈应用》教程中,

    乂乂又又
  • 【玩转腾讯云】万物皆可Serverless之Kaggle+SCF端到端验证码识别从训练到部署

    近些年来人工智能迅速发展,尤其是在深度学习神经网络这一块生态尤为繁荣,各种算法和模型层出不穷。

    乂乂又又
  • 【玩转腾讯云】万物皆可Serverless之使用SCF快速部署验证码识别接口

    如果部署在服务器端就需要自己去搭建配置网络环境并编写调用接口,这是一个极其繁琐耗时的过程。

    乂乂又又
  • 国内首发,这款 Serverless 云原生一体化部署工具正式开源!

    12 月 19 日,腾讯在 2020 Techo Park 开发者大会上集中发布了三大开源项目。其中,云开发 CloudBase Framework 作为腾讯开...

    腾讯云开发TCB
  • 如何把 Flutter 云端一体化做到极致?

    云开发 CloudBase 提供了强大的一站式后端服务,并且和微信团队合作推出了「小程序·云开发」,服务了超过 50 万开发者。

    腾讯云开发TCB
  • 开源生态建设卓见成效,腾讯云原生已覆盖百万开发者

    在刚刚过去的2020云原生技术大会上,主办方云原生基金会(CNCF)总经理Priyanka Sharma女士在演讲中表示:“目前在云原生Kubernetes相...

    腾讯开源
  • 新能力 | 云开发基于Flutter的云端一体化探索

    Flutter 框架是当下移动客户端开发最热门的解决方案,除了可以跨 Android、iOS、web 三端之外, 还能跨越第四端吗?答案是肯定的,跨越的第四端就...

    腾讯云开发TCB
  • 掘金 x 腾讯云联合征文 | 万物皆可 Serverless

    Serverless,即无服务器架构,是一种新的架构方式。目前也是非常热门的一种技术,很多大公司都在往 Serverless 这个方向上发力。 ? 无服务器架...

    腾讯云serverless团队

扫码关注云+社区

领取腾讯云代金券