Reputation: 2086
I am working on an app that uploads an image to Amazon S3 bucket, and instead of just showing a Spinner, I'd love to be able to get Progress on the status of that upload.
I am uploading a file using MultipartRequest from Package:http. I am successfully uploading the file but I want to get the Progress of the file that is being uploaded. How can I achieve that? My current code looks something like this.
static Future<bool> uploadFile({@required userId, @required albumId, @required data, @required fileName}) async{
const _accessKeyId = 'AKIAVV**********';
const _secretKeyId = 'iyBmdn6v***************************';
const _region = 'us-east-1';
const _s3Endpoint = 'https://myalbums-content.s3.amazonaws.com';
final file = data;
var stream = new http.ByteStream(DelegatingStream.typed(file.openRead()));
final length = await file.length();
final uri = Uri.parse(_s3Endpoint);
final req = http.MultipartRequest("POST", uri);
var multipartFile = http.MultipartFile('file', stream, length,
contentType: new MediaType('image','JPG'));
final policy = Policy.fromS3PresignedPost(userId.toString() +'/'+ albumId.toString() +'/'+ fileName,
'myalbums-content', _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();
if(res.statusCode == 204){
return true;
} else {
return false;
}
} catch (e) {
print('Network issue: '+e.toString());
return false;
}
}
Thank you in advance.
Upvotes: 9
Views: 7576
Reputation: 3757
Check out this example on Github. It shows how you can upload the file using a Stream. If you expose the stream of bytes uploaded to your Widget, you should be able to use a ProgressIndicator that compares the total number of bytes to the value in the Stream.
static Future<String> fileUploadMultipart(
{File file, OnUploadProgressCallback onUploadProgress}) async {
assert(file != null);
final url = '$baseUrl/api/file';
final httpClient = getHttpClient();
final request = await httpClient.postUrl(Uri.parse(url));
int byteCount = 0;
var multipart = await http.MultipartFile.fromPath(fileUtil.basename(file.path), file.path);
// final fileStreamFile = file.openRead();
// var multipart = MultipartFile("file", fileStreamFile, file.lengthSync(),
// filename: fileUtil.basename(file.path));
var requestMultipart = http.MultipartRequest("", Uri.parse("uri"));
requestMultipart.files.add(multipart);
var msStream = requestMultipart.finalize();
var totalByteLength = requestMultipart.contentLength;
request.contentLength = totalByteLength;
request.headers.set(
HttpHeaders.contentTypeHeader, requestMultipart.headers[HttpHeaders.contentTypeHeader]);
Stream<List<int>> streamUpload = msStream.transform(
new StreamTransformer.fromHandlers(
handleData: (data, sink) {
sink.add(data);
byteCount += data.length;
if (onUploadProgress != null) {
onUploadProgress(byteCount, totalByteLength);
// CALL STATUS CALLBACK;
}
},
handleError: (error, stack, sink) {
throw error;
},
handleDone: (sink) {
sink.close();
// UPLOAD DONE;
},
),
);
await request.addStream(streamUpload);
final httpResponse = await request.close();
//
var statusCode = httpResponse.statusCode;
if (statusCode ~/ 100 != 2) {
throw Exception('Error uploading file, Status code: ${httpResponse.statusCode}');
} else {
return await readResponseAsString(httpResponse);
}
}
req.send
also returns a StreamedResponse
which may be easier to implement.
Upvotes: 2