Using the s3transferutility we will upload images from your camera or photo library in swift. View the source on github
In this example We will have 2 buttons – Camera Upload and Picture Upload.
Depending on what is selected as the data source (camera or photo library) it will upload the file accordingly. If you use the camera button you will notice that we will have to create a temp directory when uploading the image, since there is no asset location for it on the device.
You can find more info in the aws sdk
//
// PictureViewController.swift
//
//
// Created by Jose Deras on 12/30/15.
// Copyright © 2015 Jose Deras. All rights reserved.
//
import UIKit
import AWSMobileAnalytics
import AWSCognito
import AWSS3
import AWSCore
import Photos
import MobileCoreServices
class PictureViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
@IBOutlet weak var progressView: UIProgressView!
@IBOutlet weak var imageView: UIImageView!
@IBAction func openCameraButton(sender: AnyObject) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera) {
let camImagePicker = UIImagePickerController()
camImagePicker.delegate = self
camImagePicker.sourceType = UIImagePickerControllerSourceType.Camera;
camImagePicker.allowsEditing = false
self.presentViewController(camImagePicker, animated: true, completion: nil)
}
}
@IBAction func openPhotoLibrary(sender: AnyObject) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary;
imagePicker.allowsEditing = true
self.presentViewController(imagePicker, animated: true, completion: nil)
}
}
//handles upload
var uploadCompletionHandler: AWSS3TransferUtilityUploadCompletionHandlerBlock?
var uploadFileURL: NSURL?
override func viewDidLoad() {
super.viewDidLoad()
//setting progress bar to 0
self.progressView.progress = 0.0;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//begin upload from photo library
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
//first run if its coming from photo album
if(picker.sourceType == UIImagePickerControllerSourceType.PhotoLibrary)
{
//getting details of image
let uploadFileURL = info[UIImagePickerControllerReferenceURL] as! NSURL
let imageName = uploadFileURL.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first! as String
// getting local path
let localPath = (documentDirectory as NSString).stringByAppendingPathComponent(imageName!)
//getting actual image
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
let data = UIImagePNGRepresentation(image)
data!.writeToFile(localPath, atomically: true)
let imageData = NSData(contentsOfFile: localPath)!
let photoURL = NSURL(fileURLWithPath: localPath)
// let imageWithData = UIImage(data: imageData)!
//defining bucket and upload file name
let S3BucketName: String = "bucketNAme"
let S3UploadKeyName: String = "test_libarayUpload.jpg"
let expression = AWSS3TransferUtilityUploadExpression()
expression.uploadProgress = {(task: AWSS3TransferUtilityTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) in
dispatch_async(dispatch_get_main_queue(), {
let progress = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
self.progressView.progress = progress
// self.statusLabel.text = "Uploading..."
NSLog("Progress is: %f",progress)
})
}
self.uploadCompletionHandler = { (task, error) -> Void in
dispatch_async(dispatch_get_main_queue(), {
if ((error) != nil){
NSLog("Failed with error")
NSLog("Error: %@",error!);
// self.statusLabel.text = "Failed"
}
else if(self.progressView.progress != 1.0) {
// self.statusLabel.text = "Failed"
NSLog("Error: Failed - Likely due to invalid region / filename")
}
else{
// self.statusLabel.text = "Success"
NSLog("Sucess")
}
})
}
let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility()
transferUtility?.uploadFile(photoURL, bucket: S3BucketName, key: S3UploadKeyName, contentType: "image/jpeg", expression: expression, completionHander: uploadCompletionHandler).continueWithBlock { (task) -> AnyObject! in
if let error = task.error {
NSLog("Error: %@",error.localizedDescription);
// self.statusLabel.text = "Failed"
}
if let exception = task.exception {
NSLog("Exception: %@",exception.description);
// self.statusLabel.text = "Failed"
}
if let _ = task.result {
// self.statusLabel.text = "Generating Upload File"
NSLog("Upload Starting!")
// Do something with uploadTask.
}
return nil;
}
//end if photo library upload
self.dismissViewControllerAnimated(true, completion: nil);
}
//second check if its coming from camera
else if(picker.sourceType == UIImagePickerControllerSourceType.Camera)
{
// var imageToSave: UIImage = info(UIImagePickerControllerOriginalImage) as UIImage
var imageToSave: UIImage = info[UIImagePickerControllerOriginalImage] as! UIImage
//defining bucket and upload file name
let S3BucketName: String = "bucketName"
//setting temp name for upload
let S3UploadKeyName = "Test2CameraUpload.jpg"
//settings temp location for image
let imageName = NSURL.fileURLWithPath(NSTemporaryDirectory() + S3UploadKeyName).lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first! as String
// getting local path
let localPath = (documentDirectory as NSString).stringByAppendingPathComponent(imageName!)
//getting actual image
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
let data = UIImagePNGRepresentation(image)
data!.writeToFile(localPath, atomically: true)
let imageData = NSData(contentsOfFile: localPath)!
let photoURL = NSURL(fileURLWithPath: localPath)
let expression = AWSS3TransferUtilityUploadExpression()
expression.uploadProgress = {(task: AWSS3TransferUtilityTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) in
dispatch_async(dispatch_get_main_queue(), {
let progress = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
self.progressView.progress = progress
// self.statusLabel.text = "Uploading..."
NSLog("Progress is: %f",progress)
})
}
self.uploadCompletionHandler = { (task, error) -> Void in
dispatch_async(dispatch_get_main_queue(), {
if ((error) != nil){
NSLog("Failed with error")
NSLog("Error: %@",error!);
// self.statusLabel.text = "Failed"
}
else if(self.progressView.progress != 1.0) {
// self.statusLabel.text = "Failed"
NSLog("Error: Failed - Likely due to invalid region / filename")
}
else{
// self.statusLabel.text = "Success"
NSLog("Sucess")
}
})
}
let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility()
transferUtility?.uploadFile(photoURL, bucket: S3BucketName, key: S3UploadKeyName, contentType: "image/jpeg", expression: expression, completionHander: uploadCompletionHandler).continueWithBlock { (task) -> AnyObject! in
if let error = task.error {
NSLog("Error: %@",error.localizedDescription);
// self.statusLabel.text = "Failed"
}
if let exception = task.exception {
NSLog("Exception: %@",exception.description);
// self.statusLabel.text = "Failed"
}
if let _ = task.result {
// self.statusLabel.text = "Generating Upload File"
NSLog("Upload Starting!")
// Do something with uploadTask.
}
return nil;
}
//end if photo library upload
self.dismissViewControllerAnimated(true, completion: nil);
}
else{
NSLog("Shit fucked up yo")
}
}
}
Can u pls send the project ……And my requirement is when i click the action sheet button then my image will be saved in the bucket….
Hi Nagaraju. I’ve added the source files so you can compare with what you have. Github
Hi Jose! I love your AWS swift series of articles. I’m trying to understand something: Say that your trying to make an app where users can upload pics/videos to S3. If you wanted to view pics/videos uploaded by a specific user, could you query AWS S3 in that way? So my understanding is you can store user data in AWS DynamoDB (w/Titan for graph based) and somehow link the userId attribute to media that you upload to S3?
Thanks so much!
Hi Jason. Yes that is possible. I am working on a tutorial hopefully I can get it finished soon!
Hey! Great tutorial! One question though: I am having problems with my ”
expression.uploadProgress”. The complier says “AWSS3TransferUtilityUploadExpression has not member uploadProgress”. I seem to have everything linked up in my bridging header and stuff. Any help please?
Thanks
Hi Kamal. Did you include AWSS3 in the header file? I’m assuming you have the expression as:
let expression = AWSS3TransferUtilityUploadExpression()
expression.uploadProgress = {(task: AWSS3TransferUtilityTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) in … etc etc.
Also have you tried comparing it with the my github project?
https://github.com/jdzorz/AWS-S3-Upload-Image-PhotoLibrary-or-Camera
Hi there,
I’m having some minor issues here.. It’s this part of the command that causes it.
“express.uploadProgress”
Error Prompt: AWSS3TransferUtilityUploadExpression has no member ‘uploadprogress’
Can i enquire: what are the reasons and how do i get this resolve?
let expression = AWSS3TransferUtilityUploadExpression()
expression.uploadProgress = {(task: AWSS3TransferUtilityTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) in
dispatch_async(dispatch_get_main_queue(), {
let progress = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
self.progressView.progress = progress
// self.statusLabel.text = “Uploading…”
NSLog(“Progress is: %f”,progress)
})
}
Hi Cedric. Do you include the AWS bridge file to import the S3 delegate class. Take a look at my git hub project and compare:
https://github.com/jdzorz/AWS-S3-Upload-Image-PhotoLibrary-or-Camera
You’ll need the bridge file:
#ifndef AWS_Bridge_h
#define AWS_Bridge_h
#import
#import
#import
#endif /* AWS_Bridge_h */
so then you can import that into your view controller:
import AWSCore
import AWSS3
Hi,
I was able to compile and execute the script. The console says the upload has been a success but I do not see anything in the Amazon S3 server. Could you tell me what the cause of this problem is?
Thanks
Can you check your S3 permissions in aws?
Hi,
Yeah I was missing a line in the S3 permissions. It works like a charm.
Thanks
Hi! I’m getting the following error:
value of type ‘AWSS3TransferUtilityUploadExpression’ has no member ‘uploadProgress’.
Do you have any idea as to why? If i comment that part, everything else works fine.
Replace that line with
let expression = AWSS3TransferUtilityUploadExpression()
expression.progressBlock = { (task: AWSS3TransferUtilityTask, progress: NSProgress) in
print(progress.fractionCompleted)
}