nvmms_aliyun_oss
一个访问阿里云oss并且支持STS临时访问凭证访问OSS的flutter库,基本上涵盖阿里云oss sdk的所有功能。⭐
注意:本项目大部分内容来源于 flutter_oss_aliyun。参考链接:https://pub.flutter-io.cn/packages/flutter_oss_aliyun ,原始代码仓库:https://github.com/huhx/flutter_oss_aliyun 。本仓库在原项目基础上进行了修改和更新。
flutter pub: https://pub.flutter-io.cn/packages/nvmms_aliyun_oss
oss sts document: https://help.aliyun.com/document_detail/100624.html
🐱 初始化Client
添加依赖
dependencies:
  nvmms_aliyun_oss: ^6.5.0 
初始化oss client, 这里我们提供两种方式
1. 提供sts server地址,需要后端添加这个api
Client.init(
    stsUrl: "server url get sts token",
    ossEndpoint: "oss-cn-beijing.aliyuncs.com",
    bucketName: "bucket name",
);
后端api至少需要返回以下数据:
{
  "AccessKeyId": "AccessKeyId",
  "AccessKeySecret": "AccessKeySecret",
  "SecurityToken": "SecurityToken",
  "Expiration": "2022-03-22T11:33:06Z"
}
2. 自定义authGetter得到Auth
Client.init(
    ossEndpoint: "oss-cn-beijing.aliyuncs.com",
    bucketName: "bucketName",
    authGetter: _authGetter
);
Auth _authGetter() {
  return Auth(
      accessKey: "accessKey",
      accessSecret: 'accessSecret',
      expire: '2023-02-23T14:02:46Z',
      secureToken: 'token',
  );
}
Integrate with get_it
injectable: https://pub.flutter-io.cn/packages/injectable
@module
abstract class OssProvider {
  @singleton
  Client client() {
    return Client.init(
      stsUrl: Env.stsUrl,
      ossEndpoint: Env.endpointUrl,
      bucketName: Env.bucketName,
    );
  }
}
你可以传入自定义的Dio
在init函数中,你可以传入dio,做到dio的定制化。比如日志或者其他的interceptors.
Client.init(
    stsUrl: "server url get sts token",
    ossEndpoint: "oss-cn-beijing.aliyuncs.com",
    bucketName: "bucket name",
    dio: Dio(BaseOptions(connectTimeout: 9000)),
);
🎨 使用
- 文件上传
- 追加文件上传
- 跨bucket文件复制
- 取消文件上传
- 批量文件上传
- 本地文件上传
- 批量本地文件上传
- 文件下载
- 查询文件是否存在
- 文件下载并保存
- 文件删除
- 批量文件删除
- 获取已签名的文件url
- 获取多个已签名的文件url
- 列举所有的存储空间
- 列举存储空间中所有文件
- 获取bucket信息
- 获取bucket的储容量以及文件数量
- 获取文件元信息
- regions的查询
- bucket acl的操作
- bucket policy的操作
文件上传
关于callback的使用: help.aliyun.com/document_detail/31989.htm?spm=a2c4g.11186623.0.0.73a830ffn45LMY#reference-zkm-311-hgb
final bytes = "file bytes".codeUnits;
await Client().putObject(
  bytes,
  "test.txt",
  option: PutRequestOption(
    onSendProgress: (count, total) {
      print("send: count = $count, and total = $total");
    },
    onReceiveProgress: (count, total) {
      print("receive: count = $count, and total = $total");
    },
    override: false,
    aclModel: AclMode.publicRead,
    storageType: StorageType.ia,
    headers: {"cache-control": "no-cache"},
    callback: Callback(
      callbackUrl: "callback url",
      callbackBody: "{\"mimeType\":\${mimeType}, \"filepath\":\${object},\"size\":\${size},\"bucket\":\${bucket},\"phone\":\${x:phone}}",
      callbackVar: {"x:phone": "android"},
      calbackBodyType: CalbackBodyType.json,
    ),       
  ),
);
PutRequestOption 字段说明,字段皆为非必需
| Filed | Default value | Description | 
|---|---|---|
| override | true | true: 允许覆盖同名Object false: 禁止覆盖同名Object | 
| aclModel | inherited | 1. publicWrite: 任何人(包括匿名访问者)都可以对该Object进行读写操作 2. publicRead: 只有该Object的拥有者可以对该Object进行写操作,任何人(包括匿名访问者)都可以对该Object进行读操作 3. private: 只有Object的拥有者可以对该Object进行读写操作,其他人无法访问该Object 4. inherited: 该Object遵循Bucket的读写权限,即Bucket是什么权限,Object就是什么权限 参考文档: help.aliyun.com/document_detail/100676.htm?spm=a2c4g.11186623.0.0.56637952SnxOWV#concept-blw-yqm-2gb | 
| storageType | Standard | 参考文档: help.aliyun.com/document_detail/51374.htm?spm=a2c4g.11186623.0.0.56632b55htpEQX#concept-fcn-3xt-tdb | 
追加文件上传
final Response<dynamic> resp = await Client().appendObject(
  Uint8List.fromList(utf8.encode("Hello World")),
  "test_append.txt",
);
final Response<dynamic> resp2 = await Client().appendObject(
  position: int.parse(resp.headers["x-oss-next-append-position"]?[0]),
  Uint8List.fromList(utf8.encode(", Fluter.")),
  "test_append.txt",
);
跨bucket复制文件
final Response<dynamic> resp = await Client().copyObject(
  const CopyRequestOption(
    sourceFileKey: 'test.csv',
    targetFileKey: "test_copy.csv",
    targetBucketName: "bucket_2"
  ),
);
取消文件上传
final CancelToken cancelToken = CancelToken();
final bytes = ("long long bytes" * 1000).codeUnits;
Client().putObject(
  Uint8List.fromList(utf8.encode(string)),
  "cancel_token_test.txt",
  cancelToken: cancelToken,
  option: PutRequestOption(
    onSendProgress: (count, total) {
      if (kDebugMode) {
        print("send: count = $count, and total = $total");
      }
      if (count > 56) {
        cancelToken.cancel("cancel the uploading.");
      }
    },
  ),
).then((response) {
  // success
  print("upload success = ${response.statusCode}");
}).catchError((err) {
  if (CancelToken.isCancel(err)) {
    print("error message = ${err.message}");
  } else {
    // handle other errors
  }
});
批量文件上传
await Client().putObjects([
  AssetEntity(
    filename: "filename1.txt",
    bytes: "files1".codeUnits,
    option: PutRequestOption(
      onSendProgress: (count, total) {
        print("send: count = $count, and total = $total");
      },
      onReceiveProgress: (count, total) {
        print("receive: count = $count, and total = $total");
      },
      aclModel: AclMode.private,
    ),
  ),
  AssetEntity(filename: "filename2.txt", bytes: "files2".codeUnits),
]);
本地文件上传
final Response<dynamic> resp = await Client().putObjectFile(
  "/Users/aaa.pdf",
  fileKey: "aaa.png",
  option: PutRequestOption(
    onSendProgress: (count, total) {
      print("send: count = $count, and total = $total");
    },
    onReceiveProgress: (count, total) {
      print("receive: count = $count, and total = $total");
    },
    aclModel: AclMode.private,
    callback: Callback(
      callbackUrl: callbackUrl,
      callbackBody:
          "{\"mimeType\":\${mimeType}, \"filepath\":\${object},\"size\":\${size},\"bucket\":\${bucket},\"phone\":\${x:phone}}",
      callbackVar: {"x:phone": "android"},
      calbackBodyType: CalbackBodyType.json,
    ),    
  ),
);
批量本地文件上传
final List<Response<dynamic>> resp = await Client().putObjectFiles(
  [
    AssetFileEntity(
      filepath: "//Users/private.txt",
      option: PutRequestOption(
        onSendProgress: (count, total) {
          print("send: count = $count, and total = $total");
        },
        onReceiveProgress: (count, total) {
          print("receive: count = $count, and total = $total");
        },
        override: false,
        aclModel: AclMode.private,
      ),
    ),
    AssetFileEntity(
      filepath: "//Users/splash.png",
      filename: "aaa.png",
      option: PutRequestOption(
        onSendProgress: (count, total) {
          print("send: count = $count, and total = $total");
        },
        onReceiveProgress: (count, total) {
          print("receive: count = $count, and total = $total");
        },
        override: true,
      ),
    ),
  ],
);
文件下载
await Client().getObject(
  "test.txt",
  onReceiveProgress: (count, total) {
    debugPrint("received = $count, total = $total");
  },
);
查询文件是否存在
final bool isExisted = await Client().doesObjectExist(
    "aaa.jpg",
);
文件下载并保存
await Client().downloadObject(
  "test.txt",
  "./example/test.txt",
  onReceiveProgress: (count, total) {
    debugPrint("received = $count, total = $total");
  },
);
文件删除
await Client().deleteObject("test.txt");
批量文件删除
await Client().deleteObjects(["filename1.txt", "filename2.txt"]);
获取已签名的文件url
需要注意的是: 这个操作并不安全,因为url包含security-token信息,即使过期时间比较短. 这个url可以直接在浏览器访问
final String url = await Client().getSignedUrl(
  "test.jpg",
  params: {"x-oss-process": "image/resize,w_10/quality,q_90"},
);
获取多个已签名的文件url
需要注意的是: 这个操作并不安全,因为url包含security-token信息,即使过期时间比较短
final Map<String, String> result = await Client().getSignedUrls(["test.txt", "filename1.txt"]);
列举所有的存储空间
列举请求者拥有的所有存储空间(Bucket)。您还可以通过设置prefix、marker或者max-keys参数列举满足指定条件的存储空间。参考: help.aliyun.com/document_detail/31957.html
final Response<dynamic> resp = await Client().listBuckets({"max-keys": 2});
列举存储空间中所有文件
接口用于列举存储空间(Bucket)中所有文件(Object)的信息。请求参数和返回结果,请参考: help.aliyun.com/document_detail/187544.html
final Response<dynamic> resp = await Client().listFiles({});
获取bucket信息
查看存储空间(Bucket)的相关信息。返回结果请参考: help.aliyun.com/document_detail/31968.html
final Response<dynamic> resp = await Client().getBucketInfo();
获取bucket的储容量以及文件数量
获取指定存储空间(Bucket)的存储容量以及文件(Object)数量。返回结果请参考: help.aliyun.com/document_detail/426056.html
final Response<dynamic> resp = await Client().getBucketStat();
获取文件元信息
final Response<dynamic> resp = await Client().getObjectMeta("huhx.csv");
regions的查询
- 查询所有
final Response<dynamic> resp = await Client().getAllRegions();
- 查询特定
final Response<dynamic> resp = await Client().getRegion("oss-ap-northeast-1");
bucket acl的操作
- 查询
final Response<dynamic> resp = await Client().getBucketAcl(
  bucketName: "bucket-name",
);
- 更新
final Response<dynamic> resp = await Client().putBucketAcl(
  AciMode.publicRead, 
  bucketName: "bucket-name",
);
bucket policy的操作
- 查询
final Response<dynamic> resp = await Client().getBucketPolicy(
  bucketName: "bucket-name",
);
- 更新
final Response<dynamic> resp = await Client().putBucketPolicy(
  {}, 
  bucketName: "bucket-name",
);
- 删除
final Response<dynamic> resp = await Client().deleteBucketPolicy(
  bucketName: "bucket-name",
);
Drop a ⭐ if it is help to you
Libraries
- nvmms_aliyun_oss
- Flutter widgets that make it easy to access aliyun oss.