在Flutter中从AWS S3上传和获取媒体文件

End*_*mic 5 amazon-s3 amazon-web-services dart flutter dart-2

我的flutter应用程序使用Firebase作为后端,但是我需要在s3存储桶中存储媒体文件(照片和视频)。任务是将从图像选择器检索到的媒体上传到s3中,并获取该URL,然后将该URL作为字符串存储在我的Firebase数据库中。

问题是缺少飞镖2的aws库或api。我在酒吧里发现了3个,但其中2个与飞镖2和1不兼容。有没有人用飞镖2在颤抖中实现这一点?欢迎任何建议。谢谢。

我找到的包是(pub.dartlang.org):aws_client,aws_interop,amazon_s3

Jon*_*Saw 5

有几种方法可以做到这一点。一种方法是使用Signature V4 签名您的请求,然后将文件签名POST到S3。

首先,创建一个策略助手:

import 'dart:convert';
import 'package:amazon_cognito_identity_dart/sig_v4.dart';

class Policy {
  String expiration;
  String region;
  String bucket;
  String key;
  String credential;
  String datetime;
  int maxFileSize;

  Policy(this.key, this.bucket, this.datetime, this.expiration, this.credential,
      this.maxFileSize,
      {this.region = 'us-east-1'});

  factory Policy.fromS3PresignedPost(
    String key,
    String bucket,
    String accessKeyId,
    int expiryMinutes,
    int maxFileSize, {
    String region,
  }) {
    final datetime = SigV4.generateDatetime();
    final expiration = (DateTime.now())
        .add(Duration(minutes: expiryMinutes))
        .toUtc()
        .toString()
        .split(' ')
        .join('T');
    final cred =
        '$accessKeyId/${SigV4.buildCredentialScope(datetime, region, 's3')}';
    final p = Policy(key, bucket, datetime, expiration, cred, maxFileSize,
        region: region);
    return p;
  }

  String encode() {
    final bytes = utf8.encode(toString());
    return base64.encode(bytes);
  }

  @override
  String toString() {
    return '''
{ "expiration": "${this.expiration}",
  "conditions": [
    {"bucket": "${this.bucket}"},
    ["starts-with", "\$key", "${this.key}"],
    {"acl": "public-read"},
    ["content-length-range", 1, ${this.maxFileSize}],
    {"x-amz-credential": "${this.credential}"},
    {"x-amz-algorithm": "AWS4-HMAC-SHA256"},
    {"x-amz-date": "${this.datetime}" }
  ]
}
''';
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,与保单助手签署您的请求,并通过进行上传http.MultipartRequest

import 'dart:convert';
import 'package:amazon_cognito_identity_dart/sig_v4.dart';

class Policy {
  String expiration;
  String region;
  String bucket;
  String key;
  String credential;
  String datetime;
  int maxFileSize;

  Policy(this.key, this.bucket, this.datetime, this.expiration, this.credential,
      this.maxFileSize,
      {this.region = 'us-east-1'});

  factory Policy.fromS3PresignedPost(
    String key,
    String bucket,
    String accessKeyId,
    int expiryMinutes,
    int maxFileSize, {
    String region,
  }) {
    final datetime = SigV4.generateDatetime();
    final expiration = (DateTime.now())
        .add(Duration(minutes: expiryMinutes))
        .toUtc()
        .toString()
        .split(' ')
        .join('T');
    final cred =
        '$accessKeyId/${SigV4.buildCredentialScope(datetime, region, 's3')}';
    final p = Policy(key, bucket, datetime, expiration, cred, maxFileSize,
        region: region);
    return p;
  }

  String encode() {
    final bytes = utf8.encode(toString());
    return base64.encode(bytes);
  }

  @override
  String toString() {
    return '''
{ "expiration": "${this.expiration}",
  "conditions": [
    {"bucket": "${this.bucket}"},
    ["starts-with", "\$key", "${this.key}"],
    {"acl": "public-read"},
    ["content-length-range", 1, ${this.maxFileSize}],
    {"x-amz-credential": "${this.credential}"},
    {"x-amz-algorithm": "AWS4-HMAC-SHA256"},
    {"x-amz-date": "${this.datetime}" }
  ]
}
''';
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,此方法要求您提供访问密钥和秘密密钥。如果您使用Cognito之类的服务,建议您获取一个临时访问密钥和秘密密钥。在此处找到使用临时访问的示例。

免责声明:我是Signature V4软件包的原始作者。

  • 嘿,早些时候这段代码对我来说工作得很好,但是在将 flutter sdk 更新到 3.3 后,我得到了 Failed host Lookup: 'bucketname.s3-us-east-1.amazonaws.com' (2认同)

小智 5

您可以使用包amazon_s3_cognito将图像上传和删除到 amazon s3。

我是该插件的作者,我们在许多项目中成功使用了该插件。

        import 'package:amazon_s3_cognito/amazon_s3_cognito.dart';
        import 'package:amazon_s3_cognito/aws_region.dart';

        String uploadedImageUrl = await AmazonS3Cognito.uploadImage(
                  _image.path, BUCKET_NAME, IDENTITY_POOL_ID);


        //Use the below code to upload an image to amazon s3 server
        //I advise using this method for image upload.
        String uploadedImageUrl = await AmazonS3Cognito.upload(
                    _image.path,
                    BUCKET_NAME,
                    IDENTITY_POOL_ID,
                    IMAGE_NAME,
                    AwsRegion.US_EAST_1,
                    AwsRegion.AP_SOUTHEAST_1)
Run Code Online (Sandbox Code Playgroud)

_image.path = 要上传的图片的路径(flutter中的file.path方法)

IMAGE_NAME = 此图像使用您在此处指定的名称上传到 s3 服务器。

        //use below code to delete an image
         String result = AmazonS3Cognito.delete(
                    BUCKET_NAME,
                    IDENTITY_POOL_ID,
                    IMAGE_NAME,
                    AwsRegion.US_EAST_1,
                    AwsRegion.AP_SOUTHEAST_1)
Run Code Online (Sandbox Code Playgroud)

要获取图像,您可以使用cached_network_image
。CachedNetworkImage可以直接使用或通过ImageProvider使用。

    CachedNetworkImage(
            imageUrl: "http://via.placeholder.com/350x150",
            placeholder: (context, url) => new CircularProgressIndicator(),
            errorWidget: (context, url, error) => new Icon(Icons.error),
         ),`enter code here`


    Future<String> _getFilePath(Asset asset,ListingImage listingImage) async{
       try {
         if (!isUploadCancelled) {
           // getting a directory path for saving
           final directory = await getTemporaryDirectory();
           String path = directory.path;
           File file = File(path + "/temp_" + listingImage.index.toString() + "_"+DateTime.now().microsecondsSinceEpoch.toString());
           listingImage.file = file;
           file = await file.writeAsBytes( asset.imageData.buffer.asUint8List(asset.imageData.offsetInBytes, asset.imageData.lengthInBytes));

           return file.path;
         } else {
           return null;
         }
       } catch(exceptioon) {
         return null;
       }

      }
Run Code Online (Sandbox Code Playgroud)

  • 请注意,您的插件不适用于 iOS 图像上传的私有存储桶。 (4认同)
  • 这适用于发现此内容的其他人。我花了很长时间才让它发挥作用。事实证明,完成这项工作的最简单方法是在 US_EAST_1 上创建您的 Identity_pool 和 s3 存储桶。我查看了这个插件包装的 Android 部分,看来 EAST 是硬编码的。其次,对于次区域,您可以再次输入 US_EAST_1。如果你遵守这些规则,就会像魅力一样发挥作用。 (2认同)
  • 即使存储桶是公共的,这个插件也不适用于 iOS,我已经浪费了很多时间来实现这个。 (2认同)

Moh*_*oud 1

你可以使用Flutter Multipart,像这样

 // open a bytestream
    var stream = new http.ByteStream(DelegatingStream.typed(_image.openRead()));
    // get file length
    var length = await _image.length();
    // string to uri
    var uri = Uri.parse(apiUrl);
    // create multipart request
    var request = new http.MultipartRequest("POST", uri);
    NetworkUtils.addAuthHeaders(request);
    // multipart that takes file
    var multipartFile = new http.MultipartFile('file', stream, length,
        filename: basename(_image.path),
        contentType: new MediaType("image", "jpg"));
    // add file to multipart
    request.files.add(multipartFile);
    request.fields.addAll(body);
    // send
    var response = await request.send();
    print(response.statusCode);
    // listen for response
    response.stream.transform(utf8.decoder).listen((value) {
      print(value);
    });
  }
Run Code Online (Sandbox Code Playgroud)