簡體   English   中英

在 Flutter 中從 AWS S3 上傳和獲取媒體文件

[英]Upload & fetch media files from AWS S3 in Flutter

我的 flutter 應用程序使用 firebase 作為后端,但我需要將媒體文件(照片和視頻)存儲在我的 s3 存儲桶中。 任務是將從圖像選擇器檢索到的媒體上傳到 s3 並取回 url,然后可以將其作為字符串存儲在我的 firebase 數據庫中。

問題是 dart 2 缺少 aws 庫或 api。我在 pub 中找到了 3 個,但其中 2 個與 dart 2 不兼容,1 個正在開發中。 有沒有人使用飛鏢 2 在 flutter 中實現過這個? 歡迎提出任何建議。 謝謝你。

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

有幾種方法可以做到這一點。 一種方法是使用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}" }
  ]
}
''';
  }
}

然后,使用您的政策助手簽署您的請求並通過http.MultipartRequest上傳:

import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:async/async.dart';
import 'package:http/http.dart' as http;
import 'package:test/test.dart';
import 'package:amazon_cognito_identity_dart/sig_v4.dart';
import './policy.dart';

void main() {
  const _accessKeyId = 'AKXXXXXXXXXXXXXXXXXX';
  const _secretKeyId = 'xxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxx';
  const _region = 'ap-southeast-1';
  const _s3Endpoint =
      'https://bucketname.s3-ap-southeast-1.amazonaws.com';

  final file = File(path.join('/path/to/file', 'square-cinnamon.jpg'));
  final stream = http.ByteStream(DelegatingStream.typed(file.openRead()));
  final length = await file.length();

  final uri = Uri.parse(_s3Endpoint);
  final req = http.MultipartRequest("POST", uri);
  final multipartFile = http.MultipartFile('file', stream, length,
      filename: path.basename(file.path));

  final policy = Policy.fromS3PresignedPost('uploaded/square-cinnamon.jpg',
      'bucketname', _accessKeyId, 15, length,
      region: _region);
  final key =
      SigV4.calculateSigningKey(_secretKeyId, policy.datetime, _region, 's3');
  final signature = SigV4.calculateSignature(key, policy.encode());

  req.files.add(multipartFile);
  req.fields['key'] = policy.key;
  req.fields['acl'] = 'public-read';
  req.fields['X-Amz-Credential'] = policy.credential;
  req.fields['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256';
  req.fields['X-Amz-Date'] = policy.datetime;
  req.fields['Policy'] = policy.encode();
  req.fields['X-Amz-Signature'] = signature;

  try {
    final res = await req.send();
    await for (var value in res.stream.transform(utf8.decoder)) {
      print(value);
    }
  } catch (e) {
    print(e.toString());
  }
}

請注意,此方法要求您提供訪問密鑰和秘密密鑰。 如果您使用 Cognito 之類的服務,建議獲取臨時的 Access Key 和 Secret Key。 此處找到使用臨時訪問的示例。

免責聲明:我是Signature V4 包的原作者。

您可以使用包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)

_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)

要獲取圖像,您可以使用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;
       }

      }

你可以使用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);
    });
  }

我不太明白amazon_s3_cognito如何在flutter上工作,它有兩種類型的函數(upload,uploadImage)用於將文件上傳到aws s3。 如果有人能為我解決這個問題,我將不勝感激,謝謝。

static Future<String> uploadImage(
    String filepath, String bucket, String identity) async {
  final Map<String, dynamic> params = <String, dynamic>{
    'filePath': filepath,
    'bucket': bucket,
    'identity': identity,
  };
  final String imagePath =
      await _channel.invokeMethod('uploadImageToAmazon', params);
  return imagePath;
}

static Future<String> upload(String filepath, String bucket, String identity,
    String imageName, String region, String subRegion) async {
  final Map<String, dynamic> params = <String, dynamic>{
    'filePath': filepath,
    'bucket': bucket,
    'identity': identity,
    'imageName': imageName,
    'region': region,
    'subRegion': subRegion
  };
  final String imagePath = await _channel.invokeMethod('uploadImage', params);
  return imagePath;
}

我想知道為什么函數接受String形式的參數文件路徑這是否意味着我需要對文件進行編碼?

這是我的源代碼,我輸入從庫中選擇一個圖像或通過相機拍照

 void _getImageAndDetectFaces(source) async {
onPickImageSelected(source);
final imageFile = await ImagePicker.pickImage(
  source: imageSource,
);
setState(() {
  _idImage = imageFile;
  isImageLoaded = true;
});

}

_idImage是一種文件類型。 我需要將文件類型轉換為String嗎?

您可以使用包amazon_s3_cognito上傳圖片。 但它在 iOS 端有問題,你可以試試我的叉子。

將這一行放在您的 pubspec.yaml 中:

amazon_s3_cognito:
  git:
    URL: https://github.com/zhihaozhang/amazon_s3_cognito.git

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM