Загружайте и извлекайте мультимедийные файлы из AWS S3 во Flutter
Мое приложение флаттера использует Firebase в качестве бэкэнда, но мне нужно хранить медиа-файлы (фото и видео) в моем контейнере s3. Миссия состоит в том, чтобы загрузить медиафайлы, извлеченные из средства выбора изображений, в s3 и вернуть URL-адрес, который затем можно сохранить в виде строки в моей базе данных Firebase.
Проблема в нехватке библиотек aws или API для dart 2. Я нашел 3 в пабе, но 2 из них были несовместимы с dart 2, а 1 находился в стадии разработки. Кто-нибудь реализовал это во флаттере, используя дротик 2? Любые предложения приветствуются. Спасибо.
Пакеты, которые я нашел, были (pub.dartlang.org): aws_client, aws_interop, amazon_s3
4 ответа
Есть несколько способов сделать это. Одним из способов является подписание вашего запроса с подписью 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, рекомендуется получить временный ключ доступа и секретный ключ. Примеры использования временного доступа можно найти здесь.
Отказ от ответственности: я являюсь первоначальным автором пакета 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 = путь к изображению, которое вы хотите загрузить (метод 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)
Для извлечения изображений можно использовать https://pub.dev/packages/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;
}
}
Вы можете использовать пакет amazon_s3_cognito для загрузки изображений. Но у него есть проблемы со стороны iOS, вы можете попробовать мою вилку.
Поместите эту строку в свой pubspec.yaml:amazon_s3_cognito: git: url: https://github.com/zhihaozhang/amazon_s3_cognito.git
Вы можете использовать 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);
});
}