Download secure file from S3 server using accesskey and secretkey - ios

I'm trying to download a secure file from S3 server using NSURLSessionDownloadTask,but it returns me 403 error(Access Denied).
My Code:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"https://xxx.amazonaws.com/bucket-name/file_name"]];
request.HTTPMethod = #"GET";
[request setValue:#"kAccessKey" forHTTPHeaderField:#"accessKey"];
[request setValue:#"kSecretKey" forHTTPHeaderField:#"secretKey"];
NSURLSessionDownloadTask *downloadPicTask = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
UIImage *downloadedImage = [UIImage imageWithData:
[NSData dataWithContentsOfURL:location]];
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.imageView.image = downloadedImage;
[weakSelf.activityIndicator stopAnimating];
});
}];
[downloadPicTask resume];
EDIT
I found this code :
AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc]initWithRegionType:AWSRegionUSWest2 identityId:#"xxxxxxx" identityPoolId:#"xxxxxxxx" logins:nil];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc]initWithRegion:AWSRegionUSWest2 credentialsProvider:credentialsProvider];
// Construct the NSURL for the download location.
NSString *downloadingFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"sample_img.png"];
NSURL *downloadingFileURL = [NSURL fileURLWithPath:downloadingFilePath];
// Construct the download request.
AWSS3TransferManagerDownloadRequest *downloadRequest = [[AWSS3TransferManagerDownloadRequest alloc]init];
AWSS3TransferManager * transferManager = [AWSS3TransferManager S3TransferManagerForKey:[[configuration credentialsProvider]sessionKey]];
downloadRequest.bucket = #"test-upload-bucket";
downloadRequest.key = #"sample_img.png";
downloadRequest.downloadingFileURL = downloadingFileURL;
[[transferManager download:downloadRequest] continueWithExecutor:[AWSExecutor mainThreadExecutor]
withBlock:^id(AWSTask *task){
return nil;
}];
What is the input value for IdentityId and IdentityPoolId ?

A working summer 2017 function, to which you can pass your image name and table cell (I'm downloading logos for certain table entries). Make sure you modify your credentials region, and your key/secret credentials, and your bucket name. Note: Your credentials should not be root. Create a separate IAM user/group/policy and authorize only specific resources (buckets/objects) and specific actions. Create your key and secret. I did this, because I do not want to use amazon's cogito to manage my users. but want my mobile app to access S3 resources directly and securely, and also not via a some redundant server-side script. But, Amazon recommends for mobile, you use cogito and have each user use own/temp creds. Caveat emptor.
-(void) awsImageLoad:(NSString*)imageFile :(UITableViewCell*)cell {
NSArray *filepathelements = [imageFile componentsSeparatedByString:#"/"];
if (filepathelements.count == 0) return;
//extract only the name from a possibe folder/folder/imagename
NSString *imageName = [filepathelements objectAtIndex:filepathelements.count-1];
AWSStaticCredentialsProvider *credentialsProvider =
[[AWSStaticCredentialsProvider alloc]
initWithAccessKey:#"_______________"
secretKey:#"__________________________________"];
//My credentials exist on the US East 1 region server farm
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc]initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider];
// Construct the NSURL for the temporary download location.
NSString *downloadingFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:imageName];
NSURL *downloadingFileURL = [NSURL fileURLWithPath:downloadingFilePath];
// Construct the download request.
AWSS3TransferManagerDownloadRequest *downloadRequest = [AWSS3TransferManagerDownloadRequest new];
// S3 has only a Global Region -- establish our creds configuration
[AWSS3TransferManager registerS3TransferManagerWithConfiguration:configuration forKey:#"GlobalS3TransferManager"];
AWSS3TransferManager * transferManager = [AWSS3TransferManager S3TransferManagerForKey:#"GlobalS3TransferManager"];
downloadRequest.bucket = #"my_bucket_name";
downloadRequest.key = imageFile;
downloadRequest.downloadingFileURL = downloadingFileURL;
[[transferManager download:downloadRequest] continueWithExecutor:[AWSExecutor mainThreadExecutor] withBlock:^id(AWSTask *task){
if (task.error){
if ([task.error.domain isEqualToString:AWSS3TransferManagerErrorDomain]) {
switch (task.error.code) {
case AWSS3TransferManagerErrorCancelled:
case AWSS3TransferManagerErrorPaused:
break;
default:
NSLog(#"Error: %#", task.error);
break;
}
} else {
NSLog(#"Error: %#", task.error);
}
}
if (task.result) {
// ...this runs on main thread already
cell.imageView.image = [UIImage imageWithContentsOfFile:downloadingFilePath];
}
return nil;
}];
}

All HTTP Request need to be properly signed before send to AWS server, the signing Process is very complicated Signature Version 4 Signing Process so I suggest to try AWS Mobile SDK for iOS v2
The example shown by Arun_ is a code snippets that how to use transferManager to download a file via AWS Mobile SDK for iOS v2.

This worked for me:
AWSStaticCredentialsProvider *credentialsProvider = [[AWSStaticCredentialsProvider alloc]initWithAccessKey:#"AccessKey" secretKey:#"secretKey"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc]initWithRegion:AWSRegionUSWest2 credentialsProvider:credentialsProvider];
// Construct the NSURL for the download location.
NSString *downloadingFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"sample_img.png"];
NSURL *downloadingFileURL = [NSURL fileURLWithPath:downloadingFilePath];
// Construct the download request.
AWSS3TransferManagerDownloadRequest *downloadRequest = [AWSS3TransferManagerDownloadRequest new];
[AWSS3TransferManager registerS3TransferManagerWithConfiguration:configuration forKey:#"USWest2S3TransferManager"];
AWSS3TransferManager * transferManager = [AWSS3TransferManager S3TransferManagerForKey:#"USWest2S3TransferManager"];
downloadRequest.bucket = #"test-upload-bucket";
downloadRequest.key = #"sample_img.png";
downloadRequest.downloadingFileURL = downloadingFileURL;
[[transferManager download:downloadRequest] continueWithExecutor:[AWSExecutor mainThreadExecutor]
withBlock:^id(AWSTask *task){
return nil;
}];

Related

AWS S3 Upload works on Simulator but not on Device

I'm encountering an interesting problem. Trying to upload a file to AWS S3, it works perfectly when run on a simulator, also when run on a connected device (DEBUG mode). But when I package the app and deploy it to a device, it doesn't work. I keep getting "Request Timed Out".
This is my code,
- (void)uploadFileAtPath:(NSString *)filePath completionHandler:(void (^)(NSString *, NSError *))handler {
NSString *fileName = [filePath lastPathComponent];
AWSS3GetPreSignedURLRequest *getPreSignedURLRequest = [AWSS3GetPreSignedURLRequest new];
getPreSignedURLRequest.bucket = self.bucketName;
getPreSignedURLRequest.key = fileName;
getPreSignedURLRequest.HTTPMethod = AWSHTTPMethodPUT;
getPreSignedURLRequest.expires = [NSDate dateWithTimeIntervalSinceNow:3600];
NSString *fileContentTypeStr = #"application/zip";
getPreSignedURLRequest.contentType = fileContentTypeStr;
[[[AWSS3PreSignedURLBuilder defaultS3PreSignedURLBuilder] getPreSignedURL:getPreSignedURLRequest]
continueWithBlock:^id(AWSTask *task) {
if (task.error) {
NSLog(#"Error: %#",task.error);
} else {
NSURL *presignedURL = task.result;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:presignedURL];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
[request setHTTPMethod:#"PUT"];
[request setValue:fileContentTypeStr forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[NSData dataWithContentsOfFile:filePath]];
NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:nil];
NSURLSessionDataTask* uploadTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(#"URL Session Task Failed: %#", [error localizedDescription]);
}
else {
NSLog(#"URL Session Task Succeeded: HTTP %ld", ((NSHTTPURLResponse*)response).statusCode);
}
handler([[((NSHTTPURLResponse*)response).URL.absoluteString componentsSeparatedByString:#"?"] firstObject], error);
}];
[uploadTask resume];
}
return nil;
}];
}
And this is the error I get (obfuscated sensitive parts) -
Error: The request timed out.,
UserInfo: {
NSErrorFailingURLKey = "https://s3.amazonaws.com/bucketname/file-2-10-2015-10-13PM.zip?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIHY7KKHBLYOPMTPA%2F20151003%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20151003T051306Z&X-Amz-Expires=3599&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=504e1f5083116as09dc6a04c3b4152816a8d9e8bccff8f4ea0cbss9fcdc21eac";
NSErrorFailingURLStringKey = "https://s3.amazonaws.com/bucketname/file-2-10-2015-10-13PM.zip?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIHY7KKHBLYOPMTPA%2F20151003%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20151003T051306Z&X-Amz-Expires=3599&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=504e1f5083116as09dc6a04c3b4152816a8d9e8bccff8f4ea0cbss9fcdc21eac";
NSLocalizedDescription = "The request timed out.";
NSUnderlyingError = "Error Domain=kCFErrorDomainCFNetwork Code=-1001 \"(null)\" UserInfo={_kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102}";
"_kCFStreamErrorCodeKey" = "-2102";
"_kCFStreamErrorDomainKey" = 4;
}
I have no idea what is going wrong here! Help much appreciated.
While the device connected to Xcode, I also got the URL out and uploaded the file via cURL. FWIW, that works too!
After 2 days, I finally found the problem! This was the part of the code I did not post, but it is how I was initializing the AWS Client.
AWSStaticCredentialsProvider *cp = [[AWSStaticCredentialsProvider alloc] initWithAccessKey:accesskey secretKey:secretKey];
AWSServiceConfiguration* config = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:cp];
AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = config;
Now, there was another library that I was using which did exactly the same thing, but with different credentials to a different bucket. Since this other library was getting called after my code, I was having problems with uploading the file. Now why was the error Request Timed Out instead of Invalid Credentials, is something I haven't found out yet.
I changed the initialization code to this --
AWSStaticCredentialsProvider *cp = [[AWSStaticCredentialsProvider alloc] initWithAccessKey:accesskey secretKey:secretKey];
AWSServiceConfiguration* config = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:cp];
[AWSS3TransferManager registerS3TransferManagerWithConfiguration:config forKey:AWSLogFilesUploaderKey];
And obtained an instance of AWSS3TransferManager like this --
AWSS3TransferManager* tm = [AWSS3TransferManager S3TransferManagerForKey:AWSLogFilesUploaderKey];
And then everything went smooth!

Uploading Facebook Profile Image to S3 via aws ios sdk

I want the profile picture of users uploaded to my S3 bucket when they register with my app.
Do I need to download the picture first from facebook, or can I pass the external url to the AWSS3TransferManager? PReferable I would of course like to not have to download the picture first to the client's devise and only then upload to S3.
//We create the url to the FB Profile Picture
NSString *compURLString = [NSString stringWithFormat:#"https://graph.facebook.com/FACEBOOKID/picture?type=large"];
NSURL *url = [NSURL URLWithString:compURLString];
// We download the FB Profile Picture from Facebook TBD DO WE NEED THIS STEP OR IS IT POSSIBLE TO PASS THE EXTERNAL URL? AND NOT DOWNLOAD THE IMAGE FIRST? https://graph.facebook.com/FACEBOOKID/picture?type=large TO THE AWS UPLOAD MANAGER
NSURLSessionDownloadTask *downloadPhotoTask = [[NSURLSession sharedSession]
downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
UIImage
// NOw that we have the FB Profile Picture, we upload it to S3
AWSS3TransferManager *uploadManager = [AWSS3TransferManager defaultS3TransferManager];
NSString *const S3BucketName = #"DEMO";
//upload the image
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
uploadRequest.body = location;
uploadRequest.bucket = S3BucketName;
uploadRequest.key = [NSString stringWithFormat:#"#%.jpg", facebookID];
uploadRequest.contentType = #"image/jpg";
[[uploadManager upload:uploadRequest] continueWithExecutor:[AWSExecutor mainThreadExecutor]
withBlock:^id(AWSTask *task) {...
}];
[downloadPhotoTask resume];}

AWSS3GetPreSignedURLRequest upload with custom headers giving 403

I've been having some problems with my AWSS3GetPreSignedURLRequest and AFNetworking's NSMutableURLRequest. I can successfully upload a file with just the Content-Type header. However, if I add the x-amz-acl and the x-amz-server-side-encryption, the upload will fail with 403 - No Permission error. What can I do? Is it an Amazon side problem, using server-side encryption or ACLs isn't allowed with pre-signed URLs, or changing the request will work? I looked pretty deep on the AWS documentation and the iOS SDK reference, but nothing on this. By the way, I'm using AWS iOS SDK v2. Does anyone how how to do this?
NSString *keyName;
NSString *fileContentTypeStr;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MM.d.h.mm.ss"];
if([multipleFileType isEqualToString:#"PNG"])
{
fileContentTypeStr = #"image/png";
keyName = [NSString stringWithFormat:#"image_%#.png", [formatter stringFromDate:[NSDate date]]];
}
else if([multipleFileType isEqualToString:#"JPG"])
{
fileContentTypeStr = #"image/jpeg";
keyName = [NSString stringWithFormat:#"image_%#.jpg", [formatter stringFromDate:[NSDate date]]];
}
self.imageUploadURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:#"image"]];
[imageData writeToURL:self.imageUploadURL atomically:YES];
AWSS3GetPreSignedURLRequest *getPreSignedURLRequest = [AWSS3GetPreSignedURLRequest new];
getPreSignedURLRequest.bucket = [NSString stringWithFormat:#"BUCKET-NAME/%#", folderObject.objectId];
getPreSignedURLRequest.key = keyName;
getPreSignedURLRequest.HTTPMethod = AWSHTTPMethodPUT;
getPreSignedURLRequest.expires = [NSDate dateWithTimeIntervalSinceNow:3600];
getPreSignedURLRequest.contentType = fileContentTypeStr;
[[[AWSS3PreSignedURLBuilder defaultS3PreSignedURLBuilder] getPreSignedURL:getPreSignedURLRequest]
continueWithBlock:^id(BFTask *task) {
if (task.error) {
NSLog(#"Error: %#",task.error);
} else {
NSURL *presignedURL = task.result;
NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:presignedURL];
[URLRequest setValue:fileContentTypeStr forHTTPHeaderField:#"Content-Type"];
[URLRequest setValue:#"AES-256" forHTTPHeaderField:#"x-amz-server-side-encryption"];
[URLRequest setValue:#"private" forHTTPHeaderField:#"x-amz-acl"];
URLRequest.HTTPMethod = #"PUT";
URLRequest.HTTPBody = imageData;
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSProgress *progress;
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:URLRequest progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if(!error){
NSLog(#"File was successfully uploaded.");
}
}];
[uploadTask resume];
}
return nil;
}];
Note: The code sample there lacks a few things that are on the global headers, and a few other completion blocks + delegates, but I believe everyone will understand the point here.
Anticipated thanks,
As #YosukeMatsuda noticed in comments you can use putObjectAcl: method.
I put ACL for uploaded object on URLSession didCompleteWithError: delegate method like this:
//
self.awss3 = [[AWSS3 alloc] initWithConfiguration:__your_config__];
//
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if (error)
{
NSLog(#"S3 UploadTask: %# completed with error: %#", task, [error localizedDescription]);
}
else
{
// AWSS3GetPreSignedURLRequest does not contain ACL property, so it has to be set after file was uploaded to bucket
AWSS3PutObjectAclRequest *aclRequest = [AWSS3PutObjectAclRequest new];
aclRequest.bucket = #"your_bucket";
aclRequest.key = #"your_key";
aclRequest.ACL = AWSS3ObjectCannedACLPublicRead;
[[self.awss3 putObjectAcl:aclRequest] continueWithBlock:^id(BFTask *bftask) {
if (bftask.error)
{
NSLog(#"Error putObjectAcl: %#", [bftask.error localizedDescription]);
}
else
{
AWSEndpoint *endpoint = self.awss3.configuration.endpoint;
NSURL *publicReadURL = [[endpoint.URL URLByAppendingPathComponent:backgroundUploadTask.bucket] URLByAppendingPathComponent:backgroundUploadTask.key];
}
return nil;
}];
}
}
We added - setValue:forRequestParameter: to AWSS3GetPreSignedURLRequest. You can use this method to add ACL and encryption headers.
Also, we introduced a new AWSS3TransferUtility for simplifying the background transfer. Refer to our blog post for more details.

Getting image URL from bucket Amazon Web Service iOS after uploading

I have an image that I'm uploading to my bucket in AWS this way:
BFTask *task = [BFTask taskWithResult:nil];
[[task continueWithBlock:^id(BFTask *task) {
self.URL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:#"test"]];
NSData *data = UIImagePNGRepresentation(image);
//NSMutableString *dataString = [NSMutableString new];
[data writeToURL:self.URL atomically:YES];
return nil;
}]continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) {
self.uploadRequest1 = [AWSS3TransferManagerUploadRequest new];
self.uploadRequest1.bucket = S3BucketName;
self.uploadRequest1.key = S3KeyUploadName1;
self.uploadRequest1.body = self.URL;
return nil;
}];
AWSS3TransferManager *transferManager = [AWSS3TransferManager defaultS3TransferManager];
[[transferManager upload:self.uploadRequest1] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) {
if (task.error != nil) {
if( task.error.code != AWSS3TransferManagerErrorCancelled
&&
task.error.code != AWSS3TransferManagerErrorPaused
)
{
NSLog(#"Upload Failed!");
}
} else {
self.uploadRequest1 = nil;
NSLog(#"Uploaded!");
}
return nil;
}];
The code for uploading the image works just fine. When I open my bucket I see the image there.
Now what I want to do is to get the URL of that image, is there a way to get the URL without getting the image again?
You don't get it, you create it like:
https://s3.amazonaws.com/BUCKET_NAME/FILE_NAME.jpg
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
uploadRequest.body = [NSURL fileURLWithPath:filePath];
uploadRequest.key = fileName;
uploadReuest.bucket = S3BucketName;
[uploadRequest setACL:AWSS3ObjectCannedACLPublicRead];
Above Answer is right but you must have to set "ACL" to uploadRequest.
In your Question,you are forget to set "ACL".
Thanks
I was able to get the path from Amazon S3 -> Bucket -> Folder -> Image file -> Properties and on right side, you will see something like this..

How to upload a UIImage to S3 with AWS iOS SDK v2

The README page in Github (https://github.com/aws/aws-sdk-ios-v2) already has an example to upload an image, from the file path URL:
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
uploadRequest.bucket = yourBucket;
uploadRequest.key = yourKey;
uploadRequest.body = yourDataURL; // <<<< this is a NSURL
uploadRequest.contentLength = [NSNumber numberWithUnsignedLongLong:fileSize];
But, what if I only have a UIImage in memory (without file path)?
Is it possible to upload a UIImage (or it's NSData) to S3 using the SDK?
Would it be easier to manually use the HTTP API (using something like AFNetworking)?
Even though AWSiOSSDKv2 doesn't support uploading images from memory, you can save it as a file and then upload it.
//image you want to upload
UIImage* imageToUpload = [UIImage imageNamed:#"imagetoupload"];
//convert uiimage to
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", dateKey]];
[UIImagePNGRepresentation(imageToUpload) writeToFile:filePath atomically:YES];
NSURL* fileUrl = [NSURL fileURLWithPath:filePath];
//upload the image
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
uploadRequest.body = fileUrl;
uploadRequest.bucket = AWS_BUCKET_NAME;
uploadRequest.key = #"yourkey";
uploadRequest.contentType = #"image/png";
[[transferManager upload:thumbNailUploadRequest] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) {
if(task.error == nil) {
NSLog(#"woot");
}
return nil;
}];
It seems that AWSiOSSDKv2 don't have support to upload images from memory at this moment :(
From a Github issue:
The decision to accept only file NSURLs was driven by the following
factors:
Since v1, the pause / resume features require the input to be
files. It's not possible to recover NSData and retry the transfer when
the app is killed.
The background transfer on iOS 7 and above only
supports files. Currently, we don't support background transfer, but
we are planning to support it in the future. We considered accepting
an NSData and internally persisting the data to a temporary directory.
We decided not to include this in 2.0 release because if the NSData is
backed by a file, it doubles the disk usage for the data. Also,
developers have to deal with disk related errors when using
S3TransferManager. Even though we decided not to accept NSData in 2.0
release, we are open for your feedback. If this is a feature you want
to see in the future release, please create a new issue with the
feature request.
```
You can apparently do it with "presigned URLs"
- (void)uploadImageToS3: (UIImage *)image {
NSData *imageData = UIImageJPEGRepresentation(image, 0.7);
AWSS3GetPreSignedURLRequest *getPreSignedURLRequest = [AWSS3GetPreSignedURLRequest new];
getPreSignedURLRequest.bucket = #"bucket-name";
getPreSignedURLRequest.key = #"image-name.jpg";
getPreSignedURLRequest.HTTPMethod = AWSHTTPMethodPUT;
getPreSignedURLRequest.expires = [NSDate dateWithTimeIntervalSinceNow:3600];
NSString *fileContentTypeString = #"text/plain";
getPreSignedURLRequest.contentType = fileContentTypeString;
[[[AWSS3PreSignedURLBuilder defaultS3PreSignedURLBuilder] getPreSignedURL:getPreSignedURLRequest] continueWithBlock:^id(AWSTask *task) {
if (task.error) {
NSLog(#"Error: %#", task.error);
} else {
NSURL *presignedURL = task.result;
NSLog(#"upload presignedURL is \n%#", presignedURL);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:presignedURL];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
[request setHTTPMethod:#"PUT"];
[request setValue:fileContentTypeString forHTTPHeaderField:#"Content-Type"];
NSURLSessionUploadTask *uploadTask = [[NSURLSession sharedSession] uploadTaskWithRequest:request fromData:imageData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"Upload errer: %#", error);
}
NSLog(#"Done");
}];
[uploadTask resume];
}
return nil;
}];
}
Documented in the S3 docs for v2 SDK at http://docs.aws.amazon.com/mobile/sdkforios/developerguide/s3transfermanager.html#use-pre-signed-urls-to-transfer-objects-in-the-background
Its a bit of a mess with nested completion blocks, but the gist is you request a url, then when that returns you start an upload task. This was for a prototype test, not polished code. You should check the status code on the upload instead of just the error.
This is an updated answer so people don't have to figure it out themselves (like me) :D
Import the proper files (download it here)
#import <AWSCore/AWSCore.h>
#import <AWSS3TransferManager.h>
.m
- (void)viewDidLoad {
[super viewDidLoad];
AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1
identityPoolId:#"us-east-1:*******-******-*****-*****-*****"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1
credentialsProvider:credentialsProvider];
AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration;
}
I used a button to know when the user wants to upload the file
- (void)upload{
//convert uiimage to
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:#".png"]];
[UIImagePNGRepresentation(YOUR_UIIMAGE) writeToFile:filePath atomically:YES];
NSURL* fileUrl = [NSURL fileURLWithPath:filePath];
//upload the image
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
uploadRequest.body = fileUrl;
uploadRequest.bucket = #"YOUR_BUCKET_NAME";
uploadRequest.key = #"YOUR_FOLDER_NAME (if you have one)/NEW_IMAGE_NAME.png";
uploadRequest.contentType = #"image/png";
uploadRequest.ACL = AWSS3BucketCannedACLPublicRead;
AWSS3TransferManager *transferManager = [AWSS3TransferManager defaultS3TransferManager];
[[transferManager upload:uploadRequest] continueWithExecutor:[AWSExecutor mainThreadExecutor]
withBlock:^id(AWSTask *task) {
if (task.error != nil) {
NSLog(#"%s %#","Error uploading :", uploadRequest.key);
}else { NSLog(#"Upload completed"); }
return nil;
}];
}
Helpfull links:
AWS Documnetion
YouTube Video
Hopefully this helps someone out!
In the current version of the SDK you can use AWSS3TransferUtility and then it does everything for you.
func uploadData() {
let data: Data = Data() // Data to be uploaded
let expression = AWSS3TransferUtilityUploadExpression()
expression.progressBlock = {(task, progress) in
DispatchQueue.main.async(execute: {
// Do something e.g. Update a progress bar.
})
}
var completionHandler: AWSS3TransferUtilityUploadCompletionHandlerBlock?
completionHandler = { (task, error) -> Void in
DispatchQueue.main.async(execute: {
// Do something e.g. Alert a user for transfer completion.
// On failed uploads, `error` contains the error object.
})
}
let transferUtility = AWSS3TransferUtility.default()
transferUtility.uploadData(data,
bucket: "YourBucket",
key: "YourFileName",
contentType: "text/plain",
expression: expression,
completionHandler: completionHandler).continueWith {
(task) -> AnyObject! in
if let error = task.error {
print("Error: \(error.localizedDescription)")
}
if let _ = task.result {
// Do something with uploadTask.
}
return nil;
}
}
Hi you can sand image without saving image to the temporary folder in the iPhone Amazon iOS v2 gives such option as well.
In this code logFile.body it is NSData.
This code will help you my friend.
AWSS3PutObjectRequest *logFile = [AWSS3PutObjectRequest new];
logFile.bucket = uploadTokenData_.bucket;
logFile.key = key;
logFile.contentType = contentType;
logFile.body = data_;
logFile.contentLength = [NSNumber numberWithInteger:[data_ length]];
AWSS3 *S3 = [[AWSS3 alloc] initWithConfiguration:[AWSCredentialsProvider runServiceWithStsCredential]];
AWSS3TransferManager *transferManager = [[AWSS3TransferManager alloc] initWithS3:S3];
[[transferManager.s3 putObject:logFile] continueWithBlock:^id(BFTask *task)
{
NSLog(#"Error : %#", task.error);
if (task.error == nil)
{
NSLog(#"Uploadet");
}
}
With AWSS3TransferUtility you can upload any data type, also AWSS3TransferManagerUploadRequest is deprecated now, here is the code sample to upload jpeg but can be converted for any data type:
Code sample

Resources